aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ARCMigrate/ARCMT.cpp48
-rw-r--r--lib/ARCMigrate/CMakeLists.txt5
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp6
-rw-r--r--lib/ARCMigrate/Internals.h8
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp69
-rw-r--r--lib/ARCMigrate/PlistReporter.cpp4
-rw-r--r--lib/ARCMigrate/TransAPIUses.cpp2
-rw-r--r--lib/ARCMigrate/TransARCAssign.cpp2
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp4
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp3
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp2
-rw-r--r--lib/ARCMigrate/TransGCAttrs.cpp28
-rw-r--r--lib/ARCMigrate/TransGCCalls.cpp2
-rw-r--r--lib/ARCMigrate/TransProperties.cpp32
-rw-r--r--lib/ARCMigrate/TransProtectedScope.cpp202
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp125
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp108
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp2
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp2
-rw-r--r--lib/ARCMigrate/TransformActions.cpp2
-rw-r--r--lib/ARCMigrate/Transforms.cpp27
-rw-r--r--lib/ARCMigrate/Transforms.h10
-rw-r--r--lib/AST/APValue.cpp4
-rw-r--r--lib/AST/ASTConsumer.cpp2
-rw-r--r--lib/AST/ASTContext.cpp767
-rw-r--r--lib/AST/ASTDiagnostic.cpp567
-rw-r--r--lib/AST/ASTDumper.cpp1996
-rw-r--r--lib/AST/ASTImporter.cpp163
-rw-r--r--lib/AST/AttrImpl.cpp4
-rw-r--r--lib/AST/CMakeLists.txt7
-rw-r--r--lib/AST/CXXABI.h6
-rw-r--r--lib/AST/CXXInheritance.cpp43
-rw-r--r--lib/AST/Comment.cpp40
-rw-r--r--lib/AST/CommentBriefParser.cpp2
-rw-r--r--lib/AST/CommentCommandTraits.cpp34
-rw-r--r--lib/AST/CommentDumper.cpp257
-rw-r--r--lib/AST/CommentLexer.cpp127
-rw-r--r--lib/AST/CommentParser.cpp66
-rw-r--r--lib/AST/CommentSema.cpp269
-rw-r--r--lib/AST/Decl.cpp1305
-rw-r--r--lib/AST/DeclBase.cpp141
-rw-r--r--lib/AST/DeclCXX.cpp828
-rw-r--r--lib/AST/DeclFriend.cpp21
-rw-r--r--lib/AST/DeclGroup.cpp2
-rw-r--r--lib/AST/DeclObjC.cpp428
-rw-r--r--lib/AST/DeclOpenMP.cpp60
-rw-r--r--lib/AST/DeclPrinter.cpp193
-rw-r--r--lib/AST/DeclTemplate.cpp61
-rw-r--r--lib/AST/DeclarationName.cpp15
-rw-r--r--lib/AST/DumpXML.cpp28
-rw-r--r--lib/AST/Expr.cpp168
-rw-r--r--lib/AST/ExprCXX.cpp76
-rw-r--r--lib/AST/ExprClassification.cpp37
-rw-r--r--lib/AST/ExprConstant.cpp306
-rw-r--r--lib/AST/ExternalASTSource.cpp4
-rw-r--r--lib/AST/InheritViz.cpp2
-rw-r--r--lib/AST/ItaniumCXXABI.cpp15
-rw-r--r--lib/AST/ItaniumMangle.cpp80
-rw-r--r--lib/AST/LambdaMangleContext.cpp9
-rw-r--r--lib/AST/Mangle.cpp2
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp136
-rw-r--r--lib/AST/MicrosoftMangle.cpp218
-rw-r--r--lib/AST/NSAPI.cpp39
-rw-r--r--lib/AST/NestedNameSpecifier.cpp15
-rw-r--r--lib/AST/RawCommentList.cpp6
-rw-r--r--lib/AST/RecordLayout.cpp7
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp135
-rw-r--r--lib/AST/Stmt.cpp156
-rw-r--r--lib/AST/StmtDumper.cpp760
-rw-r--r--lib/AST/StmtPrinter.cpp214
-rw-r--r--lib/AST/TemplateBase.cpp21
-rw-r--r--lib/AST/TemplateName.cpp14
-rw-r--r--lib/AST/Type.cpp249
-rw-r--r--lib/AST/TypeLoc.cpp30
-rw-r--r--lib/AST/TypePrinter.cpp140
-rw-r--r--lib/AST/VTableBuilder.cpp126
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp236
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp7
-rw-r--r--lib/ASTMatchers/CMakeLists.txt6
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp68
-rw-r--r--lib/Analysis/BodyFarm.cpp18
-rw-r--r--lib/Analysis/BodyFarm.h5
-rw-r--r--lib/Analysis/CFG.cpp166
-rw-r--r--lib/Analysis/CFGStmtMap.cpp2
-rw-r--r--lib/Analysis/CallGraph.cpp112
-rw-r--r--lib/Analysis/CocoaConventions.cpp8
-rw-r--r--lib/Analysis/FormatString.cpp11
-rw-r--r--lib/Analysis/FormatStringParsing.h2
-rw-r--r--lib/Analysis/LiveVariables.cpp38
-rw-r--r--lib/Analysis/PrintfFormatString.cpp34
-rw-r--r--lib/Analysis/ReachableCode.cpp14
-rw-r--r--lib/Analysis/ScanfFormatString.cpp4
-rw-r--r--lib/Analysis/ThreadSafety.cpp290
-rw-r--r--lib/Analysis/UninitializedValues.cpp160
-rw-r--r--lib/Basic/Builtins.cpp2
-rw-r--r--lib/Basic/CMakeLists.txt30
-rw-r--r--lib/Basic/CharInfo.cpp81
-rw-r--r--lib/Basic/ConvertUTF.c571
-rw-r--r--lib/Basic/ConvertUTFWrapper.cpp76
-rw-r--r--lib/Basic/Diagnostic.cpp66
-rw-r--r--lib/Basic/DiagnosticIDs.cpp72
-rw-r--r--lib/Basic/FileManager.cpp50
-rw-r--r--lib/Basic/FileSystemStatCache.cpp20
-rw-r--r--lib/Basic/IdentifierTable.cpp21
-rw-r--r--lib/Basic/LangOptions.cpp10
-rw-r--r--lib/Basic/Module.cpp134
-rw-r--r--lib/Basic/OpenMPKinds.cpp43
-rw-r--r--lib/Basic/OperatorPrecedence.cpp76
-rw-r--r--lib/Basic/SourceLocation.cpp2
-rw-r--r--lib/Basic/SourceManager.cpp90
-rw-r--r--lib/Basic/TargetInfo.cpp24
-rw-r--r--lib/Basic/Targets.cpp810
-rw-r--r--lib/Basic/TokenKinds.cpp1
-rw-r--r--lib/Basic/Version.cpp10
-rw-r--r--lib/Basic/VersionTuple.cpp4
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/ABIInfo.h21
-rw-r--r--lib/CodeGen/BackendUtil.cpp153
-rw-r--r--lib/CodeGen/CGAtomic.cpp942
-rw-r--r--lib/CodeGen/CGBlocks.cpp306
-rw-r--r--lib/CodeGen/CGBlocks.h35
-rw-r--r--lib/CodeGen/CGBuilder.h2
-rw-r--r--lib/CodeGen/CGBuiltin.cpp141
-rw-r--r--lib/CodeGen/CGCUDANV.cpp13
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp4
-rw-r--r--lib/CodeGen/CGCXX.cpp10
-rw-r--r--lib/CodeGen/CGCXXABI.cpp27
-rw-r--r--lib/CodeGen/CGCXXABI.h57
-rw-r--r--lib/CodeGen/CGCall.cpp617
-rw-r--r--lib/CodeGen/CGCall.h36
-rw-r--r--lib/CodeGen/CGClass.cpp627
-rw-r--r--lib/CodeGen/CGCleanup.cpp12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp905
-rw-r--r--lib/CodeGen/CGDebugInfo.h72
-rw-r--r--lib/CodeGen/CGDecl.cpp339
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp32
-rw-r--r--lib/CodeGen/CGException.cpp273
-rw-r--r--lib/CodeGen/CGExpr.cpp1301
-rw-r--r--lib/CodeGen/CGExprAgg.cpp215
-rw-r--r--lib/CodeGen/CGExprCXX.cpp159
-rw-r--r--lib/CodeGen/CGExprComplex.cpp126
-rw-r--r--lib/CodeGen/CGExprConstant.cpp40
-rw-r--r--lib/CodeGen/CGExprScalar.cpp478
-rw-r--r--lib/CodeGen/CGObjC.cpp265
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp275
-rw-r--r--lib/CodeGen/CGObjCMac.cpp687
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp34
-rw-r--r--lib/CodeGen/CGObjCRuntime.h29
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp38
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.h6
-rw-r--r--lib/CodeGen/CGRTTI.cpp20
-rw-r--r--lib/CodeGen/CGRecordLayout.h182
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp431
-rw-r--r--lib/CodeGen/CGStmt.cpp94
-rw-r--r--lib/CodeGen/CGVTables.cpp224
-rw-r--r--lib/CodeGen/CGVTables.h24
-rw-r--r--lib/CodeGen/CGValue.h80
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenAction.cpp20
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp382
-rw-r--r--lib/CodeGen/CodeGenFunction.h276
-rw-r--r--lib/CodeGen/CodeGenModule.cpp598
-rw-r--r--lib/CodeGen/CodeGenModule.h99
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp96
-rw-r--r--lib/CodeGen/CodeGenTBAA.h57
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp86
-rw-r--r--lib/CodeGen/CodeGenTypes.h6
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp221
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp278
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp20
-rw-r--r--lib/CodeGen/TargetInfo.cpp696
-rw-r--r--lib/CodeGen/TargetInfo.h13
-rw-r--r--lib/Driver/Action.cpp1
-rw-r--r--lib/Driver/ArgList.cpp10
-rw-r--r--lib/Driver/CC1AsOptions.cpp2
-rw-r--r--lib/Driver/Compilation.cpp128
-rw-r--r--lib/Driver/Driver.cpp247
-rw-r--r--lib/Driver/InputInfo.h2
-rw-r--r--lib/Driver/Job.cpp2
-rw-r--r--lib/Driver/OptTable.cpp2
-rw-r--r--lib/Driver/Option.cpp7
-rw-r--r--lib/Driver/Phases.cpp1
-rw-r--r--lib/Driver/SanitizerArgs.h130
-rw-r--r--lib/Driver/ToolChain.cpp100
-rw-r--r--lib/Driver/ToolChains.cpp931
-rw-r--r--lib/Driver/ToolChains.h172
-rw-r--r--lib/Driver/Tools.cpp1920
-rw-r--r--lib/Driver/Tools.h90
-rw-r--r--lib/Driver/Types.cpp76
-rw-r--r--lib/Driver/WindowsToolChain.cpp60
-rw-r--r--lib/Edit/Commit.cpp6
-rw-r--r--lib/Edit/EditedSource.cpp80
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp180
-rw-r--r--lib/Format/CMakeLists.txt26
-rw-r--r--lib/Format/Format.cpp1763
-rw-r--r--lib/Format/Makefile13
-rw-r--r--lib/Format/TokenAnnotator.cpp1187
-rw-r--r--lib/Format/TokenAnnotator.h262
-rw-r--r--lib/Format/UnwrappedLineParser.cpp858
-rw-r--r--lib/Format/UnwrappedLineParser.h201
-rw-r--r--lib/Frontend/ASTConsumers.cpp26
-rw-r--r--lib/Frontend/ASTMerge.cpp4
-rw-r--r--lib/Frontend/ASTUnit.cpp117
-rw-r--r--lib/Frontend/CacheTokens.cpp6
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp19
-rw-r--r--lib/Frontend/CompilerInstance.cpp545
-rw-r--r--lib/Frontend/CompilerInvocation.cpp275
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp14
-rw-r--r--lib/Frontend/DependencyFile.cpp8
-rw-r--r--lib/Frontend/DependencyGraph.cpp15
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp326
-rw-r--r--lib/Frontend/FrontendAction.cpp40
-rw-r--r--lib/Frontend/FrontendActions.cpp157
-rw-r--r--lib/Frontend/FrontendOptions.cpp2
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp228
-rw-r--r--lib/Frontend/InitPreprocessor.cpp36
-rw-r--r--lib/Frontend/LayoutOverrideSource.cpp21
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp2
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp1
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp60
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp214
-rw-r--r--lib/Frontend/TextDiagnostic.cpp381
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp26
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp4
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp8
-rw-r--r--lib/Frontend/Warnings.cpp18
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp75
-rw-r--r--lib/FrontendTool/Makefile15
-rw-r--r--lib/Headers/CMakeLists.txt10
-rw-r--r--lib/Headers/altivec.h7850
-rw-r--r--lib/Headers/avx2intrin.h384
-rw-r--r--lib/Headers/avxintrin.h715
-rw-r--r--lib/Headers/cpuid.h9
-rw-r--r--lib/Headers/emmintrin.h860
-rw-r--r--lib/Headers/f16cintrin.h10
-rw-r--r--lib/Headers/immintrin.h9
-rw-r--r--lib/Headers/mm3dnow.h1
-rw-r--r--lib/Headers/mm_malloc.h28
-rw-r--r--lib/Headers/module.map2
-rw-r--r--lib/Headers/pmmintrin.h48
-rw-r--r--lib/Headers/prfchwintrin.h34
-rw-r--r--lib/Headers/rdseedintrin.h48
-rw-r--r--lib/Headers/smmintrin.h6
-rw-r--r--lib/Headers/stdalign.h5
-rw-r--r--lib/Headers/stddef.h28
-rw-r--r--lib/Headers/stdnoreturn.h30
-rw-r--r--lib/Headers/tmmintrin.h120
-rw-r--r--lib/Headers/unwind.h63
-rw-r--r--lib/Headers/x86intrin.h8
-rw-r--r--lib/Headers/xmmintrin.h618
-rw-r--r--lib/Lex/CMakeLists.txt1
-rw-r--r--lib/Lex/HeaderMap.cpp4
-rw-r--r--lib/Lex/HeaderSearch.cpp311
-rw-r--r--lib/Lex/Lexer.cpp797
-rw-r--r--lib/Lex/LiteralSupport.cpp54
-rw-r--r--lib/Lex/MacroArgs.cpp18
-rw-r--r--lib/Lex/MacroArgs.h4
-rw-r--r--lib/Lex/MacroInfo.cpp119
-rw-r--r--lib/Lex/ModuleMap.cpp428
-rw-r--r--lib/Lex/PPConditionalDirectiveRecord.cpp120
-rw-r--r--lib/Lex/PPDirectives.cpp229
-rw-r--r--lib/Lex/PPExpressions.cpp28
-rw-r--r--lib/Lex/PPLexerChange.cpp53
-rw-r--r--lib/Lex/PPMacroExpansion.cpp456
-rw-r--r--lib/Lex/PTHLexer.cpp11
-rw-r--r--lib/Lex/Pragma.cpp220
-rw-r--r--lib/Lex/PreprocessingRecord.cpp189
-rw-r--r--lib/Lex/Preprocessor.cpp185
-rw-r--r--lib/Lex/PreprocessorLexer.cpp4
-rw-r--r--lib/Lex/TokenConcatenation.cpp36
-rw-r--r--lib/Lex/TokenLexer.cpp18
-rw-r--r--lib/Lex/UnicodeCharSets.h496
-rwxr-xr-xlib/Makefile18
-rw-r--r--lib/Parse/CMakeLists.txt1
-rw-r--r--lib/Parse/ParseAST.cpp61
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp55
-rw-r--r--lib/Parse/ParseDecl.cpp450
-rw-r--r--lib/Parse/ParseDeclCXX.cpp373
-rw-r--r--lib/Parse/ParseExpr.cpp139
-rw-r--r--lib/Parse/ParseExprCXX.cpp74
-rw-r--r--lib/Parse/ParseInit.cpp4
-rw-r--r--lib/Parse/ParseObjc.cpp125
-rw-r--r--lib/Parse/ParseOpenMP.cpp118
-rw-r--r--lib/Parse/ParsePragma.cpp46
-rw-r--r--lib/Parse/ParsePragma.h15
-rw-r--r--lib/Parse/ParseStmt.cpp114
-rw-r--r--lib/Parse/ParseTemplate.cpp197
-rw-r--r--lib/Parse/ParseTentative.cpp53
-rw-r--r--lib/Parse/Parser.cpp105
-rw-r--r--lib/Parse/RAIIObjectsForParser.h2
-rw-r--r--lib/Rewrite/Core/DeltaTree.cpp2
-rw-r--r--lib/Rewrite/Core/HTMLRewrite.cpp9
-rw-r--r--lib/Rewrite/Core/Rewriter.cpp8
-rw-r--r--lib/Rewrite/Core/TokenRewriter.cpp2
-rw-r--r--lib/Rewrite/Frontend/CMakeLists.txt1
-rw-r--r--lib/Rewrite/Frontend/FixItRewriter.cpp8
-rw-r--r--lib/Rewrite/Frontend/FrontendActions.cpp14
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp4
-rw-r--r--lib/Rewrite/Frontend/RewriteMacros.cpp8
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp568
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp172
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp144
-rw-r--r--lib/Sema/AttributeList.cpp13
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp61
-rw-r--r--lib/Sema/DeclSpec.cpp84
-rw-r--r--lib/Sema/IdentifierResolver.cpp14
-rw-r--r--lib/Sema/JumpDiagnostics.cpp14
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp28
-rw-r--r--lib/Sema/Sema.cpp272
-rw-r--r--lib/Sema/SemaAccess.cpp271
-rw-r--r--lib/Sema/SemaAttr.cpp5
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp45
-rw-r--r--lib/Sema/SemaCast.cpp132
-rw-r--r--lib/Sema/SemaChecking.cpp922
-rw-r--r--lib/Sema/SemaCodeComplete.cpp540
-rw-r--r--lib/Sema/SemaDecl.cpp2272
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1240
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2314
-rw-r--r--lib/Sema/SemaDeclObjC.cpp359
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp116
-rw-r--r--lib/Sema/SemaExpr.cpp976
-rw-r--r--lib/Sema/SemaExprCXX.cpp395
-rw-r--r--lib/Sema/SemaExprMember.cpp110
-rw-r--r--lib/Sema/SemaExprObjC.cpp340
-rw-r--r--lib/Sema/SemaFixItUtils.cpp4
-rw-r--r--lib/Sema/SemaInit.cpp439
-rw-r--r--lib/Sema/SemaLambda.cpp294
-rw-r--r--lib/Sema/SemaLookup.cpp233
-rw-r--r--lib/Sema/SemaObjCProperty.cpp468
-rw-r--r--lib/Sema/SemaOpenMP.cpp181
-rw-r--r--lib/Sema/SemaOverload.cpp448
-rw-r--r--lib/Sema/SemaPseudoObject.cpp27
-rw-r--r--lib/Sema/SemaStmt.cpp201
-rw-r--r--lib/Sema/SemaStmtAsm.cpp99
-rw-r--r--lib/Sema/SemaStmtAttr.cpp4
-rw-r--r--lib/Sema/SemaTemplate.cpp208
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp104
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp120
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp334
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp57
-rw-r--r--lib/Sema/SemaType.cpp860
-rw-r--r--lib/Sema/TargetAttributesSema.cpp76
-rw-r--r--lib/Sema/TreeTransform.h316
-rw-r--r--lib/Sema/TypeLocBuilder.h8
-rw-r--r--lib/Serialization/ASTCommon.cpp134
-rw-r--r--lib/Serialization/ASTCommon.h17
-rw-r--r--lib/Serialization/ASTReader.cpp2238
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp200
-rw-r--r--lib/Serialization/ASTReaderInternals.h128
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp55
-rw-r--r--lib/Serialization/ASTWriter.cpp974
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp78
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp13
-rw-r--r--lib/Serialization/CMakeLists.txt3
-rw-r--r--lib/Serialization/GeneratePCH.cpp10
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp820
-rw-r--r--lib/Serialization/Module.cpp6
-rw-r--r--lib/Serialization/ModuleManager.cpp316
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp130
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp176
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt4
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp166
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp61
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp45
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td38
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h4
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp102
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp66
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp38
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp431
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp139
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp1096
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp193
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp166
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp243
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp98
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp107
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp61
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/TraversalChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp36
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/APSIntType.cpp31
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp134
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp651
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp858
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp129
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp60
-rw-r--r--lib/StaticAnalyzer/Core/CheckerRegistry.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp54
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp78
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp130
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp665
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp123
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp230
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp572
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/FunctionSummary.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp13
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp228
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp219
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp63
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp167
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp24
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp1506
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp70
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp64
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp101
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h9
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp161
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp53
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp5
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp257
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp12
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp2
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp4
-rw-r--r--lib/Tooling/CompilationDatabase.cpp11
-rw-r--r--lib/Tooling/FileMatchTrie.cpp4
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp94
-rw-r--r--lib/Tooling/Refactoring.cpp75
-rw-r--r--lib/Tooling/Tooling.cpp43
468 files changed, 56083 insertions, 30139 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index b57d9964736f..72f35205ca8e 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -8,18 +8,19 @@
//===----------------------------------------------------------------------===//
#include "Internals.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
-#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Basic/DiagnosticCategories.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
using namespace arcmt;
@@ -39,8 +40,9 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
cleared = true;
ListTy::iterator eraseS = I++;
- while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
- ++I;
+ if (eraseS->getLevel() != DiagnosticsEngine::Note)
+ while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
+ ++I;
// Clear the diagnostic and any notes following it.
I = List.erase(eraseS, I);
continue;
@@ -130,7 +132,8 @@ public:
const Diagnostic &Info) {
if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
- CapturedDiags.push_back(StoredDiagnostic(level, Info));
+ if (Info.getLocation().isValid())
+ CapturedDiags.push_back(StoredDiagnostic(level, Info));
return;
}
@@ -172,8 +175,24 @@ static CompilerInvocation *
createInvocationForMigration(CompilerInvocation &origCI) {
OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(origCI));
- CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string();
- CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string();
+ PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
+ if (!PPOpts.ImplicitPCHInclude.empty()) {
+ // We can't use a PCH because it was likely built in non-ARC mode and we
+ // want to parse in ARC. Include the original header.
+ FileManager FileMgr(origCI.getFileSystemOpts());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ new IgnoringDiagConsumer()));
+ std::string OriginalFile =
+ ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude,
+ FileMgr, *Diags);
+ if (!OriginalFile.empty())
+ PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
+ PPOpts.ImplicitPCHInclude.clear();
+ }
+ // FIXME: Get the original header of a PTH as well.
+ CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
std::string define = getARCMTMacroName();
define += '=';
CInvok->getPreprocessorOpts().addMacroDef(define);
@@ -295,7 +314,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
std::vector<SourceLocation> ARCMTMacroLocs;
TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
- MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, ARCMTMacroLocs);
+ MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
+ ARCMTMacroLocs);
pass.setNSAllocReallocError(NoNSAllocReallocError);
pass.setNoFinalizeRemoval(NoFinalizeRemoval);
@@ -416,8 +436,8 @@ bool arcmt::getFileRemappingsFromFileList(
bool hasErrorOccurred = false;
llvm::StringMap<bool> Uniquer;
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, new DiagnosticOptions,
DiagClient, /*ShouldOwnClient=*/false));
@@ -461,7 +481,7 @@ public:
ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
: ARCMTMacroLocs(ARCMTMacroLocs) { }
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI,
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range) {
if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
@@ -598,7 +618,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
- Unit->getSema(), TA, ARCMTMacroLocs);
+ Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
trans(pass);
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index 731bcb4fc7f9..da51d6db83b8 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -9,15 +9,16 @@ add_clang_library(clangARCMigrate
TransAutoreleasePool.cpp
TransBlockObjCVariable.cpp
TransEmptyStatementsAndDealloc.cpp
- TransformActions.cpp
- Transforms.cpp
TransGCAttrs.cpp
TransGCCalls.cpp
TransProperties.cpp
+ TransProtectedScope.cpp
TransRetainReleaseDealloc.cpp
TransUnbridgedCasts.cpp
TransUnusedInitDelegate.cpp
TransZeroOutPropsInDealloc.cpp
+ TransformActions.cpp
+ Transforms.cpp
)
add_dependencies(clangARCMigrate
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 28ca9a56b20e..6a8686c4ff0f 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -8,12 +8,12 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <fstream>
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 1966a9823b92..3690c83d8457 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -146,16 +146,20 @@ public:
MigratorOptions MigOptions;
Sema &SemaRef;
TransformActions &TA;
+ const CapturedDiagList &CapturedDiags;
std::vector<SourceLocation> &ARCMTMacroLocs;
- llvm::Optional<bool> EnableCFBridgeFns;
+ Optional<bool> EnableCFBridgeFns;
MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode,
Sema &sema, TransformActions &TA,
+ const CapturedDiagList &capturedDiags,
std::vector<SourceLocation> &ARCMTMacroLocs)
: Ctx(Ctx), OrigGCMode(OrigGCMode), MigOptions(),
- SemaRef(sema), TA(TA),
+ SemaRef(sema), TA(TA), CapturedDiags(capturedDiags),
ARCMTMacroLocs(ARCMTMacroLocs) { }
+ 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; }
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index dfe14e2b5dd7..57fac0389fc3 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -8,19 +8,21 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/ARCMTActions.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/NSAPI.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/Edit/Rewriters.h"
-#include "clang/Edit/EditedSource.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
#include "clang/Edit/EditsReceiver.h"
-#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Edit/Rewriters.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Basic/FileManager.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -35,11 +37,11 @@ public:
std::string MigrateDir;
bool MigrateLiterals;
bool MigrateSubscripting;
- llvm::OwningPtr<NSAPI> NSAPIObj;
- llvm::OwningPtr<edit::EditedSource> Editor;
+ OwningPtr<NSAPI> NSAPIObj;
+ OwningPtr<edit::EditedSource> Editor;
FileRemapper &Remapper;
FileManager &FileMgr;
- const PreprocessingRecord *PPRec;
+ const PPConditionalDirectiveRecord *PPRec;
bool IsOutputFile;
ObjCMigrateASTConsumer(StringRef migrateDir,
@@ -47,7 +49,7 @@ public:
bool migrateSubscripting,
FileRemapper &remapper,
FileManager &fileMgr,
- const PreprocessingRecord *PPRec,
+ const PPConditionalDirectiveRecord *PPRec,
bool isOutputFile = false)
: MigrateDir(migrateDir),
MigrateLiterals(migrateLiterals),
@@ -93,6 +95,9 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
+ PPConditionalDirectiveRecord *
+ PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
+ CompInst->getPreprocessor().addPPCallbacks(PPRec);
ASTConsumer *
WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
@@ -100,7 +105,7 @@ ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
MigrateSubscripting,
Remapper,
CompInst->getFileManager(),
- CompInst->getPreprocessor().getPreprocessingRecord());
+ PPRec);
ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
return new MultiplexConsumer(Consumers);
}
@@ -110,17 +115,17 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
/*ignoreIfFilesChanges=*/true);
CompInst = &CI;
CI.getDiagnostics().setIgnoreAllWarnings(true);
- CI.getPreprocessorOpts().DetailedRecord = true;
- CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
return true;
}
namespace {
class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
ObjCMigrateASTConsumer &Consumer;
+ ParentMap &PMap;
public:
- ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+ ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
+ : Consumer(consumer), PMap(PMap) { }
bool shouldVisitTemplateInstantiations() const { return false; }
bool shouldWalkTypesOfTypeLocs() const { return false; }
@@ -128,7 +133,7 @@ public:
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
if (Consumer.MigrateLiterals) {
edit::Commit commit(*Consumer.Editor);
- edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit);
+ edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Consumer.Editor->commit(commit);
}
@@ -151,6 +156,23 @@ public:
return WalkUpFromObjCMessageExpr(E);
}
};
+
+class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
+ ObjCMigrateASTConsumer &Consumer;
+ OwningPtr<ParentMap> PMap;
+
+public:
+ BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+
+ bool shouldVisitTemplateInstantiations() const { return false; }
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool TraverseStmt(Stmt *S) {
+ PMap.reset(new ParentMap(S));
+ ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
+ return true;
+ }
+};
}
void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
@@ -159,7 +181,7 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
if (isa<ObjCMethodDecl>(D))
return; // Wait for the ObjC container declaration.
- ObjCMigrator(*this).TraverseDecl(D);
+ BodyMigrator(*this).TraverseDecl(D);
}
namespace {
@@ -191,13 +213,13 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
- llvm::SmallString<512> newText;
+ SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
vecOS.flush();
llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
StringRef(newText.data(), newText.size()), file->getName());
- llvm::SmallString<64> filePath(file->getName());
+ SmallString<64> filePath(file->getName());
FileMgr.FixupRelativePath(filePath);
Remapper.remap(filePath.str(), memBuf);
}
@@ -211,18 +233,19 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
CI.getDiagnostics().setIgnoreAllWarnings(true);
- CI.getPreprocessorOpts().DetailedRecord = true;
- CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
return true;
}
ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
+ PPConditionalDirectiveRecord *
+ PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
+ CI.getPreprocessor().addPPCallbacks(PPRec);
return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
/*MigrateLiterals=*/true,
/*MigrateSubscripting=*/true,
Remapper,
CI.getFileManager(),
- CI.getPreprocessor().getPreprocessingRecord(),
+ PPRec,
/*isOutputFile=*/true);
}
diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp
index d1bc90fdbe16..144ba2e398ad 100644
--- a/lib/ARCMigrate/PlistReporter.cpp
+++ b/lib/ARCMigrate/PlistReporter.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "Internals.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
using namespace clang;
using namespace arcmt;
diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp
index 5336f859052f..2305b6defd9c 100644
--- a/lib/ARCMigrate/TransAPIUses.cpp
+++ b/lib/ARCMigrate/TransAPIUses.cpp
@@ -1,4 +1,4 @@
-//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===//
+//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp
index b83f85a1fac2..80bfd22d6258 100644
--- a/lib/ARCMigrate/TransARCAssign.cpp
+++ b/lib/ARCMigrate/TransARCAssign.cpp
@@ -1,4 +1,4 @@
-//===--- TransARCAssign.cpp - Tranformations to ARC mode ------------------===//
+//===--- TransARCAssign.cpp - Transformations to ARC mode -----------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
index 5205ce4a70a9..a2990e7226ab 100644
--- a/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -1,4 +1,4 @@
-//===--- TransAutoreleasePool.cpp - Tranformations to ARC mode ------------===//
+//===--- TransAutoreleasePool.cpp - Transformations to ARC mode -----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -30,8 +30,8 @@
#include "Transforms.h"
#include "Internals.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include <map>
using namespace clang;
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 2a79c9aeff20..97c4e3480c15 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -1,4 +1,4 @@
-//===--- TransBlockObjCVariable.cpp - Tranformations to ARC mode ----------===//
+//===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===//
//
// The LLVM Compiler Infrastructure
//
@@ -28,6 +28,7 @@
#include "Transforms.h"
#include "Internals.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index 552cb2fa631c..ffb638f8a306 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -1,4 +1,4 @@
-//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===//
+//===--- TransEmptyStatements.cpp - Transformations to ARC mode -----------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp
index eec7306ba74a..d8be1ae746ab 100644
--- a/lib/ARCMigrate/TransGCAttrs.cpp
+++ b/lib/ARCMigrate/TransGCAttrs.cpp
@@ -63,19 +63,18 @@ public:
return;
TypeLoc TL = TInfo->getTypeLoc();
while (TL) {
- if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QL->getUnqualifiedLoc();
- } else if (const AttributedTypeLoc *
- Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
- if (handleAttr(*Attr, D))
+ if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QL.getUnqualifiedLoc();
+ } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
+ if (handleAttr(Attr, D))
break;
- TL = Attr->getModifiedLoc();
- } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
- TL = Arr->getElementLoc();
- } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
- TL = PT->getPointeeLoc();
- } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
- TL = RT->getPointeeLoc();
+ TL = Attr.getModifiedLoc();
+ } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
+ TL = Arr.getElementLoc();
+ } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
+ TL = PT.getPointeeLoc();
+ } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
+ TL = RT.getPointeeLoc();
else
break;
}
@@ -249,8 +248,9 @@ static void checkAllAtProps(MigrationContext &MigrateCtx,
if (!TInfo)
return;
TypeLoc TL = TInfo->getTypeLoc();
- if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
- ATLs.push_back(std::make_pair(*ATL, PD));
+ if (AttributedTypeLoc ATL =
+ TL.getAs<AttributedTypeLoc>()) {
+ ATLs.push_back(std::make_pair(ATL, PD));
if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
hasWeak = true;
} else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp
index 2ec480c0af64..249f20f01b22 100644
--- a/lib/ARCMigrate/TransGCCalls.cpp
+++ b/lib/ARCMigrate/TransGCCalls.cpp
@@ -1,4 +1,4 @@
-//===--- TransGCCalls.cpp - Tranformations to ARC mode --------------------===//
+//===--- TransGCCalls.cpp - Transformations to ARC mode -------------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index fdd6e8863b59..b6ddc43dd69f 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -1,4 +1,4 @@
-//===--- TransProperties.cpp - Tranformations to ARC mode -----------------===//
+//===--- TransProperties.cpp - Transformations to ARC mode ----------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -32,9 +32,9 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include <map>
using namespace clang;
@@ -141,10 +141,12 @@ public:
AtPropDeclsTy AtExtProps;
// Look through extensions.
- for (ObjCCategoryDecl *Cat = iface->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory())
- if (Cat->IsClassExtension())
- collectProperties(Cat, AtExtProps, &AtProps);
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ ext = iface->visible_extensions_begin(),
+ extEnd = iface->visible_extensions_end();
+ ext != extEnd; ++ext) {
+ collectProperties(*ext, AtExtProps, &AtProps);
+ }
for (AtPropDeclsTy::iterator
I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
@@ -226,8 +228,10 @@ private:
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
if (I->ImplD)
- Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
- I->ImplD->getLocation());
+ Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
+ diag::err_arc_assign_property_ownership,
+ diag::err_arc_inconsistent_property_ownership,
+ I->IvarD->getLocation());
}
}
@@ -253,8 +257,10 @@ private:
}
}
if (I->ImplD)
- Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
- I->ImplD->getLocation());
+ Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
+ diag::err_arc_assign_property_ownership,
+ diag::err_arc_inconsistent_property_ownership,
+ I->IvarD->getLocation());
}
}
@@ -276,8 +282,10 @@ private:
canUseWeak ? "__weak " : "__unsafe_unretained ");
}
if (I->ImplD) {
- Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
- I->ImplD->getLocation());
+ Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
+ diag::err_arc_assign_property_ownership,
+ diag::err_arc_inconsistent_property_ownership,
+ I->IvarD->getLocation());
Pass.TA.clearDiagnostic(
diag::err_arc_objc_property_default_assign_on_object,
I->ImplD->getLocation());
diff --git a/lib/ARCMigrate/TransProtectedScope.cpp b/lib/ARCMigrate/TransProtectedScope.cpp
new file mode 100644
index 000000000000..237aa42877e6
--- /dev/null
+++ b/lib/ARCMigrate/TransProtectedScope.cpp
@@ -0,0 +1,202 @@
+//===--- TransProtectedScope.cpp - Transformations to ARC mode ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Adds brackets in case statements that "contain" initialization of retaining
+// variable, thus emitting the "switch case is in protected scope" error.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+
+namespace {
+
+class LocalRefsCollector : public RecursiveASTVisitor<LocalRefsCollector> {
+ SmallVectorImpl<DeclRefExpr *> &Refs;
+
+public:
+ LocalRefsCollector(SmallVectorImpl<DeclRefExpr *> &refs)
+ : Refs(refs) { }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (ValueDecl *D = E->getDecl())
+ if (D->getDeclContext()->getRedeclContext()->isFunctionOrMethod())
+ Refs.push_back(E);
+ return true;
+ }
+};
+
+struct CaseInfo {
+ SwitchCase *SC;
+ SourceRange Range;
+ enum {
+ St_Unchecked,
+ St_CannotFix,
+ St_Fixed
+ } State;
+
+ CaseInfo() : SC(0), State(St_Unchecked) {}
+ CaseInfo(SwitchCase *S, SourceRange Range)
+ : SC(S), Range(Range), State(St_Unchecked) {}
+};
+
+class CaseCollector : public RecursiveASTVisitor<CaseCollector> {
+ ParentMap &PMap;
+ SmallVectorImpl<CaseInfo> &Cases;
+
+public:
+ CaseCollector(ParentMap &PMap, SmallVectorImpl<CaseInfo> &Cases)
+ : PMap(PMap), Cases(Cases) { }
+
+ bool VisitSwitchStmt(SwitchStmt *S) {
+ SwitchCase *Curr = S->getSwitchCaseList();
+ if (!Curr)
+ return true;
+ Stmt *Parent = getCaseParent(Curr);
+ Curr = Curr->getNextSwitchCase();
+ // Make sure all case statements are in the same scope.
+ while (Curr) {
+ if (getCaseParent(Curr) != Parent)
+ return true;
+ Curr = Curr->getNextSwitchCase();
+ }
+
+ SourceLocation NextLoc = S->getLocEnd();
+ Curr = S->getSwitchCaseList();
+ // We iterate over case statements in reverse source-order.
+ while (Curr) {
+ Cases.push_back(CaseInfo(Curr,SourceRange(Curr->getLocStart(), NextLoc)));
+ NextLoc = Curr->getLocStart();
+ Curr = Curr->getNextSwitchCase();
+ }
+ return true;
+ }
+
+ Stmt *getCaseParent(SwitchCase *S) {
+ Stmt *Parent = PMap.getParent(S);
+ while (Parent && (isa<SwitchCase>(Parent) || isa<LabelStmt>(Parent)))
+ Parent = PMap.getParent(Parent);
+ return Parent;
+ }
+};
+
+class ProtectedScopeFixer {
+ MigrationPass &Pass;
+ SourceManager &SM;
+ SmallVector<CaseInfo, 16> Cases;
+ SmallVector<DeclRefExpr *, 16> LocalRefs;
+
+public:
+ ProtectedScopeFixer(BodyContext &BodyCtx)
+ : Pass(BodyCtx.getMigrationContext().Pass),
+ SM(Pass.Ctx.getSourceManager()) {
+
+ CaseCollector(BodyCtx.getParentMap(), Cases)
+ .TraverseStmt(BodyCtx.getTopStmt());
+ LocalRefsCollector(LocalRefs).TraverseStmt(BodyCtx.getTopStmt());
+
+ SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange();
+ const CapturedDiagList &DiagList = Pass.getDiags();
+ // Copy the diagnostics so we don't have to worry about invaliding iterators
+ // from the diagnostic list.
+ SmallVector<StoredDiagnostic, 16> StoredDiags;
+ StoredDiags.append(DiagList.begin(), DiagList.end());
+ SmallVectorImpl<StoredDiagnostic>::iterator
+ I = StoredDiags.begin(), E = StoredDiags.end();
+ while (I != E) {
+ if (I->getID() == diag::err_switch_into_protected_scope &&
+ isInRange(I->getLocation(), BodyRange)) {
+ handleProtectedScopeError(I, E);
+ continue;
+ }
+ ++I;
+ }
+ }
+
+ void handleProtectedScopeError(
+ SmallVectorImpl<StoredDiagnostic>::iterator &DiagI,
+ SmallVectorImpl<StoredDiagnostic>::iterator DiagE){
+ Transaction Trans(Pass.TA);
+ assert(DiagI->getID() == diag::err_switch_into_protected_scope);
+ SourceLocation ErrLoc = DiagI->getLocation();
+ bool handledAllNotes = true;
+ ++DiagI;
+ for (; DiagI != DiagE && DiagI->getLevel() == DiagnosticsEngine::Note;
+ ++DiagI) {
+ if (!handleProtectedNote(*DiagI))
+ handledAllNotes = false;
+ }
+
+ if (handledAllNotes)
+ Pass.TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc);
+ }
+
+ bool handleProtectedNote(const StoredDiagnostic &Diag) {
+ assert(Diag.getLevel() == DiagnosticsEngine::Note);
+
+ for (unsigned i = 0; i != Cases.size(); i++) {
+ CaseInfo &info = Cases[i];
+ if (isInRange(Diag.getLocation(), info.Range)) {
+
+ if (info.State == CaseInfo::St_Unchecked)
+ tryFixing(info);
+ assert(info.State != CaseInfo::St_Unchecked);
+
+ if (info.State == CaseInfo::St_Fixed) {
+ Pass.TA.clearDiagnostic(Diag.getID(), Diag.getLocation());
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ void tryFixing(CaseInfo &info) {
+ assert(info.State == CaseInfo::St_Unchecked);
+ if (hasVarReferencedOutside(info)) {
+ info.State = CaseInfo::St_CannotFix;
+ return;
+ }
+
+ Pass.TA.insertAfterToken(info.SC->getColonLoc(), " {");
+ Pass.TA.insert(info.Range.getEnd(), "}\n");
+ info.State = CaseInfo::St_Fixed;
+ }
+
+ bool hasVarReferencedOutside(CaseInfo &info) {
+ for (unsigned i = 0, e = LocalRefs.size(); i != e; ++i) {
+ DeclRefExpr *DRE = LocalRefs[i];
+ if (isInRange(DRE->getDecl()->getLocation(), info.Range) &&
+ !isInRange(DRE->getLocation(), info.Range))
+ return true;
+ }
+ return false;
+ }
+
+ bool isInRange(SourceLocation Loc, SourceRange R) {
+ if (Loc.isInvalid())
+ return false;
+ return !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) &&
+ SM.isBeforeInTranslationUnit(Loc, R.getEnd());
+ }
+};
+
+} // anonymous namespace
+
+void ProtectedScopeTraverser::traverseBody(BodyContext &BodyCtx) {
+ ProtectedScopeFixer Fix(BodyCtx);
+}
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 91d2b399e3f1..0c8d15544610 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -1,4 +1,4 @@
-//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===//
+//===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===//
//
// The LLVM Compiler Infrastructure
//
@@ -24,6 +24,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace arcmt;
@@ -161,13 +162,47 @@ public:
private:
/// \brief Checks for idioms where an unused -autorelease is common.
///
- /// Currently only returns true for this idiom which is common in property
+ /// Returns true for this idiom which is common in property
/// setters:
///
/// [backingValue autorelease];
/// backingValue = [newValue retain]; // in general a +1 assign
///
+ /// For these as well:
+ ///
+ /// [[var retain] autorelease];
+ /// return var;
+ ///
bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
+ if (isPlusOneAssignBeforeOrAfterAutorelease(E))
+ return true;
+ if (isReturnedAfterAutorelease(E))
+ return true;
+ return false;
+ }
+
+ bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
+ Expr *Rec = E->getInstanceReceiver();
+ if (!Rec)
+ return false;
+
+ Decl *RefD = getReferencedDecl(Rec);
+ if (!RefD)
+ return false;
+
+ Stmt *nextStmt = getNextStmt(E);
+ if (!nextStmt)
+ return false;
+
+ // Check for "return <variable>;".
+
+ if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
+ return RefD == getReferencedDecl(RetS->getRetValue());
+
+ return false;
+ }
+
+ bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
Expr *Rec = E->getInstanceReceiver();
if (!Rec)
return false;
@@ -176,6 +211,47 @@ private:
if (!RefD)
return false;
+ Stmt *prevStmt, *nextStmt;
+ llvm::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
+
+ return isPlusOneAssignToVar(prevStmt, RefD) ||
+ isPlusOneAssignToVar(nextStmt, RefD);
+ }
+
+ bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
+ if (!S)
+ return false;
+
+ // Check for "RefD = [+1 retained object];".
+
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
+ if (RefD != getReferencedDecl(Bop->getLHS()))
+ return false;
+ if (isPlusOneAssign(Bop))
+ return true;
+ return false;
+ }
+
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
+ return isPlusOne(VD->getInit());
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ Stmt *getNextStmt(Expr *E) {
+ return getPreviousAndNextStmt(E).second;
+ }
+
+ std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
+ Stmt *prevStmt = 0, *nextStmt = 0;
+ if (!E)
+ return std::make_pair(prevStmt, nextStmt);
+
Stmt *OuterS = E, *InnerS;
do {
InnerS = OuterS;
@@ -186,36 +262,34 @@ private:
isa<ExprWithCleanups>(OuterS)));
if (!OuterS)
- return false;
-
- // Find next statement after the -autorelease.
+ return std::make_pair(prevStmt, nextStmt);
Stmt::child_iterator currChildS = OuterS->child_begin();
Stmt::child_iterator childE = OuterS->child_end();
+ Stmt::child_iterator prevChildS = childE;
for (; currChildS != childE; ++currChildS) {
if (*currChildS == InnerS)
break;
+ prevChildS = currChildS;
}
+
+ if (prevChildS != childE) {
+ prevStmt = *prevChildS;
+ if (prevStmt)
+ prevStmt = prevStmt->IgnoreImplicit();
+ }
+
if (currChildS == childE)
- return false;
+ return std::make_pair(prevStmt, nextStmt);
++currChildS;
if (currChildS == childE)
- return false;
+ return std::make_pair(prevStmt, nextStmt);
- Stmt *nextStmt = *currChildS;
- if (!nextStmt)
- return false;
- nextStmt = nextStmt->IgnoreImplicit();
+ nextStmt = *currChildS;
+ if (nextStmt)
+ nextStmt = nextStmt->IgnoreImplicit();
- // Check for "RefD = [+1 retained object];".
-
- if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(nextStmt)) {
- if (RefD != getReferencedDecl(Bop->getLHS()))
- return false;
- if (isPlusOneAssign(Bop))
- return true;
- }
- return false;
+ return std::make_pair(prevStmt, nextStmt);
}
Decl *getReferencedDecl(Expr *E) {
@@ -223,6 +297,17 @@ private:
return 0;
E = E->IgnoreParenCasts();
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ switch (ME->getMethodFamily()) {
+ case OMF_copy:
+ case OMF_autorelease:
+ case OMF_release:
+ case OMF_retain:
+ return getReferencedDecl(ME->getInstanceReceiver());
+ default:
+ return 0;
+ }
+ }
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index ac18b5d6e739..fc4a75fdb838 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -1,4 +1,4 @@
-//===--- TransUnbridgedCasts.cpp - Tranformations to ARC mode -------------===//
+//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -30,13 +30,22 @@
// ---->
// CFStringRef str = (__bridge CFStringRef)self;
//
+// Uses of Block_copy/Block_release macros are rewritten:
+//
+// c = Block_copy(b);
+// Block_release(c);
+// ---->
+// c = [b copy];
+// <removed>
+//
//===----------------------------------------------------------------------===//
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -53,32 +62,32 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
IdentifierInfo *SelfII;
OwningPtr<ParentMap> StmtMap;
Decl *ParentD;
+ Stmt *Body;
+ mutable OwningPtr<ExprSet> Removables;
public:
- UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
+ UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) {
SelfII = &Pass.Ctx.Idents.get("self");
}
void transformBody(Stmt *body, Decl *ParentD) {
this->ParentD = ParentD;
+ Body = body;
StmtMap.reset(new ParentMap(body));
TraverseStmt(body);
}
bool VisitCastExpr(CastExpr *E) {
- if (E->getCastKind() != CK_CPointerToObjCPointerCast
- && E->getCastKind() != CK_BitCast)
+ if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
+ E->getCastKind() != CK_BitCast &&
+ E->getCastKind() != CK_AnyPointerToBlockPointerCast)
return true;
QualType castType = E->getType();
Expr *castExpr = E->getSubExpr();
QualType castExprType = castExpr->getType();
- if (castType->isObjCObjectPointerType() &&
- castExprType->isObjCObjectPointerType())
- return true;
- if (!castType->isObjCObjectPointerType() &&
- !castExprType->isObjCObjectPointerType())
+ if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
return true;
bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
@@ -93,7 +102,7 @@ public:
if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
return true;
- if (castType->isObjCObjectPointerType())
+ if (castType->isObjCRetainableType())
transformNonObjCToObjCCast(E);
else
transformObjCToNonObjCCast(E);
@@ -139,7 +148,7 @@ private:
if (FD->getName() == "CFRetain" &&
FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage) {
+ FD->hasExternalLinkage()) {
Expr *Arg = callE->getArg(0);
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
const Expr *sub = ICE->getSubExpr();
@@ -262,7 +271,78 @@ private:
rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
}
+ void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+ SourceLocation Loc = E->getExprLoc();
+ assert(Loc.isMacroID());
+ SourceLocation MacroBegin, MacroEnd;
+ llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
+ SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
+ SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
+ SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
+
+ Outer = SourceRange(MacroBegin, MacroEnd);
+ Inner = SourceRange(InnerBegin, InnerEnd);
+ }
+
+ void rewriteBlockCopyMacro(CastExpr *E) {
+ SourceRange OuterRange, InnerRange;
+ getBlockMacroRanges(E, OuterRange, InnerRange);
+
+ Transaction Trans(Pass.TA);
+ Pass.TA.replace(OuterRange, InnerRange);
+ Pass.TA.insert(InnerRange.getBegin(), "[");
+ Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
+ Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+ diag::err_arc_cast_requires_bridge,
+ OuterRange);
+ }
+
+ void removeBlockReleaseMacro(CastExpr *E) {
+ SourceRange OuterRange, InnerRange;
+ getBlockMacroRanges(E, OuterRange, InnerRange);
+
+ Transaction Trans(Pass.TA);
+ Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+ diag::err_arc_cast_requires_bridge,
+ OuterRange);
+ if (!hasSideEffects(E, Pass.Ctx)) {
+ if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
+ return;
+ }
+ Pass.TA.replace(OuterRange, InnerRange);
+ }
+
+ bool tryRemoving(Expr *E) const {
+ if (!Removables) {
+ Removables.reset(new ExprSet);
+ collectRemovables(Body, *Removables);
+ }
+
+ if (Removables->count(E)) {
+ Pass.TA.removeStmt(E);
+ return true;
+ }
+
+ return false;
+ }
+
void transformObjCToNonObjCCast(CastExpr *E) {
+ SourceLocation CastLoc = E->getExprLoc();
+ if (CastLoc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
+ Pass.Ctx.getSourceManager(),
+ Pass.Ctx.getLangOpts());
+ if (MacroName == "Block_copy") {
+ rewriteBlockCopyMacro(E);
+ return;
+ }
+ if (MacroName == "Block_release") {
+ removeBlockReleaseMacro(E);
+ return;
+ }
+ }
+
if (isSelf(E->getSubExpr()))
return rewriteToBridgedCast(E, OBC_Bridge);
@@ -333,7 +413,7 @@ private:
FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage)
+ FD->hasExternalLinkage())
return true;
return false;
@@ -350,7 +430,7 @@ private:
if (arg == E || arg->IgnoreParenImpCasts() == E)
break;
}
- if (i < callE->getNumArgs()) {
+ if (i < callE->getNumArgs() && i < FD->getNumParams()) {
ParmVarDecl *PD = FD->getParamDecl(i);
if (PD->getAttr<CFConsumedAttr>()) {
isConsumed = true;
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index 3057e391d0a8..e316c73fc3cd 100644
--- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
@@ -1,4 +1,4 @@
-//===--- TransUnusedInitDelegate.cpp - Tranformations to ARC mode ---------===//
+//===--- TransUnusedInitDelegate.cpp - Transformations to ARC mode --------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index a07596d0cb0c..4d088e05bfab 100644
--- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
@@ -1,4 +1,4 @@
-//===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===//
+//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index 783db1c8f3aa..2fd0619df9f8 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -10,8 +10,8 @@
#include "Internals.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/DenseSet.h"
#include <map>
using namespace clang;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 805a67d9d188..087219535a18 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -1,4 +1,4 @@
-//===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===//
+//===--- Transforms.cpp - Transformations to ARC mode ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -9,16 +9,17 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include <map>
using namespace clang;
@@ -70,13 +71,22 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
if (E->getOpcode() != BO_Assign)
return false;
+ return isPlusOne(E->getRHS());
+}
+
+bool trans::isPlusOne(const Expr *E) {
+ if (!E)
+ return false;
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
+ E = EWC->getSubExpr();
+
if (const ObjCMessageExpr *
- ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
+ ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
if (ME->getMethodFamily() == OMF_retain)
return true;
if (const CallExpr *
- callE = dyn_cast<CallExpr>(E->getRHS()->IgnoreParenCasts())) {
+ callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
if (const FunctionDecl *FD = callE->getDirectCallee()) {
if (FD->getAttr<CFReturnsRetainedAttr>())
return true;
@@ -84,7 +94,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
if (FD->isGlobal() &&
FD->getIdentifier() &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage &&
+ FD->hasExternalLinkage() &&
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
@@ -97,7 +107,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
}
}
- const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
+ const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
while (implCE && implCE->getCastKind() == CK_BitCast)
implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
@@ -188,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getDeclContext()->isFileContext() &&
- DRE->getDecl()->getLinkage() == ExternalLinkage;
+ DRE->getDecl()->hasExternalLinkage();
if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
@@ -563,6 +573,7 @@ static void traverseAST(MigrationPass &pass) {
}
MigrateCtx.addTraverser(new PropertyRewriteTraverser());
MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
+ MigrateCtx.addTraverser(new ProtectedScopeTraverser());
MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
}
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index 5d4ac9446045..cb7d1535c628 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -1,4 +1,4 @@
-//===-- Transforms.h - Tranformations to ARC mode ---------------*- C++ -*-===//
+//===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,8 +10,8 @@
#ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
#define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -135,6 +135,11 @@ public:
virtual void traverseBody(BodyContext &BodyCtx);
};
+class ProtectedScopeTraverser : public ASTTraverser {
+public:
+ virtual void traverseBody(BodyContext &BodyCtx);
+};
+
// GC transformations
class GCAttrsTraverser : public ASTTraverser {
@@ -156,6 +161,7 @@ bool canApplyWeak(ASTContext &Ctx, QualType type,
bool AllowOnUnknownClass = false);
bool isPlusOneAssign(const BinaryOperator *E);
+bool isPlusOne(const Expr *E);
/// \brief 'Loc' is the end of a statement range. This returns the location
/// immediately after the semicolon following the statement.
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 2d7c9bd7864a..98e825b3bafb 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -19,8 +19,8 @@
#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
@@ -348,6 +348,8 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
bool IsReference = Ty->isReferenceType();
QualType InnerTy
= IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType();
+ if (InnerTy.isNull())
+ InnerTy = Ty;
if (!hasLValuePath()) {
// No lvalue path: just print the offset.
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index a4e17c03e4e3..55033b238c66 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DeclGroup.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
using namespace clang;
bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 74c68ae627ce..7245c0316082 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -12,28 +12,29 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "CXXABI.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Comment.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/TypeLoc.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/ASTMutationListener.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/Mangle.h"
-#include "clang/AST/Comment.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Capacity.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Capacity.h"
-#include "CXXABI.h"
#include <map>
using namespace clang;
@@ -84,6 +85,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return NULL;
}
+ if (const ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ TemplateSpecializationKind TSK = CTSD->getSpecializationKind();
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_Undeclared)
+ return NULL;
+ }
+
if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return NULL;
@@ -364,10 +373,12 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
if (!ID)
return;
// Add redeclared method here.
- for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = ID->known_extensions_begin(),
+ ExtEnd = ID->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
if (ObjCMethodDecl *RedeclaredMethod =
- ClsExtDecl->getMethod(ObjCMethod->getSelector(),
+ Ext->getMethod(ObjCMethod->getSelector(),
ObjCMethod->isInstanceMethod()))
Redeclared.push_back(RedeclaredMethod);
}
@@ -412,15 +423,26 @@ comments::FullComment *ASTContext::getCommentForDecl(
if (!RC) {
if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
SmallVector<const NamedDecl*, 8> Overridden;
- if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D);
+ if (OMD && OMD->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl())
+ if (comments::FullComment *FC = getCommentForDecl(PDecl, PP))
+ return cloneFullComment(FC, D);
+ if (OMD)
addRedeclaredMethods(OMD, Overridden);
getOverriddenMethods(dyn_cast<NamedDecl>(D), Overridden);
- for (unsigned i = 0, e = Overridden.size(); i < e; i++) {
- if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) {
- comments::FullComment *CFC = cloneFullComment(FC, D);
- return CFC;
- }
- }
+ for (unsigned i = 0, e = Overridden.size(); i < e; i++)
+ if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP))
+ return cloneFullComment(FC, D);
+ }
+ else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ // Attach any tag type's documentation to its typedef if latter
+ // does not have one of its own.
+ QualType QT = TD->getUnderlyingType();
+ if (const TagType *TT = QT->getAs<TagType>())
+ if (const Decl *TD = TT->getDecl())
+ if (comments::FullComment *FC = getCommentForDecl(TD, PP))
+ return cloneFullComment(FC, D);
}
return NULL;
}
@@ -571,12 +593,14 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
if (!LangOpts.CPlusPlus) return 0;
- switch (T.getCXXABI()) {
- case CXXABI_ARM:
+ switch (T.getCXXABI().getKind()) {
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
return CreateARMCXXABI(*this);
- case CXXABI_Itanium:
+ case TargetCXXABI::GenericAArch64: // Same as Itanium at this level
+ case TargetCXXABI::GenericItanium:
return CreateItaniumCXXABI(*this);
- case CXXABI_Microsoft:
+ case TargetCXXABI::Microsoft:
return CreateMicrosoftCXXABI(*this);
}
llvm_unreachable("Invalid CXXABI type!");
@@ -630,9 +654,9 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DeclarationNames(*this),
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
- CommentCommandTraits(BumpAlloc),
+ CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
LastSDM(0, 0),
- UniqueBlockByRefTypeID(0)
+ UniqueBlockByRefTypeID(0)
{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
@@ -873,12 +897,26 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
+
+ if (LangOpts.OpenCL) {
+ InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d);
+ InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray);
+ InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer);
+ InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d);
+ InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray);
+ InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d);
+
+ InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler);
+ InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent);
+ }
// Builtin type for __objc_yes and __objc_no
ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ?
SignedCharTy : BoolTy);
ObjCConstantStringType = QualType();
+
+ ObjCSuperType = QualType();
// void * type
VoidPtrTy = getPointerType(VoidTy);
@@ -1411,6 +1449,22 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(0);
Align = Target->getPointerAlign(0);
break;
+ case BuiltinType::OCLSampler:
+ // Samplers are modeled as integers.
+ Width = Target->getIntWidth();
+ Align = Target->getIntAlign();
+ break;
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ // Currently these types are pointers to opaque types.
+ Width = Target->getPointerWidth(0);
+ Align = Target->getPointerAlign(0);
+ break;
}
break;
case Type::ObjCObjectPointer:
@@ -1442,10 +1496,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::MemberPointer: {
const MemberPointerType *MPT = cast<MemberPointerType>(T);
- std::pair<uint64_t, unsigned> PtrDiffInfo =
- getTypeInfo(getPointerDiffType());
- Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT);
- Align = PtrDiffInfo.second;
+ llvm::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
break;
}
case Type::Complex: {
@@ -1548,18 +1599,21 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::Atomic: {
+ // Start with the base type information.
std::pair<uint64_t, unsigned> Info
= getTypeInfo(cast<AtomicType>(T)->getValueType());
Width = Info.first;
Align = Info.second;
- if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() &&
- llvm::isPowerOf2_64(Width)) {
- // We can potentially perform lock-free atomic operations for this
- // type; promote the alignment appropriately.
- // FIXME: We could potentially promote the width here as well...
- // is that worthwhile? (Non-struct atomic types generally have
- // power-of-two size anyway, but structs might not. Requires a bit
- // of implementation work to make sure we zero out the extra bits.)
+
+ // If the size of the type doesn't exceed the platform's max
+ // atomic promotion width, make the size and alignment more
+ // favorable to atomic operations:
+ if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) {
+ // Round the size up to a power of 2.
+ if (!llvm::isPowerOf2_64(Width))
+ Width = llvm::NextPowerOf2(Width);
+
+ // Set the alignment equal to the size.
Align = static_cast<unsigned>(Width);
}
}
@@ -1658,9 +1712,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
// Categories of this Interface.
- for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList();
- CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
- CollectInheritedProtocols(CDeclChain, Protocols);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = OI->visible_categories_begin(),
+ CatEnd = OI->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CollectInheritedProtocols(*Cat, Protocols);
+ }
+
if (ObjCInterfaceDecl *SD = OI->getSuperClass())
while (SD) {
CollectInheritedProtocols(SD, Protocols);
@@ -1690,10 +1748,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
unsigned count = 0;
// Count ivars declared in class extension.
- for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl;
- CDecl = CDecl->getNextClassExtension())
- count += CDecl->ivar_size();
-
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = OI->known_extensions_begin(),
+ ExtEnd = OI->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ count += Ext->ivar_size();
+ }
+
// Count ivar defined in this class's implementation. This
// includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
@@ -1750,12 +1811,16 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCImpls[CatD] = ImplD;
}
-ObjCInterfaceDecl *ASTContext::getObjContainingInterface(NamedDecl *ND) const {
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
+const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
+ const NamedDecl *ND) const {
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
return ID;
- if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
+ if (const ObjCCategoryDecl *CD =
+ dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
return CD->getClassInterface();
- if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
+ if (const ObjCImplDecl *IMD =
+ dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
return IMD->getClassInterface();
return 0;
@@ -1906,8 +1971,10 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ Result = getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2562,16 +2629,25 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(New, 0);
}
+/// \brief Determine whether \p T is canonical as the result type of a function.
+static bool isCanonicalResultType(QualType T) {
+ return T.isCanonical() &&
+ (T.getObjCLifetime() == Qualifiers::OCL_None ||
+ 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,
- const QualType *ArgArray, unsigned NumArgs,
+ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
const FunctionProtoType::ExtProtoInfo &EPI) const {
+ size_t NumArgs = ArgArray.size();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI,
+ *this);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -2580,7 +2656,7 @@ ASTContext::getFunctionType(QualType ResultTy,
// Determine whether the type being created is already canonical or not.
bool isCanonical =
- EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() &&
+ EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) &&
!EPI.HasTrailingReturn;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
@@ -2606,9 +2682,15 @@ ASTContext::getFunctionType(QualType ResultTy,
CanonicalEPI.ExtInfo
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
- Canonical = getFunctionType(getCanonicalType(ResultTy),
- CanonicalArgs.data(), NumArgs,
- CanonicalEPI);
+ // Result types do not have ARC lifetime qualifiers.
+ QualType CanResultTy = getCanonicalType(ResultTy);
+ if (ResultTy.getQualifiers().hasObjCLifetime()) {
+ Qualifiers Qs = CanResultTy.getQualifiers();
+ Qs.removeObjCLifetime();
+ CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
+ }
+
+ Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -2641,7 +2723,7 @@ ASTContext::getFunctionType(QualType ResultTy,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -2877,8 +2959,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
- TemplateSpecializationTypeLoc TL
- = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
+ TemplateSpecializationTypeLoc TL =
+ DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc);
TL.setLAngleLoc(Args.getLAngleLoc());
@@ -3154,7 +3236,7 @@ ASTContext::getDependentTemplateSpecializationType(
}
QualType ASTContext::getPackExpansionType(QualType Pattern,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
llvm::FoldingSetNodeID ID;
PackExpansionType::Profile(ID, Pattern, NumExpansions);
@@ -3528,6 +3610,14 @@ QualType ASTContext::getUnsignedWCharType() const {
return UnsignedIntTy;
}
+QualType ASTContext::getIntPtrType() const {
+ return getFromTargetType(Target->getIntPtrType());
+}
+
+QualType ASTContext::getUIntPtrType() const {
+ return getCorrespondingUnsignedType(getIntPtrType());
+}
+
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
@@ -3993,7 +4083,8 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
uint64_t ElementCount = 1;
do {
ElementCount *= CA->getSize().getZExtValue();
- CA = dyn_cast<ConstantArrayType>(CA->getElementType());
+ CA = dyn_cast_or_null<ConstantArrayType>(
+ CA->getElementType()->getAsArrayTypeUnsafe());
} while (CA);
return ElementCount;
}
@@ -4032,7 +4123,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
- case HalfRank: llvm_unreachable("Half ranks are not valid here");
+ case HalfRank: return HalfTy;
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
@@ -4159,8 +4250,8 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
// At this point, we should have a signed or unsigned integer type.
if (Promotable->isSignedIntegerType())
return IntTy;
- uint64_t PromotableSize = getTypeSize(Promotable);
- uint64_t IntSize = getTypeSize(IntTy);
+ uint64_t PromotableSize = getIntWidth(Promotable);
+ uint64_t IntSize = getIntWidth(IntTy);
assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize);
return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
}
@@ -4273,6 +4364,16 @@ QualType ASTContext::getCFConstantStringType() const {
return getTagDeclType(CFConstantStringTypeDecl);
}
+QualType ASTContext::getObjCSuperType() const {
+ if (ObjCSuperType.isNull()) {
+ RecordDecl *ObjCSuperTypeDecl =
+ CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("objc_super"));
+ TUDecl->addDecl(ObjCSuperTypeDecl);
+ ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl);
+ }
+ return ObjCSuperType;
+}
+
void ASTContext::setCFConstantStringType(QualType T) {
const RecordType *Rec = T->getAs<RecordType>();
assert(Rec && "Invalid CFConstantStringType");
@@ -4361,78 +4462,68 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
return getTagDeclType(BlockDescriptorExtendedType);
}
-bool ASTContext::BlockRequiresCopying(QualType Ty) const {
- if (Ty->isObjCRetainableType())
+/// BlockRequiresCopying - Returns true if byref variable "D" of type "Ty"
+/// requires copy/dispose. Note that this must match the logic
+/// in buildByrefHelpers.
+bool ASTContext::BlockRequiresCopying(QualType Ty,
+ const VarDecl *D) {
+ if (const CXXRecordDecl *record = Ty->getAsCXXRecordDecl()) {
+ const Expr *copyExpr = getBlockVarCopyInits(D);
+ if (!copyExpr && record->hasTrivialDestructor()) return false;
+
return true;
- if (getLangOpts().CPlusPlus) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- return RD->hasConstCopyConstructor();
-
+ }
+
+ if (!Ty->isObjCRetainableType()) return false;
+
+ Qualifiers qs = Ty.getQualifiers();
+
+ // If we have lifetime, that dominates.
+ if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
+ assert(getLangOpts().ObjCAutoRefCount);
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None: llvm_unreachable("impossible");
+
+ // These are just bits as far as the runtime is concerned.
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ // Tell the runtime that this is ARC __weak, called by the
+ // byref routines.
+ case Qualifiers::OCL_Weak:
+ // ARC __strong __block variables need to be retained.
+ case Qualifiers::OCL_Strong:
+ return true;
}
+ llvm_unreachable("fell out of lifetime switch!");
}
- return false;
+ return (Ty->isBlockPointerType() || isObjCNSObjectType(Ty) ||
+ Ty->isObjCObjectPointerType());
}
-QualType
-ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const {
- // type = struct __Block_byref_1_X {
- // void *__isa;
- // struct __Block_byref_1_X *__forwarding;
- // unsigned int __flags;
- // unsigned int __size;
- // void *__copy_helper; // as needed
- // void *__destroy_help // as needed
- // int X;
- // } *
-
- bool HasCopyAndDispose = BlockRequiresCopying(Ty);
-
- // FIXME: Move up
- SmallString<36> Name;
- llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
- ++UniqueBlockByRefTypeID << '_' << DeclName;
- RecordDecl *T;
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str()));
- T->startDefinition();
- QualType Int32Ty = IntTy;
- assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
- QualType FieldTypes[] = {
- getPointerType(VoidPtrTy),
- getPointerType(getTagDeclType(T)),
- Int32Ty,
- Int32Ty,
- getPointerType(VoidPtrTy),
- getPointerType(VoidPtrTy),
- Ty
- };
-
- StringRef FieldNames[] = {
- "__isa",
- "__forwarding",
- "__flags",
- "__size",
- "__copy_helper",
- "__destroy_helper",
- DeclName,
- };
-
- for (size_t i = 0; i < 7; ++i) {
- if (!HasCopyAndDispose && i >=4 && i <= 5)
- continue;
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- SourceLocation(),
- &Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false,
- ICIS_NoInit);
- Field->setAccess(AS_public);
- T->addDecl(Field);
- }
-
- T->completeDefinition();
-
- return getPointerType(getTagDeclType(T));
+bool ASTContext::getByrefLifetime(QualType Ty,
+ Qualifiers::ObjCLifetime &LifeTime,
+ bool &HasByrefExtendedLayout) const {
+
+ if (!getLangOpts().ObjC1 ||
+ getLangOpts().getGC() != LangOptions::NonGC)
+ return false;
+
+ HasByrefExtendedLayout = false;
+ if (Ty->isRecordType()) {
+ HasByrefExtendedLayout = true;
+ LifeTime = Qualifiers::OCL_None;
+ }
+ else if (getLangOpts().ObjCAutoRefCount)
+ LifeTime = Ty.getObjCLifetime();
+ // MRR.
+ else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
+ LifeTime = Qualifiers::OCL_ExplicitNone;
+ else
+ LifeTime = Qualifiers::OCL_None;
+ return true;
}
TypedefDecl *ASTContext::getObjCInstanceTypeDecl() {
@@ -4793,17 +4884,19 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
true /* outermost type */);
}
-static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
- switch (T->getAs<BuiltinType>()->getKind()) {
- default: llvm_unreachable("Unhandled builtin type kind");
+static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
+ BuiltinType::Kind kind) {
+ switch (kind) {
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
case BuiltinType::Char_U:
case BuiltinType::UChar: return 'C';
+ case BuiltinType::Char16:
case BuiltinType::UShort: return 'S';
+ case BuiltinType::Char32:
case BuiltinType::UInt: return 'I';
case BuiltinType::ULong:
- return C->getIntWidth(T) == 32 ? 'L' : 'Q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'L' : 'Q';
case BuiltinType::UInt128: return 'T';
case BuiltinType::ULongLong: return 'Q';
case BuiltinType::Char_S:
@@ -4813,13 +4906,40 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
case BuiltinType::WChar_U:
case BuiltinType::Int: return 'i';
case BuiltinType::Long:
- return C->getIntWidth(T) == 32 ? 'l' : 'q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'l' : 'q';
case BuiltinType::LongLong: return 'q';
case BuiltinType::Int128: return 't';
case BuiltinType::Float: return 'f';
case BuiltinType::Double: return 'd';
case BuiltinType::LongDouble: return 'D';
+ case BuiltinType::NullPtr: return '*'; // like char*
+
+ case BuiltinType::Half:
+ // FIXME: potentially need @encodes for these!
+ return ' ';
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("@encoding ObjC primitive type");
+
+ // OpenCL and placeholder types don't need @encodings.
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(KIND, ID)
+#define PLACEHOLDER_TYPE(KIND, ID) \
+ case BuiltinType::KIND:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("invalid builtin type for @encode");
}
+ llvm_unreachable("invalid BuiltinType::Kind value");
}
static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
@@ -4830,7 +4950,8 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
return 'i';
// The encoding of a fixed enum type matches its fixed underlying type.
- return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType());
+ const BuiltinType *BT = Enum->getIntegerType()->castAs<BuiltinType>();
+ return getObjCEncodingForPrimitiveKind(C, BT->getKind());
}
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
@@ -4858,8 +4979,10 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
if (const EnumType *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
- else
- S += ObjCEncodingForPrimitiveKind(Ctx, T);
+ else {
+ const BuiltinType *BT = T->castAs<BuiltinType>();
+ S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind());
+ }
}
S += llvm::utostr(FD->getBitWidthValue(*Ctx));
}
@@ -4873,33 +4996,52 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool EncodingProperty,
bool StructField,
bool EncodeBlockParameters,
- bool EncodeClassNames) const {
- if (T->getAs<BuiltinType>()) {
+ bool EncodeClassNames,
+ bool EncodePointerToObjCTypedef) const {
+ CanQualType CT = getCanonicalType(T);
+ switch (CT->getTypeClass()) {
+ case Type::Builtin:
+ case Type::Enum:
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
- S += ObjCEncodingForPrimitiveKind(this, T);
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CT))
+ S += getObjCEncodingForPrimitiveKind(this, BT->getKind());
+ else
+ S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
- }
- if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ case Type::Complex: {
+ const ComplexType *CT = T->castAs<ComplexType>();
S += 'j';
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
false);
return;
}
-
- // encoding for pointer or r3eference types.
- QualType PointeeTy;
- if (const PointerType *PT = T->getAs<PointerType>()) {
- if (PT->isObjCSelType()) {
- S += ':';
- return;
- }
- PointeeTy = PT->getPointeeType();
+
+ case Type::Atomic: {
+ const AtomicType *AT = T->castAs<AtomicType>();
+ S += 'A';
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, 0,
+ false, false);
+ return;
}
- else if (const ReferenceType *RT = T->getAs<ReferenceType>())
- PointeeTy = RT->getPointeeType();
- if (!PointeeTy.isNull()) {
+
+ // encoding for pointer or reference types.
+ case Type::Pointer:
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ QualType PointeeTy;
+ if (isa<PointerType>(CT)) {
+ const PointerType *PT = T->castAs<PointerType>();
+ if (PT->isObjCSelType()) {
+ S += ':';
+ return;
+ }
+ PointeeTy = PT->getPointeeType();
+ } else {
+ PointeeTy = T->castAs<ReferenceType>()->getPointeeType();
+ }
+
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -4954,10 +5096,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
NULL);
return;
}
-
- if (const ArrayType *AT =
- // Ignore type qualifiers etc.
- dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray: {
+ const ArrayType *AT = cast<ArrayType>(CT);
+
if (isa<IncompleteArrayType>(AT) && !StructField) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
@@ -4986,13 +5130,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- if (T->getAs<FunctionType>()) {
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
S += '?';
return;
- }
- if (const RecordType *RTy = T->getAs<RecordType>()) {
- RecordDecl *RDecl = RTy->getDecl();
+ case Type::Record: {
+ RecordDecl *RDecl = cast<RecordType>(CT)->getDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
@@ -5000,13 +5144,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ llvm::raw_string_ostream OS(S);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
TemplateArgs.data(),
TemplateArgs.size(),
(*this).getPrintingPolicy());
-
- S += TemplateArgsStr;
}
} else {
S += '?';
@@ -5043,19 +5185,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += RDecl->isUnion() ? ')' : '}';
return;
}
-
- if (const EnumType *ET = T->getAs<EnumType>()) {
- if (FD && FD->isBitField())
- EncodeBitField(this, S, T, FD);
- else
- S += ObjCEncodingForEnumType(this, ET);
- return;
- }
- if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ case Type::BlockPointer: {
+ const BlockPointerType *BT = T->castAs<BlockPointerType>();
S += "@?"; // Unlike a pointer-to-function, which is "^?".
if (EncodeBlockParameters) {
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+ const FunctionType *FT = BT->getPointeeType()->castAs<FunctionType>();
S += '<';
// Block return type
@@ -5089,11 +5224,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- // Ignore protocol qualifiers when mangling at this level.
- if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>())
- T = OT->getBaseType();
+ case Type::ObjCObject:
+ case Type::ObjCInterface: {
+ // Ignore protocol qualifiers when mangling at this level.
+ T = T->castAs<ObjCObjectType>()->getBaseType();
- if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
+ // The assumption seems to be that this assert will succeed
+ // because nested levels will have filtered out 'id' and 'Class'.
+ const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>();
// @encode(class_name)
ObjCInterfaceDecl *OI = OIT->getDecl();
S += '{';
@@ -5107,13 +5245,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (Field->isBitField())
getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field);
else
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD);
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD,
+ false, false, false, false, false,
+ EncodePointerToObjCTypedef);
}
S += '}';
return;
}
- if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *OPT = T->castAs<ObjCObjectPointerType>();
if (OPT->isObjCIdType()) {
S += '@';
return;
@@ -5148,14 +5289,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
QualType PointeeTy = OPT->getPointeeType();
if (!EncodingProperty &&
- isa<TypedefType>(PointeeTy.getTypePtr())) {
+ isa<TypedefType>(PointeeTy.getTypePtr()) &&
+ !EncodePointerToObjCTypedef) {
// Another historical/compatibility reason.
// We encode the underlying type which comes out as
// {...};
S += '^';
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
- NULL);
+ NULL,
+ false, false, false, false, false,
+ /*EncodePointerToObjCTypedef*/true);
return;
}
@@ -5176,18 +5320,29 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
// gcc just blithely ignores member pointers.
- // TODO: maybe there should be a mangling for these
- if (T->getAs<MemberPointerType>())
+ // FIXME: we shoul do better than that. 'M' is available.
+ case Type::MemberPointer:
return;
- if (T->isVectorType()) {
+ case Type::Vector:
+ case Type::ExtVector:
// This matches gcc's encoding, even though technically it is
// insufficient.
// FIXME. We should do a better job than gcc.
return;
+
+#define ABSTRACT_TYPE(KIND, BASE)
+#define TYPE(KIND, BASE)
+#define DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("@encode for dependent type!");
}
-
- llvm_unreachable("@encode for type not implemented!");
+ llvm_unreachable("bad type kind!");
}
void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
@@ -5426,6 +5581,85 @@ static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) {
return VaListTypeDecl;
}
+static TypedefDecl *
+CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
+ RecordDecl *VaListTagDecl;
+ if (Context->getLangOpts().CPlusPlus) {
+ // namespace std { struct __va_list {
+ NamespaceDecl *NS;
+ NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ /*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"));
+ VaListTagDecl->setDeclContext(NS);
+ } else {
+ // struct __va_list
+ VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ &Context->Idents.get("__va_list"));
+ }
+
+ VaListTagDecl->startDefinition();
+
+ const size_t NumFields = 5;
+ QualType FieldTypes[NumFields];
+ const char *FieldNames[NumFields];
+
+ // void *__stack;
+ FieldTypes[0] = Context->getPointerType(Context->VoidTy);
+ FieldNames[0] = "__stack";
+
+ // void *__gr_top;
+ FieldTypes[1] = Context->getPointerType(Context->VoidTy);
+ FieldNames[1] = "__gr_top";
+
+ // void *__vr_top;
+ FieldTypes[2] = Context->getPointerType(Context->VoidTy);
+ FieldNames[2] = "__vr_top";
+
+ // int __gr_offs;
+ FieldTypes[3] = Context->IntTy;
+ FieldNames[3] = "__gr_offs";
+
+ // int __vr_offs;
+ FieldTypes[4] = Context->IntTy;
+ FieldNames[4] = "__vr_offs";
+
+ // Create fields
+ for (unsigned i = 0; i < NumFields; ++i) {
+ FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
+ VaListTagDecl,
+ SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get(FieldNames[i]),
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ ICIS_NoInit);
+ Field->setAccess(AS_public);
+ VaListTagDecl->addDecl(Field);
+ }
+ VaListTagDecl->completeDefinition();
+ QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ 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;
+}
+
static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
@@ -5659,6 +5893,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
return CreateCharPtrBuiltinVaListDecl(Context);
case TargetInfo::VoidPtrBuiltinVaList:
return CreateVoidPtrBuiltinVaListDecl(Context);
+ case TargetInfo::AArch64ABIBuiltinVaList:
+ return CreateAArch64ABIBuiltinVaListDecl(Context);
case TargetInfo::PowerABIBuiltinVaList:
return CreatePowerABIBuiltinVaListDecl(Context);
case TargetInfo::X86_64ABIBuiltinVaList:
@@ -6496,14 +6732,14 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
- // functypes which return are preferred over those that do not.
- if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn())
- allLTypes = false;
- else if (!lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn())
- allRTypes = false;
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
+ if (lbaseInfo.getNoReturn() != NoReturn)
+ allLTypes = false;
+ if (rbaseInfo.getNoReturn() != NoReturn)
+ allRTypes = false;
+
FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn);
if (lproto && rproto) { // two C99 style function prototypes
@@ -6557,7 +6793,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, types.begin(), types.size(), EPI);
+ return getFunctionType(retType, types, EPI);
}
if (lproto) allRTypes = false;
@@ -6594,8 +6830,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, proto->arg_type_begin(),
- proto->getNumArgs(), EPI);
+ return getFunctionType(retType,
+ ArrayRef<QualType>(proto->arg_type_begin(),
+ proto->getNumArgs()),
+ EPI);
}
if (allLTypes) return lhs;
@@ -6603,6 +6841,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return getFunctionNoProtoType(retType, einfo);
}
+/// Given that we have an enum type and a non-enum type, try to merge them.
+static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
+ QualType other, bool isBlockReturnType) {
+ // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
+ // a signed integer type, or an unsigned integer type.
+ // Compatibility is based on the underlying type, not the promotion
+ // type.
+ QualType underlyingType = ET->getDecl()->getIntegerType();
+ if (underlyingType.isNull()) return QualType();
+ if (Context.hasSameType(underlyingType, other))
+ return other;
+
+ // In block return types, we're more permissive and accept any
+ // integral type of the same size.
+ if (isBlockReturnType && other->isIntegerType() &&
+ Context.getTypeSize(underlyingType) == Context.getTypeSize(other))
+ return other;
+
+ return QualType();
+}
+
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer,
bool Unqualified, bool BlockReturnType) {
@@ -6684,19 +6943,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// If the canonical type classes don't match.
if (LHSClass != RHSClass) {
- // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
- // a signed integer type, or an unsigned integer type.
- // Compatibility is based on the underlying type, not the promotion
- // type.
+ // Note that we only have special rules for turning block enum
+ // returns into block int returns, not vice-versa.
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType()))
- return RHS;
+ return mergeEnumWithInteger(*this, ETy, RHS, false);
}
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType()))
- return LHS;
+ return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
}
// allow block pointer type to match an 'id' type.
if (OfBlockPointer && !BlockReturnType) {
@@ -6928,8 +7181,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
QualType ResultType
- = getFunctionType(OldReturnType, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ = getFunctionType(OldReturnType,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
return ResultType;
}
}
@@ -7137,6 +7392,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
case 'H':
Type = Context.getObjCSelType();
break;
+ case 'M':
+ Type = Context.getObjCSuperType();
+ break;
case 'a':
Type = Context.getBuiltinVaListType();
assert(!Type.isNull() && "builtin va list type not initialized!");
@@ -7318,7 +7576,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
EPI.ExtInfo = EI;
EPI.Variadic = Variadic;
- return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI);
+ return getFunctionType(ResType, ArgTypes, EPI);
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
@@ -7383,9 +7641,6 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
TSK = VD->getTemplateSpecializationKind();
Linkage L = VD->getLinkage();
- if (L == ExternalLinkage && getLangOpts().CPlusPlus &&
- VD->getType()->getLinkage() == UniqueExternalLinkage)
- L = UniqueExternalLinkage;
switch (L) {
case NoLinkage:
@@ -7418,7 +7673,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
- } else if (!isa<FunctionDecl>(D))
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // We never need to emit an uninstantiated function template.
+ if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return false;
+ } else
+ return false;
+
+ // If this is a member of a class template, we do not need to emit it.
+ if (D->getDeclContext()->isDependentContext())
return false;
// Weak references don't produce any output by themselves.
@@ -7438,13 +7701,16 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
- // The key function for a class is required.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *RD = MD->getParent();
- if (MD->isOutOfLine() && RD->isDynamicClass()) {
- const CXXMethodDecl *KeyFunc = getKeyFunction(RD);
- if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
+ // The key function for a class is required. This rule only comes
+ // into play when inline functions can be key functions, though.
+ if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isOutOfLine() && RD->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD);
+ if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
+ return true;
+ }
}
}
@@ -7465,27 +7731,20 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly)
return false;
- // Structs that have non-trivial constructors or destructors are required.
+ // Variables that can be needed in other TUs are required.
+ GVALinkage L = GetGVALinkageForVariable(VD);
+ if (L != GVA_Internal && L != GVA_TemplateInstantiation)
+ return true;
- // FIXME: Handle references.
- // FIXME: Be more selective about which constructors we care about.
- if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() &&
- RD->hasTrivialCopyConstructor() &&
- RD->hasTrivialMoveConstructor() &&
- RD->hasTrivialDestructor()))
- return true;
- }
- }
+ // Variables that have destruction with side-effects are required.
+ if (VD->getType().isDestructedType())
+ return true;
- GVALinkage L = GetGVALinkageForVariable(VD);
- if (L == GVA_Internal || L == GVA_TemplateInstantiation) {
- if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this)))
- return false;
- }
+ // Variables that have initialization with side-effects are required.
+ if (VD->getInit() && VD->getInit()->HasSideEffects(*this))
+ return true;
- return true;
+ return false;
}
CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
@@ -7494,7 +7753,8 @@ CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
}
CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C && !LangOpts.MRTD && getTargetInfo().getCXXABI() != CXXABI_Microsoft)
+ if (CC == CC_C && !LangOpts.MRTD &&
+ getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
return CC_Default;
return CC;
}
@@ -7505,11 +7765,13 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
}
MangleContext *ASTContext::createMangleContext() {
- switch (Target->getCXXABI()) {
- case CXXABI_ARM:
- case CXXABI_Itanium:
+ switch (Target->getCXXABI().getKind()) {
+ case TargetCXXABI::GenericAArch64:
+ case TargetCXXABI::GenericItanium:
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
return createItaniumMangleContext(*this, getDiagnostics());
- case CXXABI_Microsoft:
+ case TargetCXXABI::Microsoft:
return createMicrosoftMangleContext(*this, getDiagnostics());
}
llvm_unreachable("Unsupported ABI");
@@ -7534,6 +7796,23 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
}
+void ASTContext::addUnnamedTag(const TagDecl *Tag) {
+ // FIXME: This mangling should be applied to function local classes too
+ if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
+ !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
+ return;
+
+ std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
+ UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
+ UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+}
+
+int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
+ llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
+ UnnamedMangleNumbers.find(Tag);
+ return I != UnnamedMangleNumbers.end() ? I->second : -1;
+}
+
unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
CXXRecordDecl *Lambda = CallOperator->getParent();
return LambdaMangleContexts[Lambda->getDeclContext()]
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 0b9c5249448f..1ed65e476ce3 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -11,12 +11,11 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTDiagnostic.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -232,7 +231,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
QualType ToType, bool PrintTree,
bool PrintFromType, bool ElideType,
- bool ShowColors, std::string &S);
+ bool ShowColors, raw_ostream &OS);
void clang::FormatASTNodeDiagnosticArgument(
DiagnosticsEngine::ArgumentKind Kind,
@@ -248,7 +247,8 @@ void clang::FormatASTNodeDiagnosticArgument(
ArrayRef<intptr_t> QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
- std::string S;
+ size_t OldEnd = Output.size();
+ llvm::raw_svector_ostream OS(Output);
bool NeedQuotes = true;
switch (Kind) {
@@ -262,7 +262,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree,
TDT.PrintFromType, TDT.ElideType,
- TDT.ShowColors, S)) {
+ TDT.ShowColors, OS)) {
NeedQuotes = !TDT.PrintTree;
TDT.TemplateDiffUsed = true;
break;
@@ -273,7 +273,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (TDT.PrintTree)
return;
- // Attempting to do a templete diff on non-templates. Set the variables
+ // 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;
@@ -285,23 +285,23 @@ void clang::FormatASTNodeDiagnosticArgument(
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
- QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
+ QualTypeVals);
NeedQuotes = false;
break;
}
case DiagnosticsEngine::ak_declarationname: {
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- S = N.getAsString();
-
if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
- S = '+' + S;
+ OS << '+';
else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
&& ArgLen==0)
- S = '-' + S;
+ OS << '-';
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
+
+ DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+ N.printName(OS);
break;
}
case DiagnosticsEngine::ak_nameddecl: {
@@ -314,13 +314,12 @@ void clang::FormatASTNodeDiagnosticArgument(
Qualified = false;
}
const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val);
- ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), Qualified);
+ ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified);
break;
}
case DiagnosticsEngine::ak_nestednamespec: {
- llvm::raw_string_ostream OS(S);
- reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.getPrintingPolicy());
+ NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
+ NNS->print(OS, Context.getPrintingPolicy());
NeedQuotes = false;
break;
}
@@ -331,39 +330,39 @@ void clang::FormatASTNodeDiagnosticArgument(
if (DC->isTranslationUnit()) {
// FIXME: Get these strings from some localized place
if (Context.getLangOpts().CPlusPlus)
- S = "the global namespace";
+ OS << "the global namespace";
else
- S = "the global scope";
+ OS << "the global scope";
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- S = ConvertTypeToDiagnosticString(Context,
- Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs, QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context,
+ Context.getTypeDeclType(Type),
+ PrevArgs, NumPrevArgs,
+ QualTypeVals);
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(DC);
if (isa<NamespaceDecl>(ND))
- S += "namespace ";
+ OS << "namespace ";
else if (isa<ObjCMethodDecl>(ND))
- S += "method ";
+ OS << "method ";
else if (isa<FunctionDecl>(ND))
- S += "function ";
-
- S += "'";
- ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), true);
- S += "'";
+ OS << "function ";
+
+ OS << '\'';
+ ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true);
+ OS << '\'';
}
NeedQuotes = false;
break;
}
}
-
- if (NeedQuotes)
- Output.push_back('\'');
-
- Output.append(S.begin(), S.end());
-
- if (NeedQuotes)
+
+ OS.flush();
+
+ if (NeedQuotes) {
+ Output.insert(Output.begin()+OldEnd, '\'');
Output.push_back('\'');
+ }
}
/// TemplateDiff - A class that constructs a pretty string for a pair of
@@ -396,21 +395,39 @@ class TemplateDiff {
/// will this type be outputed.
QualType ToType;
- /// Str - Storage for the output stream.
- llvm::SmallString<128> Str;
-
/// OS - The stream used to construct the output strings.
- llvm::raw_svector_ostream OS;
+ raw_ostream &OS;
/// IsBold - Keeps track of the bold formatting for the output string.
bool IsBold;
/// DiffTree - A tree representation the differences between two types.
class DiffTree {
+ public:
+ /// DiffKind - The difference in a DiffNode and which fields are used.
+ enum DiffKind {
+ /// Incomplete or invalid node.
+ Invalid,
+ /// Another level of templates, uses TemplateDecl and Qualifiers
+ Template,
+ /// Type difference, uses QualType
+ Type,
+ /// Expression difference, uses Expr
+ Expression,
+ /// Template argument difference, uses TemplateDecl
+ TemplateTemplate,
+ /// Integer difference, uses APSInt and Expr
+ Integer,
+ /// Declaration difference, uses ValueDecl
+ Declaration
+ };
+ private:
/// DiffNode - The root node stores the original type. Each child node
/// stores template arguments of their parents. For templated types, the
/// template decl is also stored.
struct DiffNode {
+ DiffKind Kind;
+
/// NextNode - The index of the next sibling node or 0.
unsigned NextNode;
@@ -439,6 +456,9 @@ class TemplateDiff {
/// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
bool IsValidFromInt, IsValidToInt;
+ /// FromValueDecl, ToValueDecl - Whether the argument is a decl.
+ ValueDecl *FromValueDecl, *ToValueDecl;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -446,13 +466,14 @@ class TemplateDiff {
bool Same;
DiffNode(unsigned ParentNode = 0)
- : NextNode(0), ChildNode(0), ParentNode(ParentNode),
+ : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
- FromDefault(false), ToDefault(false), Same(false) { }
+ IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
+ ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { }
};
/// FlatTree - A flattened tree used to store the DiffNodes.
- llvm::SmallVector<DiffNode, 16> FlatTree;
+ SmallVector<DiffNode, 16> FlatTree;
/// CurrentNode - The index of the current node being used.
unsigned CurrentNode;
@@ -504,6 +525,12 @@ class TemplateDiff {
FlatTree[CurrentNode].ToQual = ToQual;
}
+ /// SetNode - Set FromValueDecl and ToValueDecl of the current node.
+ void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) {
+ FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
+ FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
+ }
+
/// SetSame - Sets the same flag of the current node.
void SetSame(bool Same) {
FlatTree[CurrentNode].Same = Same;
@@ -515,6 +542,11 @@ class TemplateDiff {
FlatTree[CurrentNode].ToDefault = ToDefault;
}
+ /// SetKind - Sets the current node's type.
+ void SetKind(DiffKind Kind) {
+ FlatTree[CurrentNode].Kind = Kind;
+ }
+
/// Up - Changes the node to the parent of the current node.
void Up() {
CurrentNode = FlatTree[CurrentNode].ParentNode;
@@ -554,39 +586,6 @@ class TemplateDiff {
ReadNode = FlatTree[ReadNode].ParentNode;
}
- /// NodeIsTemplate - Returns true if a template decl is set, and types are
- /// set.
- bool NodeIsTemplate() {
- return (FlatTree[ReadNode].FromTD &&
- !FlatTree[ReadNode].ToType.isNull()) ||
- (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull());
- }
-
- /// NodeIsQualType - Returns true if a Qualtype is set.
- bool NodeIsQualType() {
- return !FlatTree[ReadNode].FromType.isNull() ||
- !FlatTree[ReadNode].ToType.isNull();
- }
-
- /// NodeIsExpr - Returns true if an expr is set.
- bool NodeIsExpr() {
- return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr;
- }
-
- /// NodeIsTemplateTemplate - Returns true if the argument is a template
- /// template type.
- bool NodeIsTemplateTemplate() {
- return FlatTree[ReadNode].FromType.isNull() &&
- FlatTree[ReadNode].ToType.isNull() &&
- (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD);
- }
-
- /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's.
- bool NodeIsAPSInt() {
- return FlatTree[ReadNode].IsValidFromInt ||
- FlatTree[ReadNode].IsValidToInt;
- }
-
/// GetNode - Gets the FromType and ToType.
void GetNode(QualType &FromType, QualType &ToType) {
FromType = FlatTree[ReadNode].FromType;
@@ -620,6 +619,12 @@ class TemplateDiff {
ToQual = FlatTree[ReadNode].ToQual;
}
+ /// GetNode - Gets the FromValueDecl and ToValueDecl.
+ void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) {
+ FromValueDecl = FlatTree[ReadNode].FromValueDecl;
+ ToValueDecl = FlatTree[ReadNode].ToValueDecl;
+ }
+
/// NodeIsSame - Returns true the arguments are the same.
bool NodeIsSame() {
return FlatTree[ReadNode].Same;
@@ -662,9 +667,12 @@ class TemplateDiff {
/// Empty - Returns true if the tree has no information.
bool Empty() {
- return !FlatTree[0].FromTD && !FlatTree[0].ToTD &&
- !FlatTree[0].FromExpr && !FlatTree[0].ToExpr &&
- FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull();
+ return GetKind() == Invalid;
+ }
+
+ /// GetKind - Returns the current node's type.
+ DiffKind GetKind() {
+ return FlatTree[ReadNode].Kind;
}
};
@@ -681,6 +689,10 @@ class TemplateDiff {
/// traverse over.
const TemplateSpecializationType *TST;
+ /// DesugarTST - desugared template specialization used to extract
+ /// default argument information
+ const TemplateSpecializationType *DesugarTST;
+
/// Index - the index of the template argument in TST.
unsigned Index;
@@ -693,8 +705,10 @@ class TemplateDiff {
/// TSTiterator - Constructs an iterator and sets it to the first template
/// argument.
- TSTiterator(const TemplateSpecializationType *TST)
- : TST(TST), Index(0), CurrentTA(0), EndTA(0) {
+ TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
+ : TST(TST),
+ DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())),
+ Index(0), CurrentTA(0), EndTA(0) {
if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done.
@@ -715,12 +729,17 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const {
- return Index == TST->getNumArgs();
+ return Index >= TST->getNumArgs();
}
/// &operator++ - Increment the iterator to the next template argument.
TSTiterator &operator++() {
- assert(!isEnd() && "Iterator incremented past end of arguments.");
+ // After the end, Index should be the default argument position in
+ // DesugarTST, if it exists.
+ if (isEnd()) {
+ ++Index;
+ return *this;
+ }
// If in a parameter pack, advance in the parameter pack.
if (CurrentTA != EndTA) {
@@ -761,6 +780,11 @@ class TemplateDiff {
pointer operator->() const {
return &operator*();
}
+
+ /// getDesugar - Returns the deduced template argument from DesguarTST
+ reference getDesugar() const {
+ return DesugarTST->getArg(Index);
+ }
};
// These functions build up the template diff tree, including functions to
@@ -787,7 +811,7 @@ class TemplateDiff {
TemplateName(CTSD->getSpecializedTemplate()),
CTSD->getTemplateArgs().data(),
CTSD->getTemplateArgs().size(),
- Ty.getCanonicalType());
+ Ty.getLocalUnqualifiedType().getCanonicalType());
return Ty->getAs<TemplateSpecializationType>();
}
@@ -800,7 +824,7 @@ class TemplateDiff {
TemplateParameterList *Params =
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
unsigned TotalArgs = 0;
- for (TSTiterator FromIter(FromTST), ToIter(ToTST);
+ for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
Tree.AddNode();
@@ -814,11 +838,12 @@ class TemplateDiff {
if (TemplateTypeParmDecl *DefaultTTPD =
dyn_cast<TemplateTypeParmDecl>(ParamND)) {
QualType FromType, ToType;
- GetType(FromIter, DefaultTTPD, FromType);
- GetType(ToIter, DefaultTTPD, ToType);
+ FromType = GetType(FromIter, DefaultTTPD);
+ ToType = GetType(ToIter, DefaultTTPD);
Tree.SetNode(FromType, ToType);
Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
ToIter.isEnd() && !ToType.isNull());
+ Tree.SetKind(DiffTree::Type);
if (!FromType.isNull() && !ToType.isNull()) {
if (Context.hasSameType(FromType, ToType)) {
Tree.SetSame(true);
@@ -837,6 +862,7 @@ class TemplateDiff {
Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
ToArgTST->getTemplateName().getAsTemplateDecl());
Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
DiffTemplate(FromArgTST, ToArgTST);
}
}
@@ -846,41 +872,83 @@ class TemplateDiff {
// Handle Expressions
if (NonTypeTemplateParmDecl *DefaultNTTPD =
dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
- Expr *FromExpr, *ToExpr;
+ Expr *FromExpr = 0, *ToExpr = 0;
llvm::APSInt FromInt, ToInt;
+ ValueDecl *FromValueDecl = 0, *ToValueDecl = 0;
+ unsigned ParamWidth = 128; // Safe default
+ if (DefaultNTTPD->getType()->isIntegralOrEnumerationType())
+ ParamWidth = Context.getIntWidth(DefaultNTTPD->getType());
bool HasFromInt = !FromIter.isEnd() &&
FromIter->getKind() == TemplateArgument::Integral;
bool HasToInt = !ToIter.isEnd() &&
ToIter->getKind() == TemplateArgument::Integral;
- //bool IsValidFromInt = false, IsValidToInt = false;
+ bool HasFromValueDecl =
+ !FromIter.isEnd() &&
+ FromIter->getKind() == TemplateArgument::Declaration;
+ bool HasToValueDecl =
+ !ToIter.isEnd() &&
+ ToIter->getKind() == TemplateArgument::Declaration;
+
+ assert(((!HasFromInt && !HasToInt) ||
+ (!HasFromValueDecl && !HasToValueDecl)) &&
+ "Template argument cannot be both integer and declaration");
+
if (HasFromInt)
FromInt = FromIter->getAsIntegral();
+ else if (HasFromValueDecl)
+ FromValueDecl = FromIter->getAsDecl();
else
- GetExpr(FromIter, DefaultNTTPD, FromExpr);
+ FromExpr = GetExpr(FromIter, DefaultNTTPD);
if (HasToInt)
ToInt = ToIter->getAsIntegral();
+ else if (HasToValueDecl)
+ ToValueDecl = ToIter->getAsDecl();
else
- GetExpr(ToIter, DefaultNTTPD, ToExpr);
+ ToExpr = GetExpr(ToIter, DefaultNTTPD);
- if (!HasFromInt && !HasToInt) {
+ if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
Tree.SetNode(FromExpr, ToExpr);
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
Tree.SetDefault(FromIter.isEnd() && FromExpr,
ToIter.isEnd() && ToExpr);
- } else {
+ if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) {
+ if (FromExpr)
+ FromInt = GetInt(FromIter, FromExpr);
+ if (ToExpr)
+ ToInt = GetInt(ToIter, ToExpr);
+ Tree.SetNode(FromInt, ToInt, FromExpr, ToExpr);
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr));
+ Tree.SetKind(DiffTree::Expression);
+ }
+ } else if (HasFromInt || HasToInt) {
if (!HasFromInt && FromExpr) {
- FromInt = FromExpr->EvaluateKnownConstInt(Context);
+ FromInt = GetInt(FromIter, FromExpr);
HasFromInt = true;
}
if (!HasToInt && ToExpr) {
- ToInt = ToExpr->EvaluateKnownConstInt(Context);
+ ToInt = GetInt(ToIter, ToExpr);
HasToInt = true;
}
Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt));
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
Tree.SetDefault(FromIter.isEnd() && HasFromInt,
ToIter.isEnd() && HasToInt);
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ if (!HasFromValueDecl && FromExpr)
+ FromValueDecl = GetValueDecl(FromIter, FromExpr);
+ if (!HasToValueDecl && ToExpr)
+ ToValueDecl = GetValueDecl(ToIter, ToExpr);
+ Tree.SetNode(FromValueDecl, ToValueDecl);
+ Tree.SetSame(FromValueDecl && ToValueDecl &&
+ FromValueDecl->getCanonicalDecl() ==
+ ToValueDecl->getCanonicalDecl());
+ Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
+ ToIter.isEnd() && ToValueDecl);
+ Tree.SetKind(DiffTree::Declaration);
}
}
@@ -888,15 +956,17 @@ class TemplateDiff {
if (TemplateTemplateParmDecl *DefaultTTPD =
dyn_cast<TemplateTemplateParmDecl>(ParamND)) {
TemplateDecl *FromDecl, *ToDecl;
- GetTemplateDecl(FromIter, DefaultTTPD, FromDecl);
- GetTemplateDecl(ToIter, DefaultTTPD, ToDecl);
+ FromDecl = GetTemplateDecl(FromIter, DefaultTTPD);
+ ToDecl = GetTemplateDecl(ToIter, DefaultTTPD);
Tree.SetNode(FromDecl, ToDecl);
- Tree.SetSame(FromDecl && ToDecl &&
- FromDecl->getIdentifier() == ToDecl->getIdentifier());
+ Tree.SetSame(
+ FromDecl && ToDecl &&
+ FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
+ Tree.SetKind(DiffTree::TemplateTemplate);
}
- if (!FromIter.isEnd()) ++FromIter;
- if (!ToIter.isEnd()) ++ToIter;
+ ++FromIter;
+ ++ToIter;
Tree.Up();
}
}
@@ -917,8 +987,8 @@ class TemplateDiff {
/// even if the template arguments are not.
static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
- return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
- ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier();
+ return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() ==
+ ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl();
}
/// hasSameTemplate - Returns true if both types are specialized from the
@@ -962,22 +1032,21 @@ class TemplateDiff {
/// GetType - Retrieves the template type arguments, including default
/// arguments.
- void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD,
- QualType &ArgType) {
- ArgType = QualType();
+ QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
if (!Iter.isEnd())
- ArgType = Iter->getAsType();
- else if (!isVariadic)
- ArgType = DefaultTTPD->getDefaultArgument();
+ return Iter->getAsType();
+ if (!isVariadic)
+ return DefaultTTPD->getDefaultArgument();
+
+ return QualType();
}
/// GetExpr - Retrieves the template expression argument, including default
/// arguments.
- void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD,
- Expr *&ArgExpr) {
- ArgExpr = 0;
+ Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) {
+ Expr *ArgExpr = 0;
bool isVariadic = DefaultNTTPD->isParameterPack();
if (!Iter.isEnd())
@@ -989,14 +1058,50 @@ class TemplateDiff {
while (SubstNonTypeTemplateParmExpr *SNTTPE =
dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr))
ArgExpr = SNTTPE->getReplacement();
+
+ return ArgExpr;
+ }
+
+ /// GetInt - Retrieves the template integer argument, including evaluating
+ /// default arguments.
+ llvm::APInt GetInt(const TSTiterator &Iter, Expr *ArgExpr) {
+ // Default, value-depenedent expressions require fetching
+ // from the desugared TemplateArgument
+ if (Iter.isEnd() && ArgExpr->isValueDependent())
+ switch (Iter.getDesugar().getKind()) {
+ case TemplateArgument::Integral:
+ return Iter.getDesugar().getAsIntegral();
+ case TemplateArgument::Expression:
+ ArgExpr = Iter.getDesugar().getAsExpr();
+ return ArgExpr->EvaluateKnownConstInt(Context);
+ default:
+ assert(0 && "Unexpected template argument kind");
+ }
+ return ArgExpr->EvaluateKnownConstInt(Context);
+ }
+
+ /// GetValueDecl - Retrieves the template integer argument, including
+ /// default expression argument.
+ ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
+ // Default, value-depenedent expressions require fetching
+ // from the desugared TemplateArgument
+ if (Iter.isEnd() && ArgExpr->isValueDependent())
+ switch (Iter.getDesugar().getKind()) {
+ case TemplateArgument::Declaration:
+ return Iter.getDesugar().getAsDecl();
+ case TemplateArgument::Expression:
+ ArgExpr = Iter.getDesugar().getAsExpr();
+ return cast<DeclRefExpr>(ArgExpr)->getDecl();
+ default:
+ assert(0 && "Unexpected template argument kind");
+ }
+ return cast<DeclRefExpr>(ArgExpr)->getDecl();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
- void GetTemplateDecl(const TSTiterator &Iter,
- TemplateTemplateParmDecl *DefaultTTPD,
- TemplateDecl *&ArgDecl) {
- ArgDecl = 0;
+ TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
+ TemplateTemplateParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
@@ -1005,13 +1110,25 @@ class TemplateDiff {
DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
if (!Iter.isEnd())
- ArgDecl = Iter->getAsTemplate().getAsTemplateDecl();
- else if (!isVariadic)
- ArgDecl = DefaultTD;
+ return Iter->getAsTemplate().getAsTemplateDecl();
+ if (!isVariadic)
+ return DefaultTD;
+
+ return 0;
+ }
+
+ /// IsSameConvertedInt - Returns true if both integers are equal when
+ /// converted to an integer type with the given width.
+ static bool IsSameConvertedInt(unsigned Width, const llvm::APSInt &X,
+ const llvm::APSInt &Y) {
+ llvm::APInt ConvertedX = X.extOrTrunc(Width);
+ llvm::APInt ConvertedY = Y.extOrTrunc(Width);
+ return ConvertedX == ConvertedY;
}
/// IsEqualExpr - Returns true if the expressions evaluate to the same value.
- static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {
+ static bool IsEqualExpr(ASTContext &Context, unsigned ParamWidth,
+ Expr *FromExpr, Expr *ToExpr) {
if (FromExpr == ToExpr)
return true;
@@ -1033,7 +1150,7 @@ class TemplateDiff {
Expr::EvalResult FromResult, ToResult;
if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||
!ToExpr->EvaluateAsRValue(ToResult, Context))
- assert(0 && "Template arguments must be known at compile time.");
+ return false;
APValue &FromVal = FromResult.Val;
APValue &ToVal = ToResult.Val;
@@ -1042,7 +1159,7 @@ class TemplateDiff {
switch (FromVal.getKind()) {
case APValue::Int:
- return FromVal.getInt() == ToVal.getInt();
+ return IsSameConvertedInt(ParamWidth, FromVal.getInt(), ToVal.getInt());
case APValue::LValue: {
APValue::LValueBase FromBase = FromVal.getLValueBase();
APValue::LValueBase ToBase = ToVal.getLValueBase();
@@ -1068,81 +1185,97 @@ class TemplateDiff {
void TreeToString(int Indent = 1) {
if (PrintTree) {
OS << '\n';
- for (int i = 0; i < Indent; ++i)
- OS << " ";
+ OS.indent(2 * Indent);
++Indent;
}
// Handle cases where the difference is not templates with different
// arguments.
- if (!Tree.NodeIsTemplate()) {
- if (Tree.NodeIsQualType()) {
+ switch (Tree.GetKind()) {
+ case DiffTree::Invalid:
+ llvm_unreachable("Template diffing failed with bad DiffNode");
+ case DiffTree::Type: {
QualType FromType, ToType;
Tree.GetNode(FromType, ToType);
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
- if (Tree.NodeIsExpr()) {
+ case DiffTree::Expression: {
Expr *FromExpr, *ToExpr;
Tree.GetNode(FromExpr, ToExpr);
PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
- if (Tree.NodeIsTemplateTemplate()) {
+ case DiffTree::TemplateTemplate: {
TemplateDecl *FromTD, *ToTD;
Tree.GetNode(FromTD, ToTD);
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
Tree.ToDefault(), Tree.NodeIsSame());
return;
}
-
- if (Tree.NodeIsAPSInt()) {
+ case DiffTree::Integer: {
llvm::APSInt FromInt, ToInt;
+ Expr *FromExpr, *ToExpr;
bool IsValidFromInt, IsValidToInt;
+ Tree.GetNode(FromExpr, ToExpr);
Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
- Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
+ Tree.NodeIsSame());
return;
}
- llvm_unreachable("Unable to deduce template difference.");
- }
-
- // Node is root of template. Recurse on children.
- TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
-
- assert(Tree.HasChildren() && "Template difference not found in diff tree.");
-
- Qualifiers FromQual, ToQual;
- Tree.GetNode(FromQual, ToQual);
- PrintQualifiers(FromQual, ToQual);
+ case DiffTree::Declaration: {
+ ValueDecl *FromValueDecl, *ToValueDecl;
+ Tree.GetNode(FromValueDecl, ToValueDecl);
+ PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(),
+ Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
+ case DiffTree::Template: {
+ // Node is root of template. Recurse on children.
+ TemplateDecl *FromTD, *ToTD;
+ Tree.GetNode(FromTD, ToTD);
- OS << FromTD->getNameAsString() << '<';
- Tree.MoveToChild();
- unsigned NumElideArgs = 0;
- do {
- if (ElideType) {
- if (Tree.NodeIsSame()) {
- ++NumElideArgs;
- continue;
+ if (!Tree.HasChildren()) {
+ // If we're dealing with a template specialization with zero
+ // arguments, there are no children; special-case this.
+ OS << FromTD->getNameAsString() << "<>";
+ return;
}
- if (NumElideArgs > 0) {
+
+ Qualifiers FromQual, ToQual;
+ Tree.GetNode(FromQual, ToQual);
+ PrintQualifiers(FromQual, ToQual);
+
+ OS << FromTD->getNameAsString() << '<';
+ Tree.MoveToChild();
+ unsigned NumElideArgs = 0;
+ do {
+ if (ElideType) {
+ if (Tree.NodeIsSame()) {
+ ++NumElideArgs;
+ continue;
+ }
+ if (NumElideArgs > 0) {
+ PrintElideArgs(NumElideArgs, Indent);
+ NumElideArgs = 0;
+ OS << ", ";
+ }
+ }
+ TreeToString(Indent);
+ if (Tree.HasNextSibling())
+ OS << ", ";
+ } while (Tree.AdvanceSibling());
+ if (NumElideArgs > 0)
PrintElideArgs(NumElideArgs, Indent);
- NumElideArgs = 0;
- OS << ", ";
- }
+
+ Tree.Parent();
+ OS << ">";
+ return;
}
- TreeToString(Indent);
- if (Tree.HasNextSibling())
- OS << ", ";
- } while (Tree.AdvanceSibling());
- if (NumElideArgs > 0)
- PrintElideArgs(NumElideArgs, Indent);
-
- Tree.Parent();
- OS << ">";
+ }
}
// To signal to the text printer that a certain text needs to be bolded,
@@ -1260,21 +1393,29 @@ class TemplateDiff {
void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD,
bool FromDefault, bool ToDefault, bool Same) {
assert((FromTD || ToTD) && "Only one template argument may be missing.");
+
+ std::string FromName = FromTD ? FromTD->getName() : "(no argument)";
+ std::string ToName = ToTD ? ToTD->getName() : "(no argument)";
+ if (FromTD && ToTD && FromName == ToName) {
+ FromName = FromTD->getQualifiedNameAsString();
+ ToName = ToTD->getQualifiedNameAsString();
+ }
+
if (Same) {
OS << "template " << FromTD->getNameAsString();
} else if (!PrintTree) {
OS << (FromDefault ? "(default) template " : "template ");
Bold();
- OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");
+ OS << FromName;
Unbold();
} else {
OS << (FromDefault ? "[(default) template " : "[template ");
Bold();
- OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");
+ OS << FromName;
Unbold();
OS << " != " << (ToDefault ? "(default) template " : "template ");
Bold();
- OS << (ToTD ? ToTD->getNameAsString() : "(no argument)");
+ OS << ToName;
Unbold();
OS << ']';
}
@@ -1283,8 +1424,8 @@ class TemplateDiff {
/// PrintAPSInt - Handles printing of integral arguments, highlighting
/// argument differences.
void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt, bool FromDefault,
- bool ToDefault, bool Same) {
+ bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr,
+ Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) {
assert((IsValidFromInt || IsValidToInt) &&
"Only one integral argument may be missing.");
@@ -1292,20 +1433,74 @@ class TemplateDiff {
OS << FromInt.toString(10);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ } else {
+ OS << (FromDefault ? "[(default) " : "[");
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ OS << " != " << (ToDefault ? "(default) " : "");
+ PrintAPSInt(ToInt, ToExpr, IsValidToInt);
+ OS << ']';
+ }
+ }
+
+ /// PrintAPSInt - If valid, print the APSInt. If the expression is
+ /// gives more information, print it too.
+ void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) {
+ Bold();
+ if (Valid) {
+ if (HasExtraInfo(E)) {
+ PrintExpr(E);
+ Unbold();
+ OS << " aka ";
+ Bold();
+ }
+ OS << Val.toString(10);
+ } else {
+ OS << "(no argument)";
+ }
+ Unbold();
+ }
+
+ /// HasExtraInfo - Returns true if E is not an integer literal or the
+ /// negation of an integer literal
+ bool HasExtraInfo(Expr *E) {
+ if (!E) return false;
+ if (isa<IntegerLiteral>(E)) return false;
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Minus)
+ if (isa<IntegerLiteral>(UO->getSubExpr()))
+ return false;
+
+ return true;
+ }
+
+ /// PrintDecl - Handles printing of Decl arguments, highlighting
+ /// argument differences.
+ void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromDefault, bool ToDefault, bool Same) {
+ assert((FromValueDecl || ToValueDecl) &&
+ "Only one Decl argument may be NULL");
+
+ if (Same) {
+ OS << FromValueDecl->getName();
+ } else if (!PrintTree) {
+ OS << (FromDefault ? "(default) " : "");
Bold();
- OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)");
+ OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
Unbold();
OS << ']';
}
+
}
// Prints the appropriate placeholder for elided template arguments.
@@ -1386,9 +1581,9 @@ class TemplateDiff {
public:
- TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,
- bool PrintTree, bool PrintFromType, bool ElideType,
- bool ShowColor)
+ TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType,
+ QualType ToType, bool PrintTree, bool PrintFromType,
+ bool ElideType, bool ShowColor)
: Context(Context),
Policy(Context.getLangOpts()),
ElideType(ElideType),
@@ -1397,7 +1592,7 @@ public:
// When printing a single type, the FromType is the one printed.
FromType(PrintFromType ? FromType : ToType),
ToType(PrintFromType ? ToType : FromType),
- OS(Str),
+ OS(OS),
IsBold(false) {
}
@@ -1424,6 +1619,7 @@ public:
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
Tree.SetNode(FromType, ToType);
Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
// Same base template, but different arguments.
Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
@@ -1432,17 +1628,16 @@ public:
DiffTemplate(FromOrigTST, ToOrigTST);
}
- /// MakeString - When the two types given are templated types with the same
+ /// Emit - When the two types given are templated types with the same
/// base template, a string representation of the type difference will be
- /// loaded into S and return true. Otherwise, return false.
- bool MakeString(std::string &S) {
+ /// emitted to the stream and return true. Otherwise, return false.
+ bool Emit() {
Tree.StartTraverse();
if (Tree.Empty())
return false;
TreeToString();
assert(!IsBold && "Bold is applied to end of string.");
- S = OS.str();
return true;
}
}; // end class TemplateDiff
@@ -1454,11 +1649,11 @@ public:
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
QualType ToType, bool PrintTree,
bool PrintFromType, bool ElideType,
- bool ShowColors, std::string &S) {
+ bool ShowColors, raw_ostream &OS) {
if (PrintTree)
PrintFromType = true;
- TemplateDiff TD(Context, FromType, ToType, PrintTree, PrintFromType,
+ TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType,
ElideType, ShowColors);
TD.DiffTemplate();
- return TD.MakeString(S);
+ return TD.Emit();
}
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
new file mode 100644
index 000000000000..b1d174b855eb
--- /dev/null
+++ b/lib/AST/ASTDumper.cpp
@@ -0,0 +1,1996 @@
+//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AST dump methods, which dump out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace clang::comments;
+
+//===----------------------------------------------------------------------===//
+// ASTDumper Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ // Colors used for various parts of the AST dump
+
+ struct TerminalColor {
+ raw_ostream::Colors Color;
+ bool Bold;
+ };
+
+ // Decl kind names (VarDecl, FunctionDecl, etc)
+ static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true };
+ // Attr names (CleanupAttr, GuardedByAttr, etc)
+ static const TerminalColor AttrColor = { raw_ostream::BLUE, true };
+ // Statement names (DeclStmt, ImplicitCastExpr, etc)
+ static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true };
+ // Comment names (FullComment, ParagraphComment, TextComment, etc)
+ static const TerminalColor CommentColor = { raw_ostream::YELLOW, true };
+
+ // Type names (int, float, etc, plus user defined types)
+ static const TerminalColor TypeColor = { raw_ostream::GREEN, false };
+
+ // Pointer address
+ static const TerminalColor AddressColor = { raw_ostream::YELLOW, false };
+ // Source locations
+ static const TerminalColor LocationColor = { raw_ostream::YELLOW, false };
+
+ // lvalue/xvalue
+ static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false };
+ // bitfield/objcproperty/objcsubscript/vectorcomponent
+ static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false };
+
+ // Null statements
+ static const TerminalColor NullColor = { raw_ostream::BLUE, false };
+
+ // CastKind from CastExpr's
+ static const TerminalColor CastColor = { raw_ostream::RED, false };
+
+ // Value of the statement
+ static const TerminalColor ValueColor = { raw_ostream::CYAN, true };
+ // Decl names
+ static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true };
+
+ // Indents ( `, -. | )
+ static const TerminalColor IndentColor = { raw_ostream::BLUE, false };
+
+ class ASTDumper
+ : public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>,
+ public ConstCommentVisitor<ASTDumper> {
+ raw_ostream &OS;
+ const CommandTraits *Traits;
+ const SourceManager *SM;
+ bool IsFirstLine;
+
+ // Indicates whether more child are expected at the current tree depth
+ enum IndentType { IT_Child, IT_LastChild };
+
+ /// Indents[i] indicates if another child exists at level i.
+ /// Used by Indent() to print the tree structure.
+ llvm::SmallVector<IndentType, 32> Indents;
+
+ /// Indicates that more children will be needed at this indent level.
+ /// If true, prevents lastChild() from marking the node as the last child.
+ /// This is used when there are multiple collections of children to be
+ /// dumped as well as during conditional node dumping.
+ bool MoreChildren;
+
+ /// Keep track of the last location we print out so that we can
+ /// print out deltas from then on out.
+ const char *LastLocFilename;
+ unsigned LastLocLine;
+
+ /// The \c FullComment parent of the comment being dumped.
+ const FullComment *FC;
+
+ bool ShowColors;
+
+ class IndentScope {
+ ASTDumper &Dumper;
+ // Preserve the Dumper's MoreChildren value from the previous IndentScope
+ bool MoreChildren;
+ public:
+ IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
+ MoreChildren = Dumper.hasMoreChildren();
+ Dumper.setMoreChildren(false);
+ Dumper.indent();
+ }
+ ~IndentScope() {
+ Dumper.setMoreChildren(MoreChildren);
+ Dumper.unindent();
+ }
+ };
+
+ class ColorScope {
+ ASTDumper &Dumper;
+ public:
+ ColorScope(ASTDumper &Dumper, TerminalColor Color)
+ : Dumper(Dumper) {
+ if (Dumper.ShowColors)
+ Dumper.OS.changeColor(Color.Color, Color.Bold);
+ }
+ ~ColorScope() {
+ if (Dumper.ShowColors)
+ Dumper.OS.resetColor();
+ }
+ };
+
+ 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),
+ ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
+
+ ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM, bool ShowColors)
+ : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ LastLocFilename(""), LastLocLine(~0U),
+ ShowColors(ShowColors) { }
+
+ ~ASTDumper() {
+ OS << "\n";
+ }
+
+ void dumpDecl(const Decl *D);
+ void dumpStmt(const Stmt *S);
+ void dumpFullComment(const FullComment *C);
+
+ // Formatting
+ void indent();
+ void unindent();
+ void lastChild();
+ bool hasMoreChildren();
+ void setMoreChildren(bool Value);
+
+ // Utilities
+ void dumpPointer(const void *Ptr);
+ void dumpSourceRange(SourceRange R);
+ void dumpLocation(SourceLocation Loc);
+ void dumpBareType(QualType T);
+ void dumpType(QualType T);
+ void dumpBareDeclRef(const Decl *Node);
+ void dumpDeclRef(const Decl *Node, const char *Label = 0);
+ void dumpName(const NamedDecl *D);
+ bool hasNodes(const DeclContext *DC);
+ void dumpDeclContext(const DeclContext *DC);
+ void dumpAttr(const Attr *A);
+
+ // C++ Utilities
+ void dumpAccessSpecifier(AccessSpecifier AS);
+ void dumpCXXCtorInitializer(const CXXCtorInitializer *Init);
+ void dumpTemplateParameters(const TemplateParameterList *TPL);
+ void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI);
+ void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A);
+ void dumpTemplateArgumentList(const TemplateArgumentList &TAL);
+ void dumpTemplateArgument(const TemplateArgument &A,
+ SourceRange R = SourceRange());
+
+ // Decls
+ void VisitLabelDecl(const LabelDecl *D);
+ void VisitTypedefDecl(const TypedefDecl *D);
+ void VisitEnumDecl(const EnumDecl *D);
+ void VisitRecordDecl(const RecordDecl *D);
+ void VisitEnumConstantDecl(const EnumConstantDecl *D);
+ void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
+ void VisitFunctionDecl(const FunctionDecl *D);
+ void VisitFieldDecl(const FieldDecl *D);
+ void VisitVarDecl(const VarDecl *D);
+ void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
+ void VisitImportDecl(const ImportDecl *D);
+
+ // C++ Decls
+ void VisitNamespaceDecl(const NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
+ void VisitTypeAliasDecl(const TypeAliasDecl *D);
+ void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
+ void VisitCXXRecordDecl(const CXXRecordDecl *D);
+ void VisitStaticAssertDecl(const StaticAssertDecl *D);
+ void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(const ClassTemplateDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ const ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ const ClassScopeFunctionSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
+ void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
+ void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
+ void VisitUsingDecl(const UsingDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
+ void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
+ void VisitUsingShadowDecl(const UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
+ void VisitAccessSpecDecl(const AccessSpecDecl *D);
+ void VisitFriendDecl(const FriendDecl *D);
+
+ // ObjC Decls
+ void VisitObjCIvarDecl(const ObjCIvarDecl *D);
+ void VisitObjCMethodDecl(const ObjCMethodDecl *D);
+ void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
+ void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
+ void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
+ void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
+ void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
+ void VisitBlockDecl(const BlockDecl *D);
+
+ // Stmts.
+ void VisitStmt(const Stmt *Node);
+ void VisitDeclStmt(const DeclStmt *Node);
+ void VisitAttributedStmt(const AttributedStmt *Node);
+ void VisitLabelStmt(const LabelStmt *Node);
+ void VisitGotoStmt(const GotoStmt *Node);
+
+ // Exprs
+ void VisitExpr(const Expr *Node);
+ void VisitCastExpr(const CastExpr *Node);
+ void VisitDeclRefExpr(const DeclRefExpr *Node);
+ void VisitPredefinedExpr(const PredefinedExpr *Node);
+ void VisitCharacterLiteral(const CharacterLiteral *Node);
+ void VisitIntegerLiteral(const IntegerLiteral *Node);
+ void VisitFloatingLiteral(const FloatingLiteral *Node);
+ void VisitStringLiteral(const StringLiteral *Str);
+ void VisitUnaryOperator(const UnaryOperator *Node);
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node);
+ void VisitMemberExpr(const MemberExpr *Node);
+ void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node);
+ void VisitBinaryOperator(const BinaryOperator *Node);
+ void VisitCompoundAssignOperator(const CompoundAssignOperator *Node);
+ void VisitAddrLabelExpr(const AddrLabelExpr *Node);
+ void VisitBlockExpr(const BlockExpr *Node);
+ void VisitOpaqueValueExpr(const OpaqueValueExpr *Node);
+
+ // C++
+ void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node);
+ void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
+ void VisitCXXThisExpr(const CXXThisExpr *Node);
+ void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
+ void VisitCXXConstructExpr(const CXXConstructExpr *Node);
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitExprWithCleanups(const ExprWithCleanups *Node);
+ void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
+ void dumpCXXTemporary(const CXXTemporary *Temporary);
+
+ // ObjC
+ void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
+ void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node);
+ void VisitObjCMessageExpr(const ObjCMessageExpr *Node);
+ void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node);
+ void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node);
+ void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node);
+ void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node);
+ void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node);
+ void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node);
+ void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node);
+
+ // Comments.
+ const char *getCommandName(unsigned CommandID);
+ void dumpComment(const Comment *C);
+
+ // Inline comments.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block comments.
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+// Print out the appropriate tree structure using the Indents vector.
+// Example of tree and the Indents vector at each level.
+// A { }
+// |-B { IT_Child }
+// | `-C { IT_Child, IT_LastChild }
+// `-D { IT_LastChild }
+// |-E { IT_LastChild, IT_Child }
+// `-F { IT_LastChild, IT_LastChild }
+// Type non-last element, last element
+// IT_Child "| " "|-"
+// IT_LastChild " " "`-"
+void ASTDumper::indent() {
+ if (IsFirstLine)
+ IsFirstLine = false;
+ else
+ OS << "\n";
+
+ ColorScope Color(*this, IndentColor);
+ for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(),
+ E = Indents.end();
+ I != E; ++I) {
+ switch (*I) {
+ case IT_Child:
+ if (I == E - 1)
+ OS << "|-";
+ else
+ OS << "| ";
+ continue;
+ case IT_LastChild:
+ if (I == E - 1)
+ OS << "`-";
+ else
+ OS << " ";
+ continue;
+ }
+ llvm_unreachable("Invalid IndentType");
+ }
+ Indents.push_back(IT_Child);
+}
+
+void ASTDumper::unindent() {
+ Indents.pop_back();
+}
+
+// Call before each potential last child node is to be dumped. If MoreChildren
+// is false, then this is the last child, otherwise treat as a regular node.
+void ASTDumper::lastChild() {
+ if (!hasMoreChildren())
+ Indents.back() = IT_LastChild;
+}
+
+// MoreChildren should be set before calling another function that may print
+// additional nodes to prevent conflicting final child nodes.
+bool ASTDumper::hasMoreChildren() {
+ return MoreChildren;
+}
+
+void ASTDumper::setMoreChildren(bool Value) {
+ MoreChildren = Value;
+}
+
+void ASTDumper::dumpPointer(const void *Ptr) {
+ ColorScope Color(*this, AddressColor);
+ OS << ' ' << Ptr;
+}
+
+void ASTDumper::dumpLocation(SourceLocation Loc) {
+ ColorScope Color(*this, LocationColor);
+ SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
+
+ // The general format we print out is filename:line:col, but we drop pieces
+ // that haven't changed since the last loc printed.
+ PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
+
+ if (PLoc.isInvalid()) {
+ OS << "<invalid sloc>";
+ return;
+ }
+
+ if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
+ OS << PLoc.getFilename() << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocFilename = PLoc.getFilename();
+ LastLocLine = PLoc.getLine();
+ } else if (PLoc.getLine() != LastLocLine) {
+ OS << "line" << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocLine = PLoc.getLine();
+ } else {
+ OS << "col" << ':' << PLoc.getColumn();
+ }
+}
+
+void ASTDumper::dumpSourceRange(SourceRange R) {
+ // Can't translate locations if a SourceManager isn't available.
+ if (!SM)
+ return;
+
+ OS << " <";
+ dumpLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd()) {
+ OS << ", ";
+ dumpLocation(R.getEnd());
+ }
+ OS << ">";
+
+ // <t2.c:123:421[blah], t2.c:412:321>
+
+}
+
+void ASTDumper::dumpBareType(QualType T) {
+ ColorScope Color(*this, TypeColor);
+
+ SplitQualType T_split = T.split();
+ OS << "'" << QualType::getAsString(T_split) << "'";
+
+ if (!T.isNull()) {
+ // If the type is sugared, also dump a (shallow) desugared type.
+ SplitQualType D_split = T.getSplitDesugaredType();
+ if (T_split != D_split)
+ OS << ":'" << QualType::getAsString(D_split) << "'";
+ }
+}
+
+void ASTDumper::dumpType(QualType T) {
+ OS << ' ';
+ dumpBareType(T);
+}
+
+void ASTDumper::dumpBareDeclRef(const Decl *D) {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName();
+ }
+ dumpPointer(D);
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ ColorScope Color(*this, DeclNameColor);
+ OS << " '";
+ ND->getDeclName().printName(OS);
+ OS << "'";
+ }
+
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ dumpType(VD->getType());
+}
+
+void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) {
+ if (!D)
+ return;
+
+ IndentScope Indent(*this);
+ if (Label)
+ OS << Label << ' ';
+ dumpBareDeclRef(D);
+}
+
+void ASTDumper::dumpName(const NamedDecl *ND) {
+ if (ND->getDeclName()) {
+ ColorScope Color(*this, DeclNameColor);
+ OS << ' ' << ND->getNameAsString();
+ }
+}
+
+bool ASTDumper::hasNodes(const DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ return DC->decls_begin() != DC->decls_end();
+}
+
+void ASTDumper::dumpDeclContext(const DeclContext *DC) {
+ if (!DC)
+ return;
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I) {
+ DeclContext::decl_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+}
+
+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"
+ default: llvm_unreachable("unexpected attribute kind");
+ }
+ OS << "Attr";
+ }
+ dumpPointer(A);
+ dumpSourceRange(A->getRange());
+#include "clang/AST/AttrDump.inc"
+}
+
+static Decl *getPreviousDeclImpl(...) {
+ return 0;
+}
+
+template<typename T>
+static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) {
+ return D->getPreviousDecl();
+}
+
+/// Get the previous declaration in the redeclaration chain for a declaration.
+static const Decl *getPreviousDecl(const Decl *D) {
+ switch (D->getKind()) {
+#define DECL(DERIVED, BASE) \
+ case Decl::DERIVED: \
+ return getPreviousDeclImpl(cast<DERIVED##Decl>(D));
+#define ABSTRACT_DECL(DECL)
+#include "clang/AST/DeclNodes.inc"
+ }
+ llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Utilities
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) {
+ switch (AS) {
+ case AS_none:
+ break;
+ case AS_public:
+ OS << "public";
+ break;
+ case AS_protected:
+ OS << "protected";
+ break;
+ case AS_private:
+ OS << "private";
+ break;
+ }
+}
+
+void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) {
+ IndentScope Indent(*this);
+ OS << "CXXCtorInitializer";
+ if (Init->isAnyMemberInitializer()) {
+ OS << ' ';
+ dumpBareDeclRef(Init->getAnyMember());
+ } else {
+ dumpType(QualType(Init->getBaseClass(), 0));
+ }
+ dumpStmt(Init->getInit());
+}
+
+void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
+ if (!TPL)
+ return;
+
+ for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I)
+ dumpDecl(*I);
+}
+
+void ASTDumper::dumpTemplateArgumentListInfo(
+ const TemplateArgumentListInfo &TALI) {
+ for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
+ if (i + 1 == e)
+ lastChild();
+ dumpTemplateArgumentLoc(TALI[i]);
+ }
+}
+
+void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) {
+ dumpTemplateArgument(A.getArgument(), A.getSourceRange());
+}
+
+void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
+ for (unsigned i = 0, e = TAL.size(); i < e; ++i)
+ dumpTemplateArgument(TAL[i]);
+}
+
+void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
+ IndentScope Indent(*this);
+ OS << "TemplateArgument";
+ if (R.isValid())
+ dumpSourceRange(R);
+
+ switch (A.getKind()) {
+ case TemplateArgument::Null:
+ OS << " null";
+ break;
+ case TemplateArgument::Type:
+ OS << " type";
+ lastChild();
+ dumpType(A.getAsType());
+ break;
+ case TemplateArgument::Declaration:
+ OS << " decl";
+ lastChild();
+ dumpDeclRef(A.getAsDecl());
+ break;
+ case TemplateArgument::NullPtr:
+ OS << " nullptr";
+ break;
+ case TemplateArgument::Integral:
+ OS << " integral " << A.getAsIntegral();
+ break;
+ case TemplateArgument::Template:
+ OS << " template ";
+ A.getAsTemplate().dump(OS);
+ break;
+ case TemplateArgument::TemplateExpansion:
+ OS << " template expansion";
+ A.getAsTemplateOrTemplatePattern().dump(OS);
+ break;
+ case TemplateArgument::Expression:
+ OS << " expr";
+ lastChild();
+ dumpStmt(A.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ OS << " pack";
+ for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpTemplateArgument(*I);
+ }
+ break;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Decl dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpDecl(const Decl *D) {
+ IndentScope Indent(*this);
+
+ if (!D) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName() << "Decl";
+ }
+ dumpPointer(D);
+ if (D->getLexicalDeclContext() != D->getDeclContext())
+ OS << " parent " << cast<Decl>(D->getDeclContext());
+ if (const Decl *Prev = getPreviousDecl(D))
+ OS << " prev " << Prev;
+ dumpSourceRange(D->getSourceRange());
+
+ bool HasAttrs = D->attr_begin() != D->attr_end();
+ bool HasComment = D->getASTContext().getCommentForDecl(D, 0);
+ // Decls within functions are visited by the body
+ bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
+ hasNodes(dyn_cast<DeclContext>(D));
+
+ setMoreChildren(HasAttrs || HasComment || HasDeclContext);
+ ConstDeclVisitor<ASTDumper>::Visit(D);
+
+ setMoreChildren(HasComment || HasDeclContext);
+ for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpAttr(*I);
+ }
+
+ setMoreChildren(HasDeclContext);
+ lastChild();
+ dumpFullComment(D->getASTContext().getCommentForDecl(D, 0));
+
+ setMoreChildren(false);
+ if (HasDeclContext)
+ dumpDeclContext(cast<DeclContext>(D));
+}
+
+void ASTDumper::VisitLabelDecl(const LabelDecl *D) {
+ dumpName(D);
+}
+
+void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
+ if (D->isScoped()) {
+ if (D->isScopedUsingClassTag())
+ OS << " class";
+ else
+ OS << " struct";
+ }
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isFixed())
+ dumpType(D->getIntegerType());
+}
+
+void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
+ OS << ' ' << D->getKindName();
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (const Expr *Init = D->getInitExpr()) {
+ lastChild();
+ dumpStmt(Init);
+ }
+}
+
+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);
+ }
+}
+
+void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isInlineSpecified())
+ OS << " inline";
+ if (D->isVirtualAsWritten())
+ OS << " virtual";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ if (D->isPure())
+ OS << " pure";
+ else if (D->isDeletedAsWritten())
+ OS << " delete";
+
+ bool OldMoreChildren = hasMoreChildren();
+ const FunctionTemplateSpecializationInfo *FTSI =
+ D->getTemplateSpecializationInfo();
+ bool HasTemplateSpecialization = FTSI;
+
+ bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() !=
+ D->getDeclsInPrototypeScope().end();
+
+ bool HasFunctionDecls = D->param_begin() != D->param_end();
+
+ const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
+ bool HasCtorInitializers = C && C->init_begin() != C->init_end();
+
+ bool HasDeclarationBody = D->doesThisDeclarationHaveABody();
+
+ setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls ||
+ HasCtorInitializers || HasDeclarationBody);
+ if (HasTemplateSpecialization) {
+ lastChild();
+ dumpTemplateArgumentList(*FTSI->TemplateArguments);
+ }
+
+ setMoreChildren(OldMoreChildren || HasFunctionDecls ||
+ HasCtorInitializers || HasDeclarationBody);
+ for (ArrayRef<NamedDecl *>::iterator
+ I = D->getDeclsInPrototypeScope().begin(),
+ E = D->getDeclsInPrototypeScope().end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+
+ setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody);
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+
+ setMoreChildren(OldMoreChildren || HasDeclarationBody);
+ if (HasCtorInitializers)
+ for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
+ E = C->init_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpCXXCtorInitializer(*I);
+ }
+
+ setMoreChildren(OldMoreChildren);
+ if (HasDeclarationBody) {
+ lastChild();
+ dumpStmt(D->getBody());
+ }
+}
+
+void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->isMutable())
+ OS << " mutable";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ bool OldMoreChildren = hasMoreChildren();
+ bool IsBitField = D->isBitField();
+ Expr *Init = D->getInClassInitializer();
+ bool HasInit = Init;
+
+ setMoreChildren(OldMoreChildren || HasInit);
+ if (IsBitField) {
+ lastChild();
+ dumpStmt(D->getBitWidth());
+ }
+ setMoreChildren(OldMoreChildren);
+ if (HasInit) {
+ lastChild();
+ dumpStmt(Init);
+ }
+}
+
+void ASTDumper::VisitVarDecl(const VarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isThreadSpecified())
+ OS << " __thread";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isNRVOVariable())
+ OS << " nrvo";
+ if (D->hasInit()) {
+ lastChild();
+ dumpStmt(D->getInit());
+ }
+}
+
+void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
+ lastChild();
+ dumpStmt(D->getAsmString());
+}
+
+void ASTDumper::VisitImportDecl(const ImportDecl *D) {
+ OS << ' ' << D->getImportedModule()->getFullModuleName();
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
+ dumpName(D);
+ if (D->isInline())
+ OS << " inline";
+ if (!D->isOriginalNamespace())
+ dumpDeclRef(D->getOriginalNamespace(), "original");
+}
+
+void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getNominatedNamespace());
+}
+
+void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getAliasedNamespace());
+}
+
+void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+}
+
+void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ dumpDecl(D->getTemplatedDecl());
+}
+
+void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
+ VisitRecordDecl(D);
+ if (!D->isCompleteDefinition())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(),
+ E = D->bases_end();
+ I != E; ++I) {
+ IndentScope Indent(*this);
+ if (I->isVirtual())
+ OS << "virtual ";
+ dumpAccessSpecifier(I->getAccessSpecifier());
+ dumpType(I->getType());
+ if (I->isPackExpansion())
+ OS << "...";
+ }
+}
+
+void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
+ dumpStmt(D->getAssertExpr());
+ lastChild();
+ 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:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+ 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;
+ }
+ }
+}
+
+void ASTDumper::VisitClassTemplateSpecializationDecl(
+ const ClassTemplateSpecializationDecl *D) {
+ VisitCXXRecordDecl(D);
+ dumpTemplateArgumentList(D->getTemplateArgs());
+}
+
+void ASTDumper::VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDecl(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+}
+
+void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
+ const ClassScopeFunctionSpecializationDecl *D) {
+ dumpDeclRef(D->getSpecialization());
+ if (D->hasExplicitTemplateArgs())
+ dumpTemplateArgumentListInfo(D->templateArgs());
+}
+
+void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ if (D->wasDeclaredWithTypename())
+ OS << " typename";
+ else
+ OS << " class";
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ if (D->hasDefaultArgument())
+ dumpType(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
+ dumpType(D->getType());
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ if (D->hasDefaultArgument())
+ dumpStmt(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ if (D->hasDefaultArgument())
+ dumpTemplateArgumentLoc(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingTypenameDecl(
+ const UnresolvedUsingTypenameDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+ dumpType(D->getType());
+}
+
+void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getTargetDecl());
+}
+
+void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
+ switch (D->getLanguage()) {
+ case LinkageSpecDecl::lang_c: OS << " C"; break;
+ case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
+ }
+}
+
+void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
+ OS << ' ';
+ dumpAccessSpecifier(D->getAccess());
+}
+
+void ASTDumper::VisitFriendDecl(const FriendDecl *D) {
+ lastChild();
+ if (TypeSourceInfo *T = D->getFriendType())
+ dumpType(T->getType());
+ else
+ dumpDecl(D->getFriendDecl());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->getSynthesize())
+ OS << " synthesize";
+
+ switch (D->getAccessControl()) {
+ case ObjCIvarDecl::None:
+ OS << " none";
+ break;
+ case ObjCIvarDecl::Private:
+ OS << " private";
+ break;
+ case ObjCIvarDecl::Protected:
+ OS << " protected";
+ break;
+ case ObjCIvarDecl::Public:
+ OS << " public";
+ break;
+ case ObjCIvarDecl::Package:
+ OS << " package";
+ break;
+ }
+}
+
+void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ if (D->isInstanceMethod())
+ OS << " -";
+ else
+ OS << " +";
+ dumpName(D);
+ dumpType(D->getResultType());
+
+ bool OldMoreChildren = hasMoreChildren();
+ bool IsVariadic = D->isVariadic();
+ bool HasBody = D->hasBody();
+
+ setMoreChildren(OldMoreChildren || IsVariadic || HasBody);
+ if (D->isThisDeclarationADefinition()) {
+ lastChild();
+ dumpDeclContext(D);
+ } else {
+ for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+ }
+
+ setMoreChildren(OldMoreChildren || HasBody);
+ if (IsVariadic) {
+ lastChild();
+ IndentScope Indent(*this);
+ OS << "...";
+ }
+
+ setMoreChildren(OldMoreChildren);
+ if (HasBody) {
+ lastChild();
+ dumpStmt(D->getBody());
+ }
+}
+
+void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
+ dumpDeclRef(D->getImplementation());
+ for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ lastChild();
+ dumpDeclRef(D->getCategoryDecl());
+}
+
+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);
+ }
+}
+
+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);
+ }
+}
+
+void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+ if (D->init_begin() == D->init_end())
+ lastChild();
+ dumpDeclRef(D->getClassInterface());
+ for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
+ E = D->init_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpCXXCtorInitializer(*I);
+ }
+}
+
+void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) {
+ dumpName(D);
+ lastChild();
+ dumpDeclRef(D->getClassInterface());
+}
+
+void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
+ OS << " required";
+ else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ OS << " optional";
+
+ ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
+ if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly)
+ OS << " readonly";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
+ OS << " assign";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite)
+ OS << " readwrite";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_retain)
+ OS << " retain";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_copy)
+ OS << " copy";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ OS << " nonatomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic)
+ OS << " atomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_weak)
+ OS << " weak";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_strong)
+ OS << " strong";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
+ OS << " unsafe_unretained";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) {
+ if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter))
+ lastChild();
+ dumpDeclRef(D->getGetterMethodDecl(), "getter");
+ }
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) {
+ lastChild();
+ dumpDeclRef(D->getSetterMethodDecl(), "setter");
+ }
+ }
+}
+
+void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
+ dumpName(D->getPropertyDecl());
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+ OS << " synthesize";
+ else
+ OS << " dynamic";
+ dumpDeclRef(D->getPropertyDecl());
+ lastChild();
+ dumpDeclRef(D->getPropertyIvarDecl());
+}
+
+void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
+ for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
+ I != E; ++I)
+ dumpDecl(*I);
+
+ if (D->isVariadic()) {
+ IndentScope Indent(*this);
+ OS << "...";
+ }
+
+ if (D->capturesCXXThis()) {
+ IndentScope Indent(*this);
+ OS << "capture this";
+ }
+ for (BlockDecl::capture_iterator I = D->capture_begin(), E = D->capture_end();
+ I != E; ++I) {
+ IndentScope Indent(*this);
+ OS << "capture";
+ if (I->isByRef())
+ OS << " byref";
+ if (I->isNested())
+ OS << " nested";
+ if (I->getVariable()) {
+ OS << ' ';
+ dumpBareDeclRef(I->getVariable());
+ }
+ if (I->hasCopyExpr())
+ dumpStmt(I->getCopyExpr());
+ }
+ lastChild();
+ dumpStmt(D->getBody());
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpStmt(const Stmt *S) {
+ IndentScope Indent(*this);
+
+ if (!S) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ return;
+ }
+
+ setMoreChildren(S->children());
+ ConstStmtVisitor<ASTDumper>::Visit(S);
+ setMoreChildren(false);
+ for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
+ Stmt::const_child_range Next = CI;
+ ++Next;
+ if (!Next)
+ lastChild();
+ dumpStmt(*CI);
+ }
+}
+
+void ASTDumper::VisitStmt(const Stmt *Node) {
+ {
+ ColorScope Color(*this, StmtColor);
+ OS << Node->getStmtClassName();
+ }
+ dumpPointer(Node);
+ dumpSourceRange(Node->getSourceRange());
+}
+
+void ASTDumper::VisitDeclStmt(const DeclStmt *Node) {
+ VisitStmt(Node);
+ for (DeclStmt::const_decl_iterator I = Node->decl_begin(),
+ E = Node->decl_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+}
+
+void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) {
+ VisitStmt(Node);
+ for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(),
+ E = Node->getAttrs().end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpAttr(*I);
+ }
+}
+
+void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
+ VisitStmt(Node);
+ OS << " '" << Node->getName() << "'";
+}
+
+void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
+ VisitStmt(Node);
+ OS << " '" << Node->getLabel()->getName() << "'";
+ dumpPointer(Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// Expr dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitExpr(const Expr *Node) {
+ VisitStmt(Node);
+ dumpType(Node->getType());
+
+ {
+ ColorScope Color(*this, ValueKindColor);
+ switch (Node->getValueKind()) {
+ case VK_RValue:
+ break;
+ case VK_LValue:
+ OS << " lvalue";
+ break;
+ case VK_XValue:
+ OS << " xvalue";
+ break;
+ }
+ }
+
+ {
+ ColorScope Color(*this, ObjectKindColor);
+ switch (Node->getObjectKind()) {
+ case OK_Ordinary:
+ break;
+ case OK_BitField:
+ OS << " bitfield";
+ break;
+ case OK_ObjCProperty:
+ OS << " objcproperty";
+ break;
+ case OK_ObjCSubscript:
+ OS << " objcsubscript";
+ break;
+ case OK_VectorComponent:
+ OS << " vectorcomponent";
+ break;
+ }
+ }
+}
+
+static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
+ if (Node->path_empty())
+ return;
+
+ OS << " (";
+ bool First = true;
+ for (CastExpr::path_const_iterator I = Node->path_begin(),
+ E = Node->path_end();
+ I != E; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ if (!First)
+ OS << " -> ";
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual())
+ OS << "virtual ";
+ OS << RD->getName();
+ First = false;
+ }
+
+ OS << ')';
+}
+
+void ASTDumper::VisitCastExpr(const CastExpr *Node) {
+ VisitExpr(Node);
+ OS << " <";
+ {
+ ColorScope Color(*this, CastColor);
+ OS << Node->getCastKindName();
+ }
+ dumpBasePath(OS, Node);
+ OS << ">";
+}
+
+void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
+ VisitExpr(Node);
+
+ OS << " ";
+ dumpBareDeclRef(Node->getDecl());
+ if (Node->getDecl() != Node->getFoundDecl()) {
+ OS << " (";
+ dumpBareDeclRef(Node->getFoundDecl());
+ OS << ")";
+ }
+}
+
+void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) {
+ VisitExpr(Node);
+ OS << " (";
+ if (!Node->requiresADL())
+ OS << "no ";
+ OS << "ADL) = '" << Node->getName() << '\'';
+
+ UnresolvedLookupExpr::decls_iterator
+ I = Node->decls_begin(), E = Node->decls_end();
+ if (I == E)
+ OS << " empty";
+ for (; I != E; ++I)
+ dumpPointer(*I);
+}
+
+void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
+ VisitExpr(Node);
+
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << " " << Node->getDecl()->getDeclKindName() << "Decl";
+ }
+ OS << "='" << *Node->getDecl() << "'";
+ dumpPointer(Node->getDecl());
+ if (Node->isFreeIvar())
+ OS << " isFreeIvar";
+}
+
+void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
+ VisitExpr(Node);
+ switch (Node->getIdentType()) {
+ default: llvm_unreachable("unknown case");
+ case PredefinedExpr::Func: OS << " __func__"; break;
+ case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
+ case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
+ }
+}
+
+void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {
+ VisitExpr(Node);
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValue();
+}
+
+void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) {
+ VisitExpr(Node);
+
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValue().toString(10, isSigned);
+}
+
+void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
+ VisitExpr(Node);
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValueAsApproximateDouble();
+}
+
+void ASTDumper::VisitStringLiteral(const StringLiteral *Str) {
+ VisitExpr(Str);
+ ColorScope Color(*this, ValueColor);
+ OS << " ";
+ Str->outputString(OS);
+}
+
+void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
+ << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+}
+
+void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *Node) {
+ VisitExpr(Node);
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << " sizeof";
+ break;
+ case UETT_AlignOf:
+ OS << " alignof";
+ break;
+ case UETT_VecStep:
+ OS << " vec_step";
+ break;
+ }
+ if (Node->isArgumentType())
+ dumpType(Node->getArgumentType());
+}
+
+void ASTDumper::VisitMemberExpr(const MemberExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
+ dumpPointer(Node->getMemberDecl());
+}
+
+void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getAccessor().getNameStart();
+}
+
+void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) {
+ VisitExpr(Node);
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+}
+
+void ASTDumper::VisitCompoundAssignOperator(
+ const CompoundAssignOperator *Node) {
+ VisitExpr(Node);
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
+ << "' ComputeLHSTy=";
+ dumpBareType(Node->getComputationLHSType());
+ OS << " ComputeResultTy=";
+ dumpBareType(Node->getComputationResultType());
+}
+
+void ASTDumper::VisitBlockExpr(const BlockExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getBlockDecl());
+}
+
+void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
+ VisitExpr(Node);
+
+ if (Expr *Source = Node->getSourceExpr()) {
+ lastChild();
+ dumpStmt(Source);
+ }
+}
+
+// GNU extensions.
+
+void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getLabel()->getName();
+ dumpPointer(Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getCastName()
+ << "<" << Node->getTypeAsWritten().getAsString() << ">"
+ << " <" << Node->getCastKindName();
+ dumpBasePath(OS, Node);
+ OS << ">";
+}
+
+void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->getValue() ? "true" : "false");
+}
+
+void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
+ VisitExpr(Node);
+ OS << " this";
+}
+
+void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) {
+ VisitExpr(Node);
+ OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
+ << " <" << Node->getCastKindName() << ">";
+}
+
+void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
+ VisitExpr(Node);
+ CXXConstructorDecl *Ctor = Node->getConstructor();
+ dumpType(Ctor->getType());
+ if (Node->isElidable())
+ OS << " elidable";
+ if (Node->requiresZeroInitialization())
+ OS << " zeroing";
+}
+
+void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
+ VisitExpr(Node);
+ OS << " ";
+ dumpCXXTemporary(Node->getTemporary());
+}
+
+void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
+ VisitExpr(Node);
+ for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
+ dumpDeclRef(Node->getObject(i), "cleanup");
+}
+
+void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
+ OS << "(CXXTemporary";
+ dumpPointer(Temporary);
+ OS << ")";
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Expressions
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
+ VisitExpr(Node);
+ OS << " selector=" << Node->getSelector().getAsString();
+ switch (Node->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << " class=";
+ dumpBareType(Node->getClassReceiver());
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ OS << " super (instance)";
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OS << " super (class)";
+ break;
+ }
+}
+
+void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
+ VisitExpr(Node);
+ OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
+}
+
+void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
+ VisitStmt(Node);
+ if (const VarDecl *CatchParam = Node->getCatchParamDecl())
+ dumpDecl(CatchParam);
+ else
+ OS << " catch all";
+}
+
+void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
+ VisitExpr(Node);
+ dumpType(Node->getEncodedType());
+}
+
+void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) {
+ VisitExpr(Node);
+
+ OS << " " << Node->getSelector().getAsString();
+}
+
+void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) {
+ VisitExpr(Node);
+
+ OS << ' ' << *Node->getProtocol();
+}
+
+void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isImplicitProperty()) {
+ OS << " Kind=MethodRef Getter=\"";
+ if (Node->getImplicitPropertyGetter())
+ OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ OS << "\" Setter=\"";
+ if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
+ OS << Setter->getSelector().getAsString();
+ else
+ OS << "(null)";
+ OS << "\"";
+ } else {
+ OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
+ }
+
+ if (Node->isSuperReceiver())
+ OS << " super";
+
+ OS << " Messaging=";
+ if (Node->isMessagingGetter() && Node->isMessagingSetter())
+ OS << "Getter&Setter";
+ else if (Node->isMessagingGetter())
+ OS << "Getter";
+ else if (Node->isMessagingSetter())
+ OS << "Setter";
+}
+
+void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isArraySubscriptRefExpr())
+ OS << " Kind=ArraySubscript GetterForArray=\"";
+ else
+ OS << " Kind=DictionarySubscript GetterForDictionary=\"";
+ if (Node->getAtIndexMethodDecl())
+ OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ if (Node->isArraySubscriptRefExpr())
+ OS << "\" SetterForArray=\"";
+ else
+ OS << "\" SetterForDictionary=\"";
+ if (Node->setAtIndexMethodDecl())
+ OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+}
+
+void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
+}
+
+//===----------------------------------------------------------------------===//
+// Comments
+//===----------------------------------------------------------------------===//
+
+const char *ASTDumper::getCommandName(unsigned CommandID) {
+ if (Traits)
+ return Traits->getCommandInfo(CommandID)->Name;
+ const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+ if (Info)
+ return Info->Name;
+ return "<not a builtin command>";
+}
+
+void ASTDumper::dumpFullComment(const FullComment *C) {
+ if (!C)
+ return;
+
+ FC = C;
+ dumpComment(C);
+ FC = 0;
+}
+
+void ASTDumper::dumpComment(const Comment *C) {
+ IndentScope Indent(*this);
+
+ if (!C) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, CommentColor);
+ OS << C->getCommentKindName();
+ }
+ dumpPointer(C);
+ dumpSourceRange(C->getSourceRange());
+ ConstCommentVisitor<ASTDumper>::visit(C);
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpComment(*I);
+ }
+}
+
+void ASTDumper::visitTextComment(const TextComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ OS << " RenderNormal";
+ break;
+ case InlineCommandComment::RenderBold:
+ OS << " RenderBold";
+ break;
+ case InlineCommandComment::RenderMonospaced:
+ OS << " RenderMonospaced";
+ break;
+ case InlineCommandComment::RenderEmphasized:
+ OS << " RenderEmphasized";
+ break;
+ }
+
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+ OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
+}
+
+void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
+ OS << " Name=\"" << C->getTagName() << "\"";
+ if (C->getNumAttrs() != 0) {
+ OS << " Attrs: ";
+ for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+ OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
+ }
+ }
+ if (C->isSelfClosing())
+ OS << " SelfClosing";
+}
+
+void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
+ OS << " Name=\"" << C->getTagName() << "\"";
+}
+
+void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+ OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
+}
+
+void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) {
+ OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
+
+ if (C->isDirectionExplicit())
+ OS << " explicitly";
+ else
+ OS << " implicitly";
+
+ if (C->hasParamName()) {
+ if (C->isParamIndexValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
+
+ if (C->isParamIndexValid())
+ OS << " ParamIndex=" << C->getParamIndex();
+}
+
+void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) {
+ if (C->hasParamName()) {
+ if (C->isPositionValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
+
+ if (C->isPositionValid()) {
+ OS << " Position=<";
+ for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
+ OS << C->getIndex(i);
+ if (i != e - 1)
+ OS << ", ";
+ }
+ OS << ">";
+ }
+}
+
+void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
+ " CloseName=\"" << C->getCloseName() << "\"";
+}
+
+void ASTDumper::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+//===----------------------------------------------------------------------===//
+// Decl method implementations
+//===----------------------------------------------------------------------===//
+
+void Decl::dump() const {
+ dump(llvm::errs());
+}
+
+void Decl::dump(raw_ostream &OS) const {
+ ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
+ &getASTContext().getSourceManager());
+ P.dumpDecl(this);
+}
+
+void Decl::dumpColor() const {
+ ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(),
+ &getASTContext().getSourceManager(), /*ShowColors*/true);
+ P.dumpDecl(this);
+}
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+void Stmt::dump(SourceManager &SM) const {
+ dump(llvm::errs(), SM);
+}
+
+void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
+ ASTDumper P(OS, 0, &SM);
+ P.dumpStmt(this);
+}
+
+void Stmt::dump() const {
+ ASTDumper P(llvm::errs(), 0, 0);
+ P.dumpStmt(this);
+}
+
+void Stmt::dumpColor() const {
+ ASTDumper P(llvm::errs(), 0, 0, /*ShowColors*/true);
+ P.dumpStmt(this);
+}
+
+//===----------------------------------------------------------------------===//
+// Comment method implementations
+//===----------------------------------------------------------------------===//
+
+void Comment::dump() const {
+ dump(llvm::errs(), 0, 0);
+}
+
+void Comment::dump(const ASTContext &Context) const {
+ dump(llvm::errs(), &Context.getCommentCommandTraits(),
+ &Context.getSourceManager());
+}
+
+void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM) const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ ASTDumper D(OS, Traits, SM);
+ D.dumpFullComment(FC);
+}
+
+void Comment::dumpColor() const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ ASTDumper D(llvm::errs(), 0, 0, /*ShowColors*/true);
+ D.dumpFullComment(FC);
+}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 0d4f303af2b5..d2e6d2970531 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTImporter.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -122,6 +121,7 @@ namespace clang {
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
+ bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
@@ -206,12 +206,16 @@ namespace {
/// \brief Whether to complain about failures.
bool Complain;
+ /// \brief \c true if the last diagnostic came from C2.
+ bool LastDiagFromC2;
+
StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
bool StrictTypeSpelling = false,
bool Complain = true)
: C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls),
- StrictTypeSpelling(StrictTypeSpelling), Complain(Complain) { }
+ StrictTypeSpelling(StrictTypeSpelling), Complain(Complain),
+ LastDiagFromC2(false) {}
/// \brief Determine whether the two declarations are structurally
/// equivalent.
@@ -229,11 +233,17 @@ namespace {
public:
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
assert(Complain && "Not allowed to complain");
+ if (LastDiagFromC2)
+ C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics());
+ LastDiagFromC2 = false;
return C1.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
assert(Complain && "Not allowed to complain");
+ if (!LastDiagFromC2)
+ C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics());
+ LastDiagFromC2 = true;
return C2.getDiagnostics().Report(Loc, DiagID);
}
};
@@ -892,14 +902,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
/// including the next assigned index (if none of them match). Returns an
/// empty option if the context is not a record, i.e.. if the anonymous
/// struct/union is at namespace or block scope.
-static llvm::Optional<unsigned>
-findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
+static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
QualType AnonTy = Context.getRecordType(Anon);
RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
if (!Owner)
- return llvm::Optional<unsigned>();
+ return None;
unsigned Index = 0;
for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
@@ -934,10 +943,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (llvm::Optional<unsigned> Index1
- = findAnonymousStructOrUnionIndex(D1)) {
- if (llvm::Optional<unsigned> Index2
- = findAnonymousStructOrUnionIndex(D2)) {
+ if (Optional<unsigned> Index1 = findAnonymousStructOrUnionIndex(D1)) {
+ if (Optional<unsigned> Index2 = findAnonymousStructOrUnionIndex(D2)) {
if (*Index1 != *Index2)
return false;
}
@@ -1612,8 +1619,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
Importer.Import(FromEPI.ExceptionSpecTemplate));
- return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(), ToEPI);
+ return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI);
}
QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -1825,7 +1831,7 @@ void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) {
if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) {
if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) {
- if (FromRecord->getDefinition() && !ToRecord->getDefinition()) {
+ if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && !ToRecord->getDefinition()) {
ImportDefinition(FromRecord, ToRecord);
}
}
@@ -1907,11 +1913,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor;
- ToData.UserDeclaredCopyConstructor = FromData.UserDeclaredCopyConstructor;
- ToData.UserDeclaredMoveConstructor = FromData.UserDeclaredMoveConstructor;
- ToData.UserDeclaredCopyAssignment = FromData.UserDeclaredCopyAssignment;
- ToData.UserDeclaredMoveAssignment = FromData.UserDeclaredMoveAssignment;
- ToData.UserDeclaredDestructor = FromData.UserDeclaredDestructor;
+ ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers;
ToData.Aggregate = FromData.Aggregate;
ToData.PlainOldData = FromData.PlainOldData;
ToData.Empty = FromData.Empty;
@@ -1925,30 +1927,41 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.HasMutableFields = FromData.HasMutableFields;
ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
ToData.HasInClassInitializer = FromData.HasInClassInitializer;
- ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor;
+ ToData.HasUninitializedReferenceMember
+ = FromData.HasUninitializedReferenceMember;
+ ToData.NeedOverloadResolutionForMoveConstructor
+ = FromData.NeedOverloadResolutionForMoveConstructor;
+ ToData.NeedOverloadResolutionForMoveAssignment
+ = FromData.NeedOverloadResolutionForMoveAssignment;
+ ToData.NeedOverloadResolutionForDestructor
+ = FromData.NeedOverloadResolutionForDestructor;
+ ToData.DefaultedMoveConstructorIsDeleted
+ = FromData.DefaultedMoveConstructorIsDeleted;
+ ToData.DefaultedMoveAssignmentIsDeleted
+ = FromData.DefaultedMoveAssignmentIsDeleted;
+ ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
+ ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
+ ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasConstexprNonCopyMoveConstructor
= FromData.HasConstexprNonCopyMoveConstructor;
ToData.DefaultedDefaultConstructorIsConstexpr
= FromData.DefaultedDefaultConstructorIsConstexpr;
ToData.HasConstexprDefaultConstructor
= FromData.HasConstexprDefaultConstructor;
- ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor;
- ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor;
- ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment;
- ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment;
- ToData.HasTrivialDestructor = FromData.HasTrivialDestructor;
- ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasNonLiteralTypeFieldsOrBases
= FromData.HasNonLiteralTypeFieldsOrBases;
// ComputedVisibleConversions not imported.
ToData.UserProvidedDefaultConstructor
= FromData.UserProvidedDefaultConstructor;
- ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor;
- ToData.DeclaredCopyConstructor = FromData.DeclaredCopyConstructor;
- ToData.DeclaredMoveConstructor = FromData.DeclaredMoveConstructor;
- ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment;
- ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment;
- ToData.DeclaredDestructor = FromData.DeclaredDestructor;
+ ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers;
+ ToData.ImplicitCopyConstructorHasConstParam
+ = FromData.ImplicitCopyConstructorHasConstParam;
+ ToData.ImplicitCopyAssignmentHasConstParam
+ = FromData.ImplicitCopyAssignmentHasConstParam;
+ ToData.HasDeclaredCopyConstructorWithConstParam
+ = FromData.HasDeclaredCopyConstructorWithConstParam;
+ ToData.HasDeclaredCopyAssignmentWithConstParam
+ = FromData.HasDeclaredCopyAssignmentWithConstParam;
ToData.FailedImplicitMoveConstructor
= FromData.FailedImplicitMoveConstructor;
ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
@@ -2143,7 +2156,18 @@ bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum);
}
-bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
+bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC,
+ EnumConstantDecl *ToEC)
+{
+ const llvm::APSInt &FromVal = FromEC->getInitVal();
+ const llvm::APSInt &ToVal = ToEC->getInitVal();
+
+ return FromVal.isSigned() == ToVal.isSigned() &&
+ FromVal.getBitWidth() == ToVal.getBitWidth() &&
+ FromVal == ToVal;
+}
+
+bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
ClassTemplateDecl *To) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2185,7 +2209,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace();
} else {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace))
@@ -2248,7 +2272,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2328,7 +2352,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// We may already have an enum of the same name; try to find and match it.
if (!DC->isFunctionOrMethod() && SearchName) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2414,7 +2438,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
RecordDecl *AdoptDecl = 0;
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2431,10 +2455,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
FoundRecord->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (llvm::Optional<unsigned> Index1
+ if (Optional<unsigned> Index1
= findAnonymousStructOrUnionIndex(D)) {
- if (llvm::Optional<unsigned> Index2
- = findAnonymousStructOrUnionIndex(FoundRecord)) {
+ if (Optional<unsigned> Index2 =
+ findAnonymousStructOrUnionIndex(FoundRecord)) {
if (*Index1 != *Index2)
continue;
}
@@ -2521,12 +2545,18 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
+ if (EnumConstantDecl *FoundEnumConstant
+ = dyn_cast<EnumConstantDecl>(FoundDecls[I])) {
+ if (IsStructuralMatch(D, FoundEnumConstant))
+ return Importer.Imported(D, FoundEnumConstant);
+ }
+
ConflictingDecls.push_back(FoundDecls[I]);
}
@@ -2567,7 +2597,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2629,8 +2659,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
FromFPT->getResultType(),
- FromFPT->arg_type_begin(),
- FromFPT->arg_type_end() - FromFPT->arg_type_begin(),
+ ArrayRef<QualType>(FromFPT->arg_type_begin(),
+ FromFPT->getNumArgs()),
DefaultEPI);
usedDifferentExceptionSpec = true;
}
@@ -2686,8 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
cast<CXXRecordDecl>(DC),
D->getInnerLocStart(),
NameInfo, T, TInfo,
- Method->isStatic(),
- Method->getStorageClassAsWritten(),
+ Method->getStorageClass(),
Method->isInlineSpecified(),
D->isConstexpr(),
Importer.Import(D->getLocEnd()));
@@ -2695,7 +2724,6 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
D->getInnerLocStart(),
NameInfo, T, TInfo, D->getStorageClass(),
- D->getStorageClassAsWritten(),
D->isInlineSpecified(),
D->hasWrittenPrototype(),
D->isConstexpr());
@@ -2777,7 +2805,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
return 0;
// Determine whether we've already imported this field.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
@@ -2833,7 +2861,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
return 0;
// Determine whether we've already imported this field.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (IndirectFieldDecl *FoundField
@@ -2898,7 +2926,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
return 0;
// Determine whether we've already imported this ivar
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) {
@@ -2953,7 +2981,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
VarDecl *MergeWithVar = 0;
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -3046,8 +3074,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo,
- D->getStorageClass(),
- D->getStorageClassAsWritten());
+ D->getStorageClass());
ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
@@ -3115,7 +3142,6 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
- D->getStorageClassAsWritten(),
/*FIXME: Default argument*/ 0);
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
@@ -3129,7 +3155,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) {
@@ -3376,7 +3402,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
return 0;
ObjCProtocolDecl *MergeWithProtocol = 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol))
@@ -3480,10 +3506,13 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
// Import categories. When the categories themselves are imported, they'll
// hook themselves into this interface.
- for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat;
- FromCat = FromCat->getNextClassCategory())
- Importer.Import(FromCat);
-
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = From->known_categories_begin(),
+ CatEnd = From->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ Importer.Import(*Cat);
+ }
+
// If we have an @implementation, import it as well.
if (From->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
@@ -3523,7 +3552,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Look for an existing interface with the same name.
ObjCInterfaceDecl *MergeWithIface = 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
@@ -3675,7 +3704,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
return 0;
// Check whether we have already imported this property.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCPropertyDecl *FoundProp
@@ -3908,7 +3937,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// We may already have a template of the same name; try to find and match it.
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
@@ -4295,7 +4324,7 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
bool MinimalImport)
: ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
- Minimal(MinimalImport)
+ Minimal(MinimalImport), LastDiagFromFrom(false)
{
ImportedDecls[FromContext.getTranslationUnitDecl()]
= ToContext.getTranslationUnitDecl();
@@ -4798,10 +4827,18 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
+ if (LastDiagFromFrom)
+ ToContext.getDiagnostics().notePriorDiagnosticFrom(
+ FromContext.getDiagnostics());
+ LastDiagFromFrom = false;
return ToContext.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
+ if (!LastDiagFromFrom)
+ FromContext.getDiagnostics().notePriorDiagnosticFrom(
+ ToContext.getDiagnostics());
+ LastDiagFromFrom = true;
return FromContext.getDiagnostics().Report(Loc, DiagID);
}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index cffcc6501eff..daf65e56bdc6 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -13,8 +13,8 @@
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
using namespace clang;
Attr::~Attr() { }
@@ -23,4 +23,6 @@ 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 d20d77ef7ea5..e804fe720558 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -5,13 +5,13 @@ add_clang_library(clangAST
ASTConsumer.cpp
ASTContext.cpp
ASTDiagnostic.cpp
+ ASTDumper.cpp
ASTImporter.cpp
AttrImpl.cpp
CXXInheritance.cpp
Comment.cpp
CommentBriefParser.cpp
CommentCommandTraits.cpp
- CommentDumper.cpp
CommentLexer.cpp
CommentParser.cpp
CommentSema.cpp
@@ -22,6 +22,7 @@ add_clang_library(clangAST
DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
+ DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DumpXML.cpp
@@ -45,7 +46,6 @@ add_clang_library(clangAST
RecordLayoutBuilder.cpp
SelectorLocationsKind.cpp
Stmt.cpp
- StmtDumper.cpp
StmtIterator.cpp
StmtPrinter.cpp
StmtProfile.cpp
@@ -64,10 +64,13 @@ add_dependencies(clangAST
ClangAttrClasses
ClangAttrList
ClangAttrImpl
+ ClangAttrDump
ClangCommentCommandInfo
+ ClangCommentCommandList
ClangCommentNodes
ClangCommentHTMLTags
ClangCommentHTMLTagsProperties
+ ClangCommentHTMLNamedCharacterReferences
ClangDeclNodes
ClangDiagnosticAST
ClangDiagnosticComment
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 0d9c869d87ca..6d67d9a12b55 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -27,9 +27,9 @@ class CXXABI {
public:
virtual ~CXXABI();
- /// Returns the size of a member pointer in multiples of the target
- /// pointer size.
- virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
+ /// Returns the width and alignment of a member pointer in bits.
+ virtual std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0;
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 213b214a4e4c..0e0b35d92adf 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SetVector.h"
#include <algorithm>
#include <set>
@@ -28,7 +28,7 @@ void CXXBasePaths::ComputeDeclsFound() {
llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls;
for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
- Decls.insert(*Path->Decls.first);
+ Decls.insert(Path->Decls.front());
NumDeclsFound = Decls.size();
DeclsFound = new NamedDecl * [NumDeclsFound];
@@ -118,7 +118,19 @@ static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) {
}
bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
- return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl());
+ return forallBases(BaseIsNot,
+ const_cast<CXXRecordDecl *>(Base->getCanonicalDecl()));
+}
+
+bool
+CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const {
+ assert(isDependentContext());
+
+ for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
+ if (CurContext->Equals(this))
+ return true;
+
+ return false;
}
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
@@ -140,7 +152,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
CXXRecordDecl *Base =
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
- if (!Base) {
+ if (!Base ||
+ (Base->isDependentContext() &&
+ !Base->isCurrentInstantiation(Record))) {
if (AllowShortCircuit) return false;
AllMatches = false;
continue;
@@ -384,9 +398,9 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}
@@ -402,9 +416,9 @@ bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS))
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
return true;
}
@@ -420,11 +434,11 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
// FIXME: Refactor the "is it a nested-name-specifier?" check
- if (isa<TypedefNameDecl>(*Path.Decls.first) ||
- (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ if (isa<TypedefNameDecl>(Path.Decls.front()) ||
+ Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}
@@ -725,4 +739,3 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
AddIndirectPrimaryBases(BaseDecl, Context, Bases);
}
}
-
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 361f8ac61c2a..db55c045449d 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -32,20 +32,6 @@ const char *Comment::getCommentKindName() const {
llvm_unreachable("Unknown comment kind!");
}
-void Comment::dump() const {
- // It is important that Comment::dump() is defined in a different TU than
- // Comment::dump(raw_ostream, SourceManager). If both functions were defined
- // in CommentDumper.cpp, that object file would be removed by linker because
- // none of its functions are referenced by other object files, despite the
- // LLVM_ATTRIBUTE_USED.
- dump(llvm::errs(), NULL, NULL);
-}
-
-void Comment::dump(const ASTContext &Context) const {
- dump(llvm::errs(), &Context.getCommentCommandTraits(),
- &Context.getSourceManager());
-}
-
namespace {
struct good {};
struct bad {};
@@ -255,32 +241,32 @@ void DeclInfo::fill() {
while (true) {
TL = TL.IgnoreParens();
// Look through qualified types.
- if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QualifiedTL->getUnqualifiedLoc();
+ if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QualifiedTL.getUnqualifiedLoc();
continue;
}
// Look through pointer types.
- if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
- TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
+ TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
- if (BlockPointerTypeLoc *BlockPointerTL =
- dyn_cast<BlockPointerTypeLoc>(&TL)) {
- TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (BlockPointerTypeLoc BlockPointerTL =
+ TL.getAs<BlockPointerTypeLoc>()) {
+ TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
- if (MemberPointerTypeLoc *MemberPointerTL =
- dyn_cast<MemberPointerTypeLoc>(&TL)) {
- TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (MemberPointerTypeLoc MemberPointerTL =
+ TL.getAs<MemberPointerTypeLoc>()) {
+ TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
// Is this a typedef for a function type?
- if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
Kind = FunctionKind;
- ArrayRef<ParmVarDecl *> Params = FTL->getParams();
+ ArrayRef<ParmVarDecl *> Params = FTL.getParams();
ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
Params.size());
- ResultType = FTL->getResultLoc().getType();
+ ResultType = FTL.getResultLoc().getType();
break;
}
break;
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 95daa7e3f809..090b9211d4c1 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -78,7 +78,7 @@ std::string BriefParser::Parse() {
continue;
}
- if (Tok.is(tok::command)) {
+ if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBriefCommand) {
FirstParagraphOrBrief.clear();
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index e7e40fd1090f..e24d542c9623 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -15,9 +15,21 @@ namespace comments {
#include "clang/AST/CommentCommandInfo.inc"
-CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) :
- NextID(llvm::array_lengthof(Commands)), Allocator(Allocator)
-{ }
+CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
+ const CommentOptions &CommentOptions) :
+ NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
+ registerCommentOptions(CommentOptions);
+}
+
+void CommandTraits::registerCommentOptions(
+ const CommentOptions &CommentOptions) {
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = CommentOptions.BlockCommandNames.begin(),
+ E = CommentOptions.BlockCommandNames.end();
+ I != E; I++) {
+ registerBlockCommand(*I);
+ }
+}
const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
@@ -31,7 +43,7 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
-const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) {
+CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
memcpy(Name, CommandName.data(), CommandName.size());
Name[CommandName.size()] = '\0';
@@ -40,13 +52,25 @@ const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName)
CommandInfo *Info = new (Allocator) CommandInfo();
Info->Name = Name;
Info->ID = NextID++;
- Info->IsUnknownCommand = true;
RegisteredCommands.push_back(Info);
return Info;
}
+const CommandInfo *CommandTraits::registerUnknownCommand(
+ StringRef CommandName) {
+ CommandInfo *Info = createCommandInfoWithName(CommandName);
+ Info->IsUnknownCommand = true;
+ return Info;
+}
+
+const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
+ CommandInfo *Info = createCommandInfoWithName(CommandName);
+ Info->IsBlockCommand = true;
+ return Info;
+}
+
const CommandInfo *CommandTraits::getBuiltinCommandInfo(
unsigned CommandID) {
if (CommandID < llvm::array_lengthof(Commands))
diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp
deleted file mode 100644
index 19d24b2f3a03..000000000000
--- a/lib/AST/CommentDumper.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/CommentVisitor.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace clang {
-namespace comments {
-
-namespace {
-class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
- raw_ostream &OS;
- const CommandTraits *Traits;
- const SourceManager *SM;
-
- /// The \c FullComment parent of the comment being dumped.
- const FullComment *FC;
-
- unsigned IndentLevel;
-
-public:
- CommentDumper(raw_ostream &OS,
- const CommandTraits *Traits,
- const SourceManager *SM,
- const FullComment *FC) :
- OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0)
- { }
-
- void dumpIndent() const {
- for (unsigned i = 1, e = IndentLevel; i < e; ++i)
- OS << " ";
- }
-
- void dumpLocation(SourceLocation Loc) {
- if (SM)
- Loc.print(OS, *SM);
- }
-
- void dumpSourceRange(const Comment *C);
-
- void dumpComment(const Comment *C);
-
- void dumpSubtree(const Comment *C);
-
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
-
- void visitFullComment(const FullComment *C);
-
- const char *getCommandName(unsigned CommandID) {
- if (Traits)
- return Traits->getCommandInfo(CommandID)->Name;
- const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
- if (Info)
- return Info->Name;
- return "<not a builtin command>";
- }
-};
-
-void CommentDumper::dumpSourceRange(const Comment *C) {
- if (!SM)
- return;
-
- SourceRange SR = C->getSourceRange();
-
- OS << " <";
- dumpLocation(SR.getBegin());
- if (SR.getBegin() != SR.getEnd()) {
- OS << ", ";
- dumpLocation(SR.getEnd());
- }
- OS << ">";
-}
-
-void CommentDumper::dumpComment(const Comment *C) {
- dumpIndent();
- OS << "(" << C->getCommentKindName()
- << " " << (const void *) C;
- dumpSourceRange(C);
-}
-
-void CommentDumper::dumpSubtree(const Comment *C) {
- ++IndentLevel;
- if (C) {
- visit(C);
- for (Comment::child_iterator I = C->child_begin(),
- E = C->child_end();
- I != E; ++I) {
- OS << '\n';
- dumpSubtree(*I);
- }
- OS << ')';
- } else {
- dumpIndent();
- OS << "<<<NULL>>>";
- }
- --IndentLevel;
-}
-
-void CommentDumper::visitTextComment(const TextComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- OS << " RenderNormal";
- break;
- case InlineCommandComment::RenderBold:
- OS << " RenderBold";
- break;
- case InlineCommandComment::RenderMonospaced:
- OS << " RenderMonospaced";
- break;
- case InlineCommandComment::RenderEmphasized:
- OS << " RenderEmphasized";
- break;
- }
-
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
- OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
-}
-
-void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << C->getTagName() << "\"";
- if (C->getNumAttrs() != 0) {
- OS << " Attrs: ";
- for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
- const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
- OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
- }
- }
- if (C->isSelfClosing())
- OS << " SelfClosing";
-}
-
-void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << C->getTagName() << "\"";
-}
-
-void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
- dumpComment(C);
-}
-
-void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
- OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
-}
-
-void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
- dumpComment(C);
-
- OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
-
- if (C->isDirectionExplicit())
- OS << " explicitly";
- else
- OS << " implicitly";
-
- if (C->hasParamName()) {
- if (C->isParamIndexValid())
- OS << " Param=\"" << C->getParamName(FC) << "\"";
- else
- OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
- }
-
- if (C->isParamIndexValid())
- OS << " ParamIndex=" << C->getParamIndex();
-}
-
-void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
- dumpComment(C);
-
- if (C->hasParamName()) {
- if (C->isPositionValid())
- OS << " Param=\"" << C->getParamName(FC) << "\"";
- else
- OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
- }
-
- if (C->isPositionValid()) {
- OS << " Position=<";
- for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
- OS << C->getIndex(i);
- if (i != e - 1)
- OS << ", ";
- }
- OS << ">";
- }
-}
-
-void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
- " CloseName=\"" << C->getCloseName() << "\"";
-}
-
-void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitFullComment(const FullComment *C) {
- dumpComment(C);
-}
-
-} // unnamed namespace
-
-void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
- const SourceManager *SM) const {
- const FullComment *FC = dyn_cast<FullComment>(this);
- CommentDumper D(llvm::errs(), Traits, SM, FC);
- D.dumpSubtree(this);
- llvm::errs() << '\n';
-}
-
-} // end namespace comments
-} // end namespace clang
-
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 31a09f71d993..1194520bf360 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -1,7 +1,9 @@
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentCommandTraits.h"
-#include "clang/Basic/ConvertUTF.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
@@ -13,34 +15,46 @@ void Token::dump(const Lexer &L, const SourceManager &SM) const {
llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n";
}
-namespace {
-bool isHTMLNamedCharacterReferenceCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+static inline bool isHTMLNamedCharacterReferenceCharacter(char C) {
+ return isLetter(C);
}
-bool isHTMLDecimalCharacterReferenceCharacter(char C) {
- return C >= '0' && C <= '9';
+static inline bool isHTMLDecimalCharacterReferenceCharacter(char C) {
+ return isDigit(C);
}
-bool isHTMLHexCharacterReferenceCharacter(char C) {
- return (C >= '0' && C <= '9') ||
- (C >= 'a' && C <= 'f') ||
- (C >= 'A' && C <= 'F');
+static inline bool isHTMLHexCharacterReferenceCharacter(char C) {
+ return isHexDigit(C);
}
+static inline StringRef convertCodePointToUTF8(
+ llvm::BumpPtrAllocator &Allocator,
+ unsigned CodePoint) {
+ char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
+ char *ResolvedPtr = Resolved;
+ if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
+ return StringRef(Resolved, ResolvedPtr - Resolved);
+ else
+ return StringRef();
+}
+
+namespace {
+
#include "clang/AST/CommentHTMLTags.inc"
+#include "clang/AST/CommentHTMLNamedCharacterReferences.inc"
} // unnamed namespace
StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const {
+ // Fast path, first check a few most widely used named character references.
return llvm::StringSwitch<StringRef>(Name)
.Case("amp", "&")
.Case("lt", "<")
.Case("gt", ">")
.Case("quot", "\"")
.Case("apos", "\'")
- .Default("");
+ // Slow path.
+ .Default(translateHTMLNamedCharacterReferenceToUTF8(Name));
}
StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
@@ -50,13 +64,7 @@ StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
CodePoint *= 10;
CodePoint += Name[i] - '0';
}
-
- char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
- char *ResolvedPtr = Resolved;
- if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
- return StringRef(Resolved, ResolvedPtr - Resolved);
- else
- return StringRef();
+ return convertCodePointToUTF8(Allocator, CodePoint);
}
StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
@@ -65,20 +73,9 @@ StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
CodePoint *= 16;
const char C = Name[i];
assert(isHTMLHexCharacterReferenceCharacter(C));
- if (C >= '0' && C <= '9')
- CodePoint += Name[i] - '0';
- else if (C >= 'a' && C <= 'f')
- CodePoint += Name[i] - 'a' + 10;
- else
- CodePoint += Name[i] - 'A' + 10;
+ CodePoint += llvm::hexDigitValue(C);
}
-
- char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
- char *ResolvedPtr = Resolved;
- if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
- return StringRef(Resolved, ResolvedPtr - Resolved);
- else
- return StringRef();
+ return convertCodePointToUTF8(Allocator, CodePoint);
}
void Lexer::skipLineStartingDecorations() {
@@ -99,7 +96,7 @@ void Lexer::skipLineStartingDecorations() {
return;
char C = *NewBufferPtr;
- while (C == ' ' || C == '\t' || C == '\f' || C == '\v') {
+ while (isHorizontalWhitespace(C)) {
NewBufferPtr++;
if (NewBufferPtr == CommentEnd)
return;
@@ -119,8 +116,7 @@ namespace {
/// Returns pointer to the first newline character in the string.
const char *findNewline(const char *BufferPtr, const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
- const char C = *BufferPtr;
- if (C == '\n' || C == '\r')
+ if (isVerticalWhitespace(*BufferPtr))
return BufferPtr;
}
return BufferEnd;
@@ -169,14 +165,11 @@ const char *skipHexCharacterReference(const char *BufferPtr,
}
bool isHTMLIdentifierStartingCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+ return isLetter(C);
}
bool isHTMLIdentifierCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9');
+ return isAlphanumeric(C);
}
const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) {
@@ -205,15 +198,6 @@ const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd)
return BufferEnd;
}
-bool isHorizontalWhitespace(char C) {
- return C == ' ' || C == '\t' || C == '\f' || C == '\v';
-}
-
-bool isWhitespace(char C) {
- return C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\f' || C == '\v';
-}
-
const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
if (!isWhitespace(*BufferPtr))
@@ -227,14 +211,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) {
}
bool isCommandNameStartCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+ return isLetter(C);
}
bool isCommandNameCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9');
+ return isAlphanumeric(C);
}
const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
@@ -250,12 +231,10 @@ const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) {
const char *CurPtr = BufferPtr;
while (CurPtr != BufferEnd) {
- char C = *CurPtr;
- while (C != '\n' && C != '\r') {
+ while (!isVerticalWhitespace(*CurPtr)) {
CurPtr++;
if (CurPtr == BufferEnd)
return BufferEnd;
- C = *CurPtr;
}
// We found a newline, check if it is escaped.
const char *EscapePtr = CurPtr - 1;
@@ -319,6 +298,11 @@ void Lexer::lexCommentText(Token &T) {
switch(*TokenPtr) {
case '\\':
case '@': {
+ // Commands that start with a backslash and commands that start with
+ // 'at' have equivalent semantics. But we keep information about the
+ // exact syntax in AST for comments.
+ tok::TokenKind CommandKind =
+ (*TokenPtr == '@') ? tok::at_command : tok::backslash_command;
TokenPtr++;
if (TokenPtr == CommentEnd) {
formTextToken(T, TokenPtr);
@@ -379,7 +363,7 @@ void Lexer::lexCommentText(Token &T) {
setupAndLexVerbatimLine(T, TokenPtr, Info);
return;
}
- formTokenWithChars(T, TokenPtr, tok::command);
+ formTokenWithChars(T, TokenPtr, CommandKind);
T.setCommandID(Info->getID());
return;
}
@@ -415,15 +399,12 @@ void Lexer::lexCommentText(Token &T) {
return;
default: {
- while (true) {
- TokenPtr++;
- if (TokenPtr == CommentEnd)
- break;
- const char C = *TokenPtr;
- if(C == '\n' || C == '\r' ||
- C == '\\' || C == '@' || C == '&' || C == '<')
- break;
- }
+ size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr).
+ find_first_of("\n\r\\@&<");
+ if (End != StringRef::npos)
+ TokenPtr += End;
+ else
+ TokenPtr = CommentEnd;
formTextToken(T, TokenPtr);
return;
}
@@ -446,13 +427,11 @@ void Lexer::setupAndLexVerbatimBlock(Token &T,
// If there is a newline following the verbatim opening command, skip the
// newline so that we don't create an tok::verbatim_block_line with empty
// text content.
- if (BufferPtr != CommentEnd) {
- const char C = *BufferPtr;
- if (C == '\n' || C == '\r') {
- BufferPtr = skipNewline(BufferPtr, CommentEnd);
- State = LS_VerbatimBlockBody;
- return;
- }
+ if (BufferPtr != CommentEnd &&
+ isVerticalWhitespace(*BufferPtr)) {
+ BufferPtr = skipNewline(BufferPtr, CommentEnd);
+ State = LS_VerbatimBlockBody;
+ return;
}
State = LS_VerbatimBlockFirstLine;
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index d0a84741b6f2..09912c618864 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -8,9 +8,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentParser.h"
-#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/CommentSema.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/ErrorHandling.h"
@@ -109,11 +110,6 @@ class TextTokenRetokenizer {
return true;
}
- static bool isWhitespace(char C) {
- return C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\f' || C == '\v';
- }
-
void consumeWhitespace() {
while (!isEnd()) {
if (isWhitespace(peek()))
@@ -175,8 +171,7 @@ public:
memcpy(TextPtr, WordText.c_str(), Length + 1);
StringRef Text = StringRef(TextPtr, Length);
- formTokenWithChars(Tok, Loc, WordBegin,
- Pos.BufferPtr - WordBegin, Text);
+ formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
return true;
}
@@ -305,7 +300,7 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
}
BlockCommandComment *Parser::parseBlockCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
ParamCommandComment *PC;
TParamCommandComment *TPC;
@@ -313,25 +308,29 @@ BlockCommandComment *Parser::parseBlockCommand() {
bool IsParam = false;
bool IsTParam = false;
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ CommandMarkerKind CommandMarker =
+ Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At;
if (Info->IsParamCommand) {
IsParam = true;
PC = S.actOnParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
- } if (Info->IsTParamCommand) {
+ Tok.getCommandID(),
+ CommandMarker);
+ } else if (Info->IsTParamCommand) {
IsTParam = true;
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
} else {
BC = S.actOnBlockCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
}
consumeToken();
- if (Tok.is(tok::command) &&
- Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) {
+ if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
ParagraphComment *Paragraph = S.actOnParagraphComment(
@@ -363,10 +362,28 @@ BlockCommandComment *Parser::parseBlockCommand() {
Retokenizer.putBackLeftoverTokens();
}
- BlockContentComment *Block = parseParagraphOrBlockCommand();
- // Since we have checked for a block command, we should have parsed a
- // paragraph.
- ParagraphComment *Paragraph = cast<ParagraphComment>(Block);
+ // If there's a block command ahead, we will attach an empty paragraph to
+ // this command.
+ bool EmptyParagraph = false;
+ if (isTokBlockCommand())
+ EmptyParagraph = true;
+ else if (Tok.is(tok::newline)) {
+ Token PrevTok = Tok;
+ consumeToken();
+ EmptyParagraph = isTokBlockCommand();
+ putBack(PrevTok);
+ }
+
+ ParagraphComment *Paragraph;
+ if (EmptyParagraph)
+ Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>());
+ else {
+ BlockContentComment *Block = parseParagraphOrBlockCommand();
+ // Since we have checked for a block command, we should have parsed a
+ // paragraph.
+ Paragraph = cast<ParagraphComment>(Block);
+ }
+
if (IsParam) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
@@ -380,7 +397,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
}
InlineCommandComment *Parser::parseInlineCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
const Token CommandTok = Tok;
consumeToken();
@@ -547,7 +564,8 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
continue;
- case tok::command: {
+ case tok::backslash_command:
+ case tok::at_command: {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBlockCommand) {
if (Content.size() == 0)
@@ -557,6 +575,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
if (Info->IsVerbatimBlockEndCommand) {
Diag(Tok.getLocation(),
diag::warn_verbatim_block_end_without_start)
+ << Tok.is(tok::at_command)
<< Info->Name
<< SourceRange(Tok.getLocation(), Tok.getEndLocation());
consumeToken();
@@ -694,7 +713,8 @@ BlockContentComment *Parser::parseBlockContent() {
switch (Tok.getKind()) {
case tok::text:
case tok::unknown_command:
- case tok::command:
+ case tok::backslash_command:
+ case tok::at_command:
case tok::html_start_tag:
case tok::html_end_tag:
return parseParagraphOrBlockCommand();
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 08ecb3a994d7..e0138d5f3f27 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -8,14 +8,15 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
namespace clang {
namespace comments {
@@ -28,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), ReturnsCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
+ HeaderfileCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -45,10 +47,16 @@ ParagraphComment *Sema::actOnParagraphComment(
return new (Allocator) ParagraphComment(Content);
}
-BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
- return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
+BlockCommandComment *Sema::actOnBlockCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
+ BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
+ CommandID,
+ CommandMarker);
+ checkContainerDecl(BC);
+ return BC;
}
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
@@ -65,20 +73,139 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
checkDeprecatedCommand(Command);
}
-ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+ParamCommandComment *Sema::actOnParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
ParamCommandComment *Command =
- new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
}
+void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsFunctionDeclarationCommand)
+ return;
+
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_function:
+ DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_functiongroup:
+ DiagSelect = !isAnyFunctionDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_method:
+ DiagSelect = !isObjCMethodDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_methodgroup:
+ DiagSelect = !isObjCMethodDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_callback:
+ DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDeclarationCommand)
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_class:
+ DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_interface:
+ DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_protocol:
+ DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_struct:
+ DiagSelect = !isClassOrStructDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_union:
+ DiagSelect = !isUnionDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_classdesign:
+ DiagSelect = 1;
+ break;
+ case CommandTraits::KCI_coclass:
+ DiagSelect = 2;
+ break;
+ case CommandTraits::KCI_dependency:
+ DiagSelect = 3;
+ break;
+ case CommandTraits::KCI_helper:
+ DiagSelect = 4;
+ break;
+ case CommandTraits::KCI_helperclass:
+ DiagSelect = 5;
+ break;
+ case CommandTraits::KCI_helps:
+ DiagSelect = 6;
+ break;
+ case CommandTraits::KCI_instancesize:
+ DiagSelect = 7;
+ break;
+ case CommandTraits::KCI_ownership:
+ DiagSelect = 8;
+ break;
+ case CommandTraits::KCI_performance:
+ DiagSelect = 9;
+ break;
+ case CommandTraits::KCI_security:
+ DiagSelect = 10;
+ break;
+ case CommandTraits::KCI_superclass:
+ DiagSelect = 11;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
@@ -158,15 +285,19 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
}
-TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+TParamCommandComment *Sema::actOnTParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
TParamCommandComment *Command =
- new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isTemplateOrSpecialization())
Diag(Command->getLocation(),
diag::warn_doc_tparam_not_attached_to_a_template_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
@@ -324,12 +455,15 @@ VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) {
- return new (Allocator) VerbatimLineComment(
+ VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
CommandID,
TextBegin,
Text);
+ checkFunctionDeclVerbatimLine(VL);
+ checkContainerDeclVerbatimLine(VL);
+ return VL;
}
HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
@@ -430,6 +564,7 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
if (!DiagLoc.isValid())
DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -457,14 +592,19 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_attached_to_a_void_function)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< DiagKind
<< Command->getSourceRange();
}
return;
}
+ else if (isObjCPropertyDecl())
+ return;
+
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -484,6 +624,12 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
return;
}
PrevCommand = ReturnsCommand;
+ } else if (Info->IsHeaderfileCommand) {
+ if (!HeaderfileCommand) {
+ HeaderfileCommand = Command;
+ return;
+ }
+ PrevCommand = HeaderfileCommand;
} else {
// We don't want to check this command for duplicates.
return;
@@ -491,15 +637,18 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
StringRef CommandName = Command->getCommandName(Traits);
StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
+ << Command->getCommandMarker()
<< CommandName
<< Command->getSourceRange();
if (CommandName == PrevCommandName)
Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< PrevCommand->getSourceRange();
else
Diag(PrevCommand->getLocation(),
diag::note_doc_block_command_previous_alias)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< CommandName;
}
@@ -559,11 +708,11 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
return;
}
- llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
+ SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
// Comment AST nodes that correspond to \c ParamVars for which we have
// found a \\param command or NULL if no documentation was found so far.
- llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
+ SmallVector<ParamCommandComment *, 8> ParamVarDocs;
ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
ParamVarDocs.resize(ParamVars.size(), NULL);
@@ -596,7 +745,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
}
// Find parameter declarations that have no corresponding \\param.
- llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
+ SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
if (!ParamVarDocs[i])
OrphanedParamDecls.push_back(ParamVars[i]);
@@ -645,6 +794,40 @@ bool Sema::isFunctionDecl() {
return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
}
+bool Sema::isAnyFunctionDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCMethodDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
+/// function decl.
+bool Sema::isFunctionPointerVarDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
+ if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
+ QualType QT = VD->getType();
+ return QT->isFunctionPointerType();
+ }
+ }
+ return false;
+}
+
+bool Sema::isObjCPropertyDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
+}
+
bool Sema::isTemplateOrSpecialization() {
if (!ThisDeclInfo)
return false;
@@ -653,6 +836,54 @@ bool Sema::isTemplateOrSpecialization() {
return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
}
+bool Sema::isRecordLikeDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return isUnionDecl() || isClassOrStructDecl()
+ || isObjCInterfaceDecl() || isObjCProtocolDecl();
+}
+
+bool Sema::isUnionDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
+ return RD->isUnion();
+ return false;
+}
+
+bool Sema::isClassOrStructDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
+ !isUnionDecl();
+}
+
+bool Sema::isObjCInterfaceDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCProtocolDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
+}
+
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 7b13755979f1..bf807aeb1d69 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -12,23 +12,24 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Module.h"
#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;
@@ -37,17 +38,163 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
-static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+// Visibility rules aren't rigorously externally specified, but here
+// are the basic principles behind what we implement:
+//
+// 1. An explicit visibility attribute is generally a direct expression
+// of the user's intent and should be honored. Only the innermost
+// visibility attribute applies. If no visibility attribute applies,
+// global visibility settings are considered.
+//
+// 2. There is one caveat to the above: on or in a template pattern,
+// an explicit visibility attribute is just a default rule, and
+// visibility can be decreased by the visibility of template
+// arguments. But this, too, has an exception: an attribute on an
+// explicit specialization or instantiation causes all the visibility
+// restrictions of the template arguments to be ignored.
+//
+// 3. A variable that does not otherwise have explicit visibility can
+// be restricted by the visibility of its type.
+//
+// 4. A visibility restriction is explicit if it comes from an
+// attribute (or something like it), not a global visibility setting.
+// When emitting a reference to an external symbol, visibility
+// restrictions are ignored unless they are explicit.
+//
+// 5. When computing the visibility of a non-type, including a
+// non-type member of a class, only non-type visibility restrictions
+// are considered: the 'visibility' attribute, global value-visibility
+// settings, and a few special cases like __private_extern.
+//
+// 6. When computing the visibility of a type, including a type member
+// of a class, only type visibility restrictions are considered:
+// the 'type_visibility' attribute and global type-visibility settings.
+// However, a 'visibility' attribute counts as a 'type_visibility'
+// attribute on any declaration that only has the former.
+//
+// The visibility of a "secondary" entity, like a template argument,
+// is computed using the kind of that entity, not the kind of the
+// primary entity for which we are computing visibility. For example,
+// the visibility of a specialization of either of these templates:
+// template <class T, bool (&compare)(T, X)> bool has_match(list<T>, X);
+// template <class T, bool (&compare)(T, X)> class matcher;
+// is restricted according to the type visibility of the argument 'T',
+// the type visibility of 'bool(&)(T,X)', and the value visibility of
+// the argument function 'compare'. That 'has_match' is a value
+// and 'matcher' is a type only matters when looking for attributes
+// and settings from the immediate context.
+
+const unsigned IgnoreExplicitVisibilityBit = 2;
+
+/// Kinds of LV computation. The linkage side of the computation is
+/// always the same, but different things can change how visibility is
+/// computed.
+enum LVComputationKind {
+ /// Do an LV computation for, ultimately, a type.
+ /// Visibility may be restricted by type visibility settings and
+ /// the visibility of template arguments.
+ LVForType = NamedDecl::VisibilityForType,
+
+ /// Do an LV computation for, ultimately, a non-type declaration.
+ /// Visibility may be restricted by value visibility settings and
+ /// the visibility of template arguments.
+ LVForValue = NamedDecl::VisibilityForValue,
+
+ /// Do an LV computation for, ultimately, a type that already has
+ /// some sort of explicit visibility. Visibility may only be
+ /// restricted by the visibility of template arguments.
+ LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
+
+ /// Do an LV computation for, ultimately, a non-type declaration
+ /// that already has some sort of explicit visibility. Visibility
+ /// may only be restricted by the visibility of template arguments.
+ LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
+};
+
+/// Does this computation kind permit us to consider additional
+/// visibility settings from attributes and the like?
+static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
+ return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0);
+}
+
+/// Given an LVComputationKind, return one of the same type/value sort
+/// that records that it already has explicit visibility.
+static LVComputationKind
+withExplicitVisibilityAlready(LVComputationKind oldKind) {
+ LVComputationKind newKind =
+ static_cast<LVComputationKind>(unsigned(oldKind) |
+ IgnoreExplicitVisibilityBit);
+ assert(oldKind != LVForType || newKind == LVForExplicitType);
+ assert(oldKind != LVForValue || newKind == LVForExplicitValue);
+ assert(oldKind != LVForExplicitType || newKind == LVForExplicitType);
+ assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue);
+ return newKind;
+}
+
+static Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+ LVComputationKind kind) {
+ assert(!hasExplicitVisibilityAlready(kind) &&
+ "asking for explicit visibility when we shouldn't be");
+ return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind);
+}
+
+/// Is the given declaration a "type" or a "value" for the purposes of
+/// visibility computation?
+static bool usesTypeVisibility(const NamedDecl *D) {
+ return isa<TypeDecl>(D) ||
+ isa<ClassTemplateDecl>(D) ||
+ isa<ObjCInterfaceDecl>(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
+isExplicitMemberSpecialization(const T *D) {
+ if (const MemberSpecializationInfo *member =
+ D->getMemberSpecializationInfo()) {
+ return member->isExplicitSpecialization();
+ }
+ return false;
+}
+
+/// For templates, this question is easier: a member template can't be
+/// explicitly instantiated, so there's a single bit indicating whether
+/// or not this is an explicit member specialization.
+static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) {
+ return D->isMemberSpecialization();
+}
+
+/// Given a visibility attribute, return the explicit visibility
+/// associated with it.
+template <class T>
+static Visibility getVisibilityFromAttr(const T *attr) {
+ switch (attr->getVisibility()) {
+ case T::Default:
+ return DefaultVisibility;
+ case T::Hidden:
+ return HiddenVisibility;
+ case T::Protected:
+ return ProtectedVisibility;
+ }
+ llvm_unreachable("bad visibility kind");
+}
+
+/// Return the explicit visibility of the given declaration.
+static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
+ NamedDecl::ExplicitVisibilityKind kind) {
+ // If we're ultimately computing the visibility of a type, look for
+ // a 'type_visibility' attribute before looking for 'visibility'.
+ if (kind == NamedDecl::VisibilityForType) {
+ if (const TypeVisibilityAttr *A = D->getAttr<TypeVisibilityAttr>()) {
+ return getVisibilityFromAttr(A);
+ }
+ }
+
// If this declaration has an explicit visibility attribute, use it.
if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
- switch (A->getVisibility()) {
- case VisibilityAttr::Default:
- return DefaultVisibility;
- case VisibilityAttr::Hidden:
- return HiddenVisibility;
- case VisibilityAttr::Protected:
- return ProtectedVisibility;
- }
+ return getVisibilityFromAttr(A);
}
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
@@ -61,43 +208,61 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
return DefaultVisibility;
}
- return llvm::Optional<Visibility>();
-}
-
-typedef NamedDecl::LinkageInfo LinkageInfo;
-
-static LinkageInfo getLVForType(QualType T) {
- std::pair<Linkage,Visibility> P = T->getLinkageAndVisibility();
- return LinkageInfo(P.first, P.second, T->isVisibilityExplicit());
+ return None;
}
/// \brief Get the most restrictive linkage for the types in the given
-/// template parameter list.
+/// template parameter list. For visibility purposes, template
+/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *Params) {
- LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
- for (TemplateParameterList::const_iterator P = Params->begin(),
- PEnd = Params->end();
+getLVForTemplateParameterList(const TemplateParameterList *params) {
+ LinkageInfo LV;
+ for (TemplateParameterList::const_iterator P = params->begin(),
+ PEnd = params->end();
P != PEnd; ++P) {
+
+ // Template type parameters are the most common and never
+ // contribute to visibility, pack or not.
+ 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 (NTTP->isExpandedParameterPack()) {
- for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
- QualType T = NTTP->getExpansionType(I);
- if (!T->isDependentType())
- LV.merge(getLVForType(T));
+ // Handle the non-pack case first.
+ if (!NTTP->isExpandedParameterPack()) {
+ if (!NTTP->getType()->isDependentType()) {
+ LV.merge(NTTP->getType()->getLinkageAndVisibility());
}
continue;
}
- if (!NTTP->getType()->isDependentType()) {
- LV.merge(getLVForType(NTTP->getType()));
- continue;
+ // Look at all the types in an expanded pack.
+ for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) {
+ QualType type = NTTP->getExpansionType(i);
+ if (!type->isDependentType())
+ LV.merge(type->getLinkageAndVisibility());
}
+ continue;
}
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(*P)) {
+ // Template template parameters can be restricted by their
+ // template parameters, recursively.
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+
+ // Handle the non-pack case first.
+ if (!TTP->isExpandedParameterPack()) {
LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ continue;
+ }
+
+ // Look at all expansions in an expanded pack.
+ for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
+ i != n; ++i) {
+ LV.merge(getLVForTemplateParameterList(
+ TTP->getExpansionTemplateParameters(i)));
}
}
@@ -105,67 +270,177 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) {
}
/// getLVForDecl - Get the linkage and visibility for the given declaration.
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate);
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation);
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
-static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs,
- bool OnlyTemplate) {
- LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
+///
+/// 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) {
+ LinkageInfo LV;
- for (unsigned I = 0; I != NumArgs; ++I) {
- switch (Args[I].getKind()) {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ const TemplateArgument &arg = args[i];
+ switch (arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
- break;
+ continue;
case TemplateArgument::Type:
- LV.mergeWithMin(getLVForType(Args[I].getAsType()));
- break;
+ LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ continue;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
- LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
- break;
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
+ assert(!usesTypeVisibility(ND));
+ LV.merge(getLVForDecl(ND, LVForValue));
+ }
+ continue;
case TemplateArgument::NullPtr:
- LV.mergeWithMin(getLVForType(Args[I].getNullPtrType()));
- break;
+ LV.merge(arg.getNullPtrType()->getLinkageAndVisibility());
+ continue;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template
- = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV.mergeWithMin(getLVForDecl(Template, OnlyTemplate));
- break;
+ = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ LV.merge(getLVForDecl(Template, LVForValue));
+ continue;
case TemplateArgument::Pack:
- LV.mergeWithMin(getLVForTemplateArgumentList(Args[I].pack_begin(),
- Args[I].pack_size(),
- OnlyTemplate));
- break;
+ LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray()));
+ continue;
}
+ llvm_unreachable("bad template argument kind");
}
return LV;
}
static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
- bool OnlyTemplate) {
- return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), OnlyTemplate);
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
+ return getLVForTemplateArgumentList(TArgs.asArray());
}
-static bool shouldConsiderTemplateVis(const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *spec) {
- return !fn->hasAttr<VisibilityAttr>() || spec->isExplicitSpecialization();
+static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo) {
+ // Include visibility from the template parameters and arguments
+ // only if this is not an explicit instantiation or specialization
+ // with direct explicit visibility. (Implicit instantiations won't
+ // have a direct attribute.)
+ if (!specInfo->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ return !fn->hasAttr<VisibilityAttr>();
+}
+
+/// Merge in template-related linkage and visibility for the given
+/// function template specialization.
+///
+/// We don't need a computation kind here because we can assume
+/// LVForValue.
+///
+/// \param[out] LV the computation to use for the parent
+static void
+mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo) {
+ bool considerVisibility =
+ shouldConsiderTemplateVisibility(fn, specInfo);
+
+ // Merge information from the template parameters.
+ FunctionTemplateDecl *temp = specInfo->getTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+ // Merge information from the template arguments.
+ const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
+}
+
+/// Does the given declaration have a direct visibility attribute
+/// that would match the given rules?
+static bool hasDirectVisibilityAttribute(const NamedDecl *D,
+ LVComputationKind computation) {
+ switch (computation) {
+ case LVForType:
+ case LVForExplicitType:
+ if (D->hasAttr<TypeVisibilityAttr>())
+ return true;
+ // fallthrough
+ case LVForValue:
+ case LVForExplicitValue:
+ if (D->hasAttr<VisibilityAttr>())
+ return true;
+ return false;
+ }
+ llvm_unreachable("bad visibility computation kind");
+}
+
+/// Should we consider visibility associated with the template
+/// arguments and parameters of the given class template specialization?
+static bool shouldConsiderTemplateVisibility(
+ const ClassTemplateSpecializationDecl *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).
+ //
+ // Furthermore, we want to ignore template parameters and arguments
+ // for an explicit specialization when computing the visibility of a
+ // member thereof with explicit visibility.
+ //
+ // This is a bit complex; let's unpack it.
+ //
+ // An explicit class specialization is an independent, top-level
+ // declaration. As such, if it or any of its members has an
+ // explicit visibility attribute, that must directly express the
+ // user's intent, and we should honor it. The same logic applies to
+ // an explicit instantiation of a member of such a thing.
+
+ // Fast path: if this is not an explicit instantiation or
+ // specialization, we always want to consider template-related
+ // visibility restrictions.
+ if (!spec->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ // This is the 'member thereof' check.
+ if (spec->isExplicitSpecialization() &&
+ hasExplicitVisibilityAlready(computation))
+ return false;
+
+ return !hasDirectVisibilityAttribute(spec, computation);
}
-static bool
-shouldConsiderTemplateVis(const ClassTemplateSpecializationDecl *d) {
- return !d->hasAttr<VisibilityAttr>() || d->isExplicitSpecialization();
+/// Merge in template-related linkage and visibility for the given
+/// class template specialization.
+static void mergeTemplateLV(LinkageInfo &LV,
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
+
+ // Merge information from the template parameters, but ignore
+ // visibility if we're only considering template arguments.
+
+ ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ 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);
+ LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
static bool useInlineVisibilityHidden(const NamedDecl *D) {
@@ -196,8 +471,13 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>();
}
+template <typename T> static bool isInExternCContext(T *D) {
+ const T *First = D->getFirstDeclaration();
+ return First->getDeclContext()->isExternCContext();
+}
+
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
- bool OnlyTemplate) {
+ LVComputationKind computation) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -218,26 +498,24 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// declared to have external linkage; or (there is no equivalent in C99)
if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstQualified() &&
- !Var->getType().isVolatileQualified() &&
- Var->getStorageClass() != SC_Extern &&
- Var->getStorageClass() != SC_PrivateExtern) {
- bool FoundExtern = false;
- for (const VarDecl *PrevVar = Var->getPreviousDecl();
- PrevVar && !FoundExtern;
- PrevVar = PrevVar->getPreviousDecl())
- if (isExternalLinkage(PrevVar->getLinkage()))
- FoundExtern = true;
-
- if (!FoundExtern)
- return LinkageInfo::internal();
- }
- if (Var->getStorageClass() == SC_None) {
+ !Var->getType().isVolatileQualified()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
- for (; PrevVar; PrevVar = PrevVar->getPreviousDecl())
- if (PrevVar->getStorageClass() == SC_PrivateExtern)
- break;
if (PrevVar)
return PrevVar->getLinkageAndVisibility();
+
+ if (Var->getStorageClass() != SC_Extern &&
+ Var->getStorageClass() != SC_PrivateExtern)
+ return LinkageInfo::internal();
+ }
+
+ for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar;
+ PrevVar = PrevVar->getPreviousDecl()) {
+ if (PrevVar->getStorageClass() == SC_PrivateExtern &&
+ Var->getStorageClass() == SC_None)
+ return PrevVar->getLinkageAndVisibility();
+ // Explicitly declared static.
+ if (PrevVar->getStorageClass() == SC_Static)
+ return LinkageInfo::internal();
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -251,7 +529,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
Function = cast<FunctionDecl>(D);
// Explicitly declared static.
- if (Function->getStorageClass() == SC_Static)
+ if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// - a data member of an anonymous union.
@@ -262,8 +540,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
- if ((!Var || !Var->getDeclContext()->isExternCContext()) &&
- (!Func || !Func->getDeclContext()->isExternCContext()))
+ if ((!Var || !isInExternCContext(Var)) &&
+ (!Func || !isInExternCContext(Func)))
return LinkageInfo::uniqueExternal();
}
@@ -275,31 +553,41 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// external.
LinkageInfo LV;
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
LV.mergeVisibility(*Vis, true);
} else {
// If we're declared in a namespace with a visibility attribute,
- // use that namespace's visibility, but don't call it explicit.
+ // use that namespace's visibility, and it still counts as explicit.
for (const DeclContext *DC = D->getDeclContext();
!isa<TranslationUnitDecl>(DC);
DC = DC->getParent()) {
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) continue;
- if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(ND, computation)) {
LV.mergeVisibility(*Vis, true);
break;
}
}
}
- }
- if (!OnlyTemplate) {
- LV.mergeVisibility(Context.getLangOpts().getVisibilityMode());
- // If we're paying attention to global visibility, apply
- // -finline-visibility-hidden if this is an inline method.
- if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
- LV.mergeVisibility(HiddenVisibility, true);
+ // Add in global settings if the above didn't give us direct visibility.
+ if (!LV.isVisibilityExplicit()) {
+ // Use global type/value visibility as appropriate.
+ Visibility globalVisibility;
+ if (computation == LVForValue) {
+ globalVisibility = Context.getLangOpts().getValueVisibilityMode();
+ } else {
+ assert(computation == LVForType);
+ globalVisibility = Context.getLangOpts().getTypeVisibilityMode();
+ }
+ LV.mergeVisibility(globalVisibility, /*explicit*/ false);
+
+ // If we're paying attention to global visibility, apply
+ // -finline-visibility-hidden if this is an inline method.
+ if (useInlineVisibilityHidden(D))
+ LV.mergeVisibility(HiddenVisibility, true);
+ }
}
// C++ [basic.link]p4:
@@ -330,12 +618,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOpts().CPlusPlus &&
- !Var->getDeclContext()->isExternCContext()) {
- LinkageInfo TypeLV = getLVForType(Var->getType());
- if (TypeLV.linkage() != ExternalLinkage)
+ if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) {
+ LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
+ if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
- LV.mergeVisibility(TypeLV);
+ if (!LV.isVisibilityExplicit())
+ LV.mergeVisibility(TypeLV);
}
if (Var->getStorageClass() == SC_PrivateExtern)
@@ -355,30 +643,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Function->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
- // C99 6.2.2p5:
- // If the declaration of an identifier for a function has no
- // storage-class specifier, its linkage is determined exactly
- // as if it were declared with the storage-class specifier
- // extern.
- if (!Context.getLangOpts().CPlusPlus &&
- (Function->getStorageClass() == SC_Extern ||
- Function->getStorageClass() == SC_PrivateExtern ||
- Function->getStorageClass() == SC_None)) {
- // C99 6.2.2p4:
- // For an identifier declared with the storage-class specifier
- // extern in a scope in which a prior declaration of that
- // identifier is visible, if the prior declaration specifies
- // internal or external linkage, the linkage of the identifier
- // at the later declaration is the same as the linkage
- // specified at the prior declaration. If no prior declaration
- // is visible, or if the prior declaration specifies no
- // linkage, then the identifier has external linkage.
- if (const FunctionDecl *PrevFunc = Function->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(PrevFunc, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
- }
+ // Note that Sema::MergeCompatibleFunctionDecls already takes care of
+ // merging storage classes and visibility attributes, so we don't have to
+ // look at previous decls in here.
// In C++, then if the type of the function uses a type with
// unique-external linkage, it's not legally usable from outside
@@ -389,21 +656,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
Function->getType()->getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- // Consider LV from the template and the template arguments unless
- // this is an explicit specialization with a visibility attribute.
+ // Consider LV from the template and the template arguments.
+ // We're at file scope, so we do not need to worry about nested
+ // specializations.
if (FunctionTemplateSpecializationInfo *specInfo
= Function->getTemplateSpecializationInfo()) {
- LinkageInfo TempLV = getLVForDecl(specInfo->getTemplate(), true);
- const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(templateArgs,
- OnlyTemplate);
- if (shouldConsiderTemplateVis(Function, specInfo)) {
- LV.mergeWithMin(TempLV);
- LV.mergeWithMin(ArgsLV);
- } else {
- LV.mergeLinkage(TempLV);
- LV.mergeLinkage(ArgsLV);
- }
+ mergeTemplateLV(LV, Function, specInfo);
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -414,41 +672,33 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// has the typedef name for linkage purposes (7.1.3); or
} else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
// Unnamed tags have no linkage.
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl())
+ if (!Tag->hasNameForLinkage())
return LinkageInfo::none();
// If this is a class template specialization, consider the
- // linkage of the template and template arguments.
+ // linkage of the template and template arguments. We're at file
+ // scope, so we do not need to worry about nested specializations.
if (const ClassTemplateSpecializationDecl *spec
= dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
- // From the template.
- LinkageInfo TempLV = getLVForDecl(spec->getSpecializedTemplate(), true);
-
- // The arguments at which the template was instantiated.
- const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- if (shouldConsiderTemplateVis(spec)) {
- LV.mergeWithMin(TempLV);
- LV.mergeWithMin(ArgsLV);
- } else {
- LV.mergeLinkage(TempLV);
- LV.mergeLinkage(ArgsLV);
- }
+ mergeTemplateLV(LV, spec, computation);
}
// - an enumerator belonging to an enumeration with external linkage;
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
- OnlyTemplate);
- if (!isExternalLinkage(EnumLV.linkage()))
+ computation);
+ if (!isExternalLinkage(EnumLV.getLinkage()))
return LinkageInfo::none();
LV.merge(EnumLV);
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
- LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters()));
+ bool considerVisibility = !hasExplicitVisibilityAlready(computation);
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
} else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
@@ -466,13 +716,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// If we ended up with non-external linkage, visibility should
// always be default.
- if (LV.linkage() != ExternalLinkage)
- return LinkageInfo(LV.linkage(), DefaultVisibility, false);
+ if (LV.getLinkage() != ExternalLinkage)
+ return LinkageInfo(LV.getLinkage(), DefaultVisibility, false);
return LV;
}
-static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForClassMember(const NamedDecl *D,
+ LVComputationKind computation) {
// Only certain class members have linkage. Note that fields don't
// really have linkage, but it's convenient to say they do for the
// purposes of calculating linkage of pointer-to-data-member
@@ -480,46 +731,45 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
- (isa<TagDecl>(D) &&
- (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl()))))
+ isa<TagDecl>(D)))
return LinkageInfo::none();
LinkageInfo LV;
// If we have an explicit visibility attribute, merge that in.
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility())
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(D, computation))
LV.mergeVisibility(*Vis, true);
// If we're paying attention to global visibility, apply
// -finline-visibility-hidden if this is an inline method.
//
// Note that we do this before merging information about
// the class visibility.
- if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
+ if (!LV.isVisibilityExplicit() && useInlineVisibilityHidden(D))
LV.mergeVisibility(HiddenVisibility, true);
}
// If this class member has an explicit visibility attribute, the only
// thing that can change its visibility is the template arguments, so
// only look for them when processing the class.
- bool ClassOnlyTemplate = LV.visibilityExplicit() ? true : OnlyTemplate;
-
- // If this member has an visibility attribute, ClassF will exclude
- // attributes on the class or command line options, keeping only information
- // about the template instantiation. If the member has no visibility
- // attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin
- // produces the desired result.
- LV.mergeWithMin(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
- ClassOnlyTemplate));
- if (!isExternalLinkage(LV.linkage()))
+ LVComputationKind classComputation = computation;
+ if (LV.isVisibilityExplicit())
+ classComputation = withExplicitVisibilityAlready(computation);
+
+ LinkageInfo classLV =
+ getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
+ if (!isExternalLinkage(classLV.getLinkage()))
return LinkageInfo::none();
// If the class already has unique-external linkage, we can't improve.
- if (LV.linkage() == UniqueExternalLinkage)
+ if (classLV.getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- if (!OnlyTemplate)
- LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode());
+ // Otherwise, don't merge in classLV yet, because in certain cases
+ // we need to completely ignore the visibility from it.
+
+ // Specifically, if this decl exists and has an explicit attribute.
+ const NamedDecl *explicitSpecSuppressor = 0;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
// If the type of the function uses a type with unique-external
@@ -531,192 +781,269 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
- const TemplateArgumentList &TemplateArgs = *spec->TemplateArguments;
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- TemplateParameterList *TemplateParams =
- spec->getTemplate()->getTemplateParameters();
- LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams);
- if (shouldConsiderTemplateVis(MD, spec)) {
- LV.mergeWithMin(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeWithMin(ParamsLV);
- } else {
- LV.mergeLinkage(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeLinkage(ParamsLV);
+ mergeTemplateLV(LV, MD, spec);
+ if (spec->isExplicitSpecialization()) {
+ explicitSpecSuppressor = MD;
+ } else if (isExplicitMemberSpecialization(spec->getTemplate())) {
+ explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl();
}
+ } else if (isExplicitMemberSpecialization(MD)) {
+ explicitSpecSuppressor = MD;
}
- // Note that in contrast to basically every other situation, we
- // *do* apply -fvisibility to method declarations.
-
} else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (const ClassTemplateSpecializationDecl *spec
= dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
- // Merge template argument/parameter information for member
- // class template specializations.
- const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- TemplateParameterList *TemplateParams =
- spec->getSpecializedTemplate()->getTemplateParameters();
- LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams);
- if (shouldConsiderTemplateVis(spec)) {
- LV.mergeWithMin(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeWithMin(ParamsLV);
+ mergeTemplateLV(LV, spec, computation);
+ if (spec->isExplicitSpecialization()) {
+ explicitSpecSuppressor = spec;
} else {
- LV.mergeLinkage(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeLinkage(ParamsLV);
+ const ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+ if (isExplicitMemberSpecialization(temp)) {
+ explicitSpecSuppressor = temp->getTemplatedDecl();
+ }
}
+ } else if (isExplicitMemberSpecialization(RD)) {
+ explicitSpecSuppressor = RD;
}
// Static data members.
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LinkageInfo TypeLV = getLVForType(VD->getType());
- if (TypeLV.linkage() != ExternalLinkage)
- LV.mergeLinkage(UniqueExternalLinkage);
- LV.mergeVisibility(TypeLV);
- }
+ LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility();
+ LV.mergeMaybeWithVisibility(typeLV,
+ !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit());
- return LV;
-}
+ if (isExplicitMemberSpecialization(VD)) {
+ explicitSpecSuppressor = VD;
+ }
-static void clearLinkageForClass(const CXXRecordDecl *record) {
- for (CXXRecordDecl::decl_iterator
- i = record->decls_begin(), e = record->decls_end(); i != e; ++i) {
- Decl *child = *i;
- if (isa<NamedDecl>(child))
- cast<NamedDecl>(child)->ClearLinkageCache();
+ // Template members.
+ } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
+ bool considerVisibility =
+ (!LV.isVisibilityExplicit() &&
+ !classLV.isVisibilityExplicit() &&
+ !hasExplicitVisibilityAlready(computation));
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+ if (const RedeclarableTemplateDecl *redeclTemp =
+ dyn_cast<RedeclarableTemplateDecl>(temp)) {
+ if (isExplicitMemberSpecialization(redeclTemp)) {
+ explicitSpecSuppressor = temp->getTemplatedDecl();
+ }
+ }
}
-}
-void NamedDecl::anchor() { }
+ // We should never be looking for an attribute directly on a template.
+ assert(!explicitSpecSuppressor || !isa<TemplateDecl>(explicitSpecSuppressor));
-void NamedDecl::ClearLinkageCache() {
- // Note that we can't skip clearing the linkage of children just
- // because the parent doesn't have cached linkage: we don't cache
- // when computing linkage for parent contexts.
+ // If this member is an explicit member specialization, and it has
+ // an explicit attribute, ignore visibility from the parent.
+ bool considerClassVisibility = true;
+ if (explicitSpecSuppressor &&
+ // optimization: hasDVA() is true only with explicit visibility.
+ LV.isVisibilityExplicit() &&
+ classLV.getVisibility() != DefaultVisibility &&
+ hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) {
+ considerClassVisibility = false;
+ }
- HasCachedLinkage = 0;
+ // Finally, merge in information from the class.
+ LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
+ return LV;
+}
- // If we're changing the linkage of a class, we need to reset the
- // linkage of child declarations, too.
- if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this))
- clearLinkageForClass(record);
+void NamedDecl::anchor() { }
- if (ClassTemplateDecl *temp =
- dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) {
- // Clear linkage for the template pattern.
- CXXRecordDecl *record = temp->getTemplatedDecl();
- record->HasCachedLinkage = 0;
- clearLinkageForClass(record);
+bool NamedDecl::isLinkageValid() const {
+ if (!HasCachedLinkage)
+ return true;
- // We need to clear linkage for specializations, too.
- for (ClassTemplateDecl::spec_iterator
- i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
- i->ClearLinkageCache();
- }
+ return getLVForDecl(this, LVForExplicitValue).getLinkage() ==
+ Linkage(CachedLinkage);
+}
- // Clear cached linkage for function template decls, too.
- if (FunctionTemplateDecl *temp =
- dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) {
- temp->getTemplatedDecl()->ClearLinkageCache();
- for (FunctionTemplateDecl::spec_iterator
- i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
- i->ClearLinkageCache();
- }
-
+bool NamedDecl::hasExternalLinkageUncached() const {
+ return getLVForDecl(this, LVForExplicitValue).getLinkage() == ExternalLinkage;
}
Linkage NamedDecl::getLinkage() const {
- if (HasCachedLinkage) {
- assert(Linkage(CachedLinkage) ==
- getLVForDecl(this, true).linkage());
+ if (HasCachedLinkage)
return Linkage(CachedLinkage);
- }
- CachedLinkage = getLVForDecl(this, true).linkage();
+ // We don't care about visibility here, so ask for the cheapest
+ // possible visibility analysis.
+ CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage();
HasCachedLinkage = 1;
+
+#ifndef NDEBUG
+ verifyLinkage();
+#endif
+
return Linkage(CachedLinkage);
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
- LinkageInfo LI = getLVForDecl(this, false);
- assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage());
+ LVComputationKind computation =
+ (usesTypeVisibility(this) ? LVForType : LVForValue);
+ LinkageInfo LI = getLVForDecl(this, computation);
+ if (HasCachedLinkage) {
+ assert(Linkage(CachedLinkage) == LI.getLinkage());
+ return LI;
+ }
HasCachedLinkage = 1;
- CachedLinkage = LI.linkage();
+ CachedLinkage = LI.getLinkage();
+
+#ifndef NDEBUG
+ verifyLinkage();
+#endif
+
return LI;
}
-llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
- // Use the most recent declaration of a variable.
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (llvm::Optional<Visibility> V =
- getVisibilityOf(Var->getMostRecentDecl()))
- return V;
+void NamedDecl::verifyLinkage() const {
+ // In C (because of gnu inline) and in c++ with microsoft extensions an
+ // static can follow an extern, so we can have two decls with different
+ // linkages.
+ const LangOptions &Opts = getASTContext().getLangOpts();
+ if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+ return;
+
+ // 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 *D = NULL;
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ NamedDecl *T = cast<NamedDecl>(*I);
+ if (T == this)
+ continue;
+ if (T->HasCachedLinkage != 0) {
+ D = T;
+ break;
+ }
+ }
+ assert(!D || D->CachedLinkage == CachedLinkage);
+}
+
+Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
+ // Check the declaration itself first.
+ if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ return V;
+
+ // If this is a member class of a specialization of a class template
+ // and the corresponding decl has explicit visibility, use that.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
+ if (InstantiatedFrom)
+ return getVisibilityOf(InstantiatedFrom, kind);
+ }
+
+ // If there wasn't explicit visibility there, and this is a
+ // specialization of a class template, check for visibility
+ // on the pattern.
+ if (const ClassTemplateSpecializationDecl *spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
+ kind);
+ // Use the most recent declaration.
+ const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
+ if (MostRecent != this)
+ return MostRecent->getExplicitVisibility(kind);
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
}
- return llvm::Optional<Visibility>();
+ return None;
}
- // Use the most recent declaration of a function, and also handle
- // function template specializations.
+ // Also handle function template specializations.
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
- if (llvm::Optional<Visibility> V
- = getVisibilityOf(fn->getMostRecentDecl()))
- return V;
-
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
= fn->getTemplateSpecializationInfo())
- return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+ return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(),
+ kind);
// If the function is a member of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
- return llvm::Optional<Visibility>();
+ return None;
}
- // Otherwise, just check the declaration itself first.
- if (llvm::Optional<Visibility> V = getVisibilityOf(this))
- return V;
-
// The visibility of a template is stored in the templated decl.
if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
- return getVisibilityOf(TD->getTemplatedDecl());
+ return getVisibilityOf(TD->getTemplatedDecl(), kind);
- // If there wasn't explicit visibility there, and this is a
- // specialization of a class template, check for visibility
- // on the pattern.
- if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(this))
- return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+ return None;
+}
- // If this is a member class of a specialization of a class template
- // and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
- CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
- if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ if (Function->isInAnonymousNamespace() &&
+ !Function->getDeclContext()->isExternCContext())
+ return LinkageInfo::uniqueExternal();
+
+ // This is a "void f();" which got merged with a file static.
+ if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
+ return LinkageInfo::internal();
+
+ LinkageInfo LV;
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis =
+ getExplicitVisibility(Function, computation))
+ LV.mergeVisibility(*Vis, true);
+ }
+
+ // Note that Sema::MergeCompatibleFunctionDecls already takes care of
+ // merging storage classes and visibility attributes, so we don't have to
+ // look at previous decls in here.
+
+ return LV;
}
- return llvm::Optional<Visibility>();
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (Var->hasExternalStorage()) {
+ if (Var->isInAnonymousNamespace() &&
+ !Var->getDeclContext()->isExternCContext())
+ return LinkageInfo::uniqueExternal();
+
+ LinkageInfo LV;
+ if (Var->getStorageClass() == SC_PrivateExtern)
+ LV.mergeVisibility(HiddenVisibility, true);
+ else if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(Var, computation))
+ LV.mergeVisibility(*Vis, true);
+ }
+
+ if (const VarDecl *Prev = Var->getPreviousDecl()) {
+ LinkageInfo PrevLV = getLVForDecl(Prev, computation);
+ if (PrevLV.getLinkage())
+ LV.setLinkage(PrevLV.getLinkage());
+ LV.mergeVisibility(PrevLV);
+ }
+
+ return LV;
+ }
+ }
+
+ return LinkageInfo::none();
}
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
@@ -751,12 +1078,11 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
if (isa<ParmVarDecl>(ContextDecl))
DC = ContextDecl->getDeclContext()->getRedeclContext();
else
- return getLVForDecl(cast<NamedDecl>(ContextDecl),
- OnlyTemplate);
+ return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
}
if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, OnlyTemplate);
+ return getLVForDecl(ND, computation);
return LinkageInfo::external();
}
@@ -767,7 +1093,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// Handle linkage for namespace-scope names.
if (D->getDeclContext()->getRedeclContext()->isFileContext())
- return getLVForNamespaceScopeDecl(D, OnlyTemplate);
+ return getLVForNamespaceScopeDecl(D, computation);
// C++ [basic.link]p5:
// In addition, a member function, static data member, a named
@@ -777,7 +1103,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// purposes (7.1.3), has external linkage if the name of the class
// has external linkage.
if (D->getDeclContext()->isRecord())
- return getLVForClassMember(D, OnlyTemplate);
+ return getLVForClassMember(D, computation);
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -790,48 +1116,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// one such matching entity, the program is ill-formed. Otherwise,
// if no matching entity is found, the block scope entity receives
// external linkage.
- if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- if (Function->isInAnonymousNamespace() &&
- !Function->getDeclContext()->isExternCContext())
- return LinkageInfo::uniqueExternal();
-
- LinkageInfo LV;
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
- LV.mergeVisibility(*Vis, true);
- }
-
- if (const FunctionDecl *Prev = Function->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
-
- return LV;
- }
-
- if (const VarDecl *Var = dyn_cast<VarDecl>(D))
- if (Var->getStorageClass() == SC_Extern ||
- Var->getStorageClass() == SC_PrivateExtern) {
- if (Var->isInAnonymousNamespace() &&
- !Var->getDeclContext()->isExternCContext())
- return LinkageInfo::uniqueExternal();
-
- LinkageInfo LV;
- if (Var->getStorageClass() == SC_PrivateExtern)
- LV.mergeVisibility(HiddenVisibility, true);
- else if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
- LV.mergeVisibility(*Vis, true);
- }
-
- // Note that Sema::MergeVarDecl already takes care of implementing
- // C99 6.2.2p4 and propagating the visibility attribute, so we don't
- // have to do it here.
- return LV;
- }
- }
+ if (D->getDeclContext()->isFunctionOrMethod())
+ return getLVForLocalDecl(D, computation);
// C++ [basic.link]p6:
// Names not covered by these rules have no linkage.
@@ -843,10 +1129,24 @@ std::string NamedDecl::getQualifiedNameAsString() const {
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+ printQualifiedName(OS, P);
+ return OS.str();
+}
+
+void NamedDecl::printQualifiedName(raw_ostream &OS) const {
+ printQualifiedName(OS, getASTContext().getPrintingPolicy());
+}
+
+void NamedDecl::printQualifiedName(raw_ostream &OS,
+ const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
- if (Ctx->isFunctionOrMethod())
- return getNameAsString();
+ if (Ctx->isFunctionOrMethod()) {
+ printName(OS);
+ return;
+ }
typedef SmallVector<const DeclContext *, 8> ContextsTy;
ContextsTy Contexts;
@@ -855,22 +1155,18 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
while (Ctx && isa<NamedDecl>(Ctx)) {
Contexts.push_back(Ctx);
Ctx = Ctx->getParent();
- };
-
- std::string QualName;
- llvm::raw_string_ostream OS(QualName);
+ }
for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend();
I != E; ++I) {
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(*I)) {
+ OS << Spec->getName();
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.data(),
- TemplateArgs.size(),
- P);
- OS << Spec->getName() << TemplateArgsStr;
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
+ TemplateArgs.data(),
+ TemplateArgs.size(),
+ P);
} else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
if (ND->isAnonymousNamespace())
OS << "<anonymous namespace>";
@@ -912,8 +1208,15 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
OS << *this;
else
OS << "<anonymous>";
+}
- return OS.str();
+void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
+ const PrintingPolicy &Policy,
+ bool Qualified) const {
+ if (Qualified)
+ printQualifiedName(OS, Policy);
+ else
+ printName(OS);
}
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
@@ -1166,45 +1469,80 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten) {
- return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten);
+ StorageClass S) {
+ return new (C) VarDecl(Var, 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, SC_None);
+ QualType(), 0, SC_None);
}
void VarDecl::setStorageClass(StorageClass SC) {
assert(isLegalForVariable(SC));
- if (getStorageClass() != SC)
- ClearLinkageCache();
-
VarDeclBits.SClass = SC;
}
SourceRange VarDecl::getSourceRange() const {
if (const Expr *Init = getInit()) {
SourceLocation InitEnd = Init->getLocEnd();
- if (InitEnd.isValid())
+ // If Init is implicit, ignore its source range and fallback on
+ // DeclaratorDecl::getSourceRange() to handle postfix elements.
+ if (InitEnd.isValid() && InitEnd != getLocation())
return SourceRange(getOuterLocStart(), InitEnd);
}
return DeclaratorDecl::getSourceRange();
}
-bool VarDecl::isExternC() const {
- if (getLinkage() != ExternalLinkage)
- return false;
+template<typename T>
+static LanguageLinkage getLanguageLinkageTemplate(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 (!isExternalLinkage(D.getLinkage()))
+ return NoLanguageLinkage;
+
+ // Language linkage is a C++ concept, but saying that everything else in C has
+ // C language linkage fits the implementation nicely.
+ ASTContext &Context = D.getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return CLanguageLinkage;
- const DeclContext *DC = getDeclContext();
+ // C++ [dcl.link]p4: A C language linkage is ignored in determining the
+ // language linkage of the names of class members and the function type of
+ // class member functions.
+ const DeclContext *DC = D.getDeclContext();
if (DC->isRecord())
+ return CXXLanguageLinkage;
+
+ // If the first decl is in an extern "C" context, any other redeclaration
+ // will have C language linkage. If the first one is not in an extern "C"
+ // context, we would have reported an error for any other decl being in one.
+ const T *First = D.getFirstDeclaration();
+ if (First->getDeclContext()->isExternCContext())
+ return CLanguageLinkage;
+ return CXXLanguageLinkage;
+}
+
+template<typename T>
+static bool isExternCTemplate(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();
+ if (DC->isRecord()) {
+ assert(D.getASTContext().getLangOpts().CPlusPlus);
return false;
+ }
- ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().CPlusPlus)
- return true;
- return DC->isExternCContext();
+ return D.getLanguageLinkage() == CLanguageLinkage;
+}
+
+LanguageLinkage VarDecl::getLanguageLinkage() const {
+ return getLanguageLinkageTemplate(*this);
+}
+
+bool VarDecl::isExternC() const {
+ return isExternCTemplate(*this);
}
VarDecl *VarDecl::getCanonicalDecl() {
@@ -1241,12 +1579,11 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// AST for 'extern "C" int foo;' is annotated with 'extern'.
if (hasExternalStorage())
return DeclarationOnly;
-
- if (getStorageClassAsWritten() == SC_Extern ||
- getStorageClassAsWritten() == SC_PrivateExtern) {
+
+ if (hasExternalStorage()) {
for (const VarDecl *PrevVar = getPreviousDecl();
PrevVar; PrevVar = PrevVar->getPreviousDecl()) {
- if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit())
+ if (PrevVar->getLinkage() == InternalLinkage)
return DeclarationOnly;
}
}
@@ -1375,7 +1712,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
// In C++11, any variable of reference type can be used in a constant
// expression if it is initialized by a constant expression.
- if (Lang.CPlusPlus0x && getType()->isReferenceType())
+ if (Lang.CPlusPlus11 && getType()->isReferenceType())
return true;
// Only const objects can be used in constant expressions in C++. C++98 does
@@ -1391,7 +1728,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
// Additionally, in C++11, non-volatile constexpr variables can be used in
// constant expressions.
- return Lang.CPlusPlus0x && isConstexpr();
+ return Lang.CPlusPlus11 && isConstexpr();
}
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
@@ -1409,12 +1746,12 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
}
APValue *VarDecl::evaluateValue() const {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
return evaluateValue(Notes);
}
APValue *VarDecl::evaluateValue(
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
// We only produce notes indicating why an initializer is non-constant the
@@ -1447,7 +1784,7 @@ APValue *VarDecl::evaluateValue(
// In C++11, we have determined whether the initializer was a constant
// expression as a side-effect.
- if (getASTContext().getLangOpts().CPlusPlus0x && !Eval->CheckedICE) {
+ if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) {
Eval->CheckedICE = true;
Eval->IsICE = Result && Notes.empty();
}
@@ -1471,8 +1808,8 @@ bool VarDecl::checkInitIsICE() const {
// In C++11, evaluate the initializer to check whether it's a constant
// expression.
- if (getASTContext().getLangOpts().CPlusPlus0x) {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (getASTContext().getLangOpts().CPlusPlus11) {
+ SmallVector<PartialDiagnosticAt, 8> Notes;
evaluateValue(Notes);
return Eval->IsICE;
}
@@ -1541,16 +1878,15 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten,
- Expr *DefArg) {
+ StorageClass S, Expr *DefArg) {
return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo,
- S, SCAsWritten, DefArg);
+ S, DefArg);
}
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, SC_None, 0);
+ 0, QualType(), 0, SC_None, 0);
}
SourceRange ParmVarDecl::getSourceRange() const {
@@ -1602,17 +1938,13 @@ unsigned ParmVarDecl::getParameterIndexLarge() const {
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//
-void FunctionDecl::getNameForDiagnostic(std::string &S,
- const PrintingPolicy &Policy,
- bool Qualified) const {
- NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+void FunctionDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs();
if (TemplateArgs)
- S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs->data(),
- TemplateArgs->size(),
- Policy);
-
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs->data(), TemplateArgs->size(), Policy);
}
bool FunctionDecl::isVariadic() const {
@@ -1684,13 +2016,6 @@ void FunctionDecl::setPure(bool P) {
Parent->markedVirtualFunctionPure();
}
-void FunctionDecl::setConstexpr(bool IC) {
- IsConstexpr = IC;
- CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this);
- if (IC && CD)
- CD->getParent()->markedConstructorConstexpr(CD);
-}
-
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
@@ -1722,29 +2047,25 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-bool FunctionDecl::isExternC() const {
- if (getLinkage() != ExternalLinkage)
- return false;
-
- if (getAttr<OverloadableAttr>())
- return false;
-
- const DeclContext *DC = getDeclContext();
- if (DC->isRecord())
- return false;
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
+ // Users expect to be able to write
+ // extern "C" void *__builtin_alloca (size_t);
+ // so consider builtins as having C language linkage.
+ if (getBuiltinID())
+ return CLanguageLinkage;
- ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().CPlusPlus)
- return true;
+ return getLanguageLinkageTemplate(*this);
+}
- return isMain() || DC->isExternCContext();
+bool FunctionDecl::isExternC() const {
+ return isExternCTemplate(*this);
}
bool FunctionDecl::isGlobal() const {
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this))
return Method->isStatic();
- if (getStorageClass() == SC_Static)
+ if (getCanonicalDecl()->getStorageClass() == SC_Static)
return false;
for (const DeclContext *DC = getDeclContext();
@@ -1760,6 +2081,12 @@ bool FunctionDecl::isGlobal() const {
return true;
}
+bool FunctionDecl::isNoReturn() const {
+ return hasAttr<NoReturnAttr>() || hasAttr<CXX11NoReturnAttr>() ||
+ hasAttr<C11NoReturnAttr>() ||
+ getType()->getAs<FunctionType>()->getNoReturnAttr();
+}
+
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
redeclarable_base::setPreviousDeclaration(PrevDecl);
@@ -1783,14 +2110,6 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void FunctionDecl::setStorageClass(StorageClass SC) {
- assert(isLegalForFunction(SC));
- if (getStorageClass() != SC)
- ClearLinkageCache();
-
- SClass = SC;
-}
-
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
///
@@ -1851,7 +2170,7 @@ unsigned FunctionDecl::getNumParams() const {
}
void FunctionDecl::setParams(ASTContext &C,
- llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+ ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!");
@@ -1862,13 +2181,13 @@ void FunctionDecl::setParams(ASTContext &C,
}
}
-void FunctionDecl::setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls) {
+void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) {
assert(DeclsInPrototypeScope.empty() && "Already has prototype decls!");
if (!NewDecls.empty()) {
NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
std::copy(NewDecls.begin(), NewDecls.end(), A);
- DeclsInPrototypeScope = llvm::ArrayRef<NamedDecl*>(A, NewDecls.size());
+ DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size());
}
}
@@ -1907,38 +2226,6 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
return NumRequiredArgs;
}
-bool FunctionDecl::isInlined() const {
- if (IsInline)
- return true;
-
- if (isa<CXXMethodDecl>(this)) {
- if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified())
- return true;
- }
-
- switch (getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return false;
-
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // Handle below.
- break;
- }
-
- const FunctionDecl *PatternDecl = getTemplateInstantiationPattern();
- bool HasPattern = false;
- if (PatternDecl)
- HasPattern = PatternDecl->hasBody(PatternDecl);
-
- if (HasPattern && PatternDecl)
- return PatternDecl->isInlined();
-
- return false;
-}
-
static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
// Only consider file-scope declarations in this test.
if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
@@ -1973,7 +2260,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
//
// FIXME: What happens if gnu_inline gets added on after the first
// declaration?
- if (!isInlineSpecified() || getStorageClassAsWritten() == SC_Extern)
+ if (!isInlineSpecified() || getStorageClass() == SC_Extern)
return false;
const FunctionDecl *Prev = this;
@@ -1985,10 +2272,10 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then it is always externally visible.
if (!Prev->isInlineSpecified() ||
- Prev->getStorageClassAsWritten() != SC_Extern)
+ Prev->getStorageClass() != SC_Extern)
return false;
} else if (Prev->isInlineSpecified() &&
- Prev->getStorageClassAsWritten() != SC_Extern) {
+ Prev->getStorageClass() != SC_Extern) {
return false;
}
}
@@ -2014,8 +2301,8 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
-/// \brief For an inline function definition in C or C++, determine whether the
-/// definition will be externally visible.
+/// \brief For an inline function definition in C, or for a gnu_inline function
+/// in C++, determine whether the definition will be externally visible.
///
/// Inline function definitions are always available for inlining optimizations.
/// However, depending on the language dialect, declaration specifiers, and
@@ -2043,7 +2330,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
- if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern))
+ if (!(isInlineSpecified() && getStorageClass() == SC_Extern))
return true;
// If any declaration is 'inline' but not 'extern', then this definition
@@ -2052,13 +2339,17 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
Redecl != RedeclEnd;
++Redecl) {
if (Redecl->isInlineSpecified() &&
- Redecl->getStorageClassAsWritten() != SC_Extern)
+ Redecl->getStorageClass() != SC_Extern)
return true;
}
return false;
}
+ // The rest of this function is C-only.
+ assert(!Context.getLangOpts().CPlusPlus &&
+ "should not use C inline rules in C++");
+
// C99 6.7.4p6:
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
@@ -2118,10 +2409,6 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
return 0;
}
-MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
-}
-
void
FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
FunctionDecl *FD,
@@ -2553,18 +2840,17 @@ TagDecl* TagDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
- TypedefNameDeclOrQualifier = TDD;
+void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
+ TypedefNameDeclOrQualifier = TDD;
if (TypeForDecl)
- const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
- ClearLinkageCache();
+ assert(TypeForDecl->isLinkageValid());
+ assert(isLinkageValid());
}
void TagDecl::startDefinition() {
IsBeingDefined = true;
- if (isa<CXXRecordDecl>(this)) {
- CXXRecordDecl *D = cast<CXXRecordDecl>(this);
+ if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(this)) {
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
@@ -2587,6 +2873,16 @@ void TagDecl::completeDefinition() {
TagDecl *TagDecl::getDefinition() const {
if (isCompleteDefinition())
return const_cast<TagDecl *>(this);
+
+ // If it's possible for us to have an out-of-date definition, check now.
+ if (MayHaveOutOfDateDef) {
+ if (IdentifierInfo *II = getIdentifier()) {
+ if (II->isOutOfDate()) {
+ updateOutOfDate(*II);
+ }
+ }
+ }
+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
@@ -2643,14 +2939,17 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
bool IsScopedUsingClassTag, bool IsFixed) {
EnumDecl *Enum = new (C) EnumDecl(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));
- return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
- false, false, false);
+ EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(),
+ 0, 0, false, false, false);
+ Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+ return Enum;
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -2708,6 +3007,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
+ HasVolatileMember = false;
LoadedFieldsFromExternalStorage = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
}
@@ -2717,14 +3017,18 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
IdentifierInfo *Id, RecordDecl* PrevDecl) {
RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
PrevDecl);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+
C.getTypeDeclType(R, PrevDecl);
return R;
}
RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl));
- return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+ return R;
}
bool RecordDecl::isInjectedClassName() const {
@@ -2793,7 +3097,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
-void BlockDecl::setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
// Zero params -> null pointer.
@@ -2871,6 +3175,14 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
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))
+ return true;
+
+ return isWeakImported();
+}
+
void ImplicitParamDecl::anchor() { }
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
@@ -2890,12 +3202,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass SC, StorageClass SCAsWritten,
+ StorageClass SC,
bool isInlineSpecified,
bool hasWrittenPrototype,
bool isConstexprSpecified) {
FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
- T, TInfo, SC, SCAsWritten,
+ T, TInfo, SC,
isInlineSpecified,
isConstexprSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
@@ -2906,7 +3218,7 @@ 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, SC_None, false, false);
+ SC_None, false, false);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
@@ -3013,6 +3325,17 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation());
}
+void EmptyDecl::anchor() {}
+
+EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) EmptyDecl(DC, L);
+}
+
+EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EmptyDecl));
+ return new (Mem) EmptyDecl(0, SourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 4400d503f263..bd6d99cd59ea 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -12,19 +12,21 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclBase.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
@@ -39,6 +41,10 @@ using namespace clang;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
+void Decl::updateOutOfDate(IdentifierInfo &II) const {
+ getASTContext().getExternalSource()->updateOutOfDateIdentifier(II);
+}
+
void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
unsigned ID,
unsigned Size) {
@@ -58,6 +64,11 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
return Result;
}
+Module *Decl::getOwningModuleSlow() const {
+ assert(isFromASTFile() && "Not from AST file?");
+ return getASTContext().getExternalSource()->getModule(getOwningModuleID());
+}
+
const char *Decl::getDeclKindName() const {
switch (DeclKind) {
default: llvm_unreachable("Declaration not in DeclNodes.inc!");
@@ -180,8 +191,11 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const {
OS << Message;
- if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
- OS << " '" << DN->getQualifiedNameAsString() << '\'';
+ if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) {
+ OS << " '";
+ DN->printQualifiedName(OS);
+ OS << '\'';
+ }
OS << '\n';
}
@@ -253,6 +267,19 @@ ASTMutationListener *Decl::getASTMutationListener() const {
return getASTContext().getASTMutationListener();
}
+unsigned Decl::getMaxAlignment() const {
+ if (!hasAttrs())
+ return 0;
+
+ unsigned Align = 0;
+ const AttrVec &V = getAttrs();
+ ASTContext &Ctx = getASTContext();
+ specific_attr_iterator<AlignedAttr> I(V.begin()), E(V.end());
+ for (; I != E; ++I)
+ Align = std::max(Align, I->getAlignment(Ctx));
+ return Align;
+}
+
bool Decl::isUsed(bool CheckUsedAttr) const {
if (Used)
return true;
@@ -260,13 +287,7 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
// Check for used attribute.
if (CheckUsedAttr && hasAttr<UsedAttr>())
return true;
-
- // Check redeclarations for used attribute.
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used)
- return true;
- }
-
+
return false;
}
@@ -414,7 +435,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const {
// Variables, if they aren't definitions.
if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (!Var->hasExternalStorage() || Var->getInit()) {
+ if (Var->isThisDeclarationADefinition()) {
IsDefinition = true;
return false;
}
@@ -541,6 +562,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCategory:
case ObjCCategoryImpl:
case Import:
+ case OMPThreadPrivate:
+ case Empty:
// Never looked up by name.
return 0;
}
@@ -789,6 +812,17 @@ bool DeclContext::isExternCContext() const {
return false;
}
+bool DeclContext::isExternCXXContext() const {
+ const DeclContext *DC = this;
+ while (DC->DeclKind != Decl::TranslationUnit) {
+ if (DC->DeclKind == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage()
+ == LinkageSpecDecl::lang_cxx;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -862,7 +896,7 @@ DeclContext *DeclContext::getPrimaryContext() {
}
void
-DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){
+DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){
Contexts.clear();
if (DeclKind != Decl::Namespace) {
@@ -900,6 +934,21 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
return std::make_pair(FirstNewDecl, PrevDecl);
}
+/// \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() {
+ assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
+ NeedToReconcileExternalVisibleStorage = false;
+
+ StoredDeclsMap &Map = *LookupPtr.getPointer();
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
+ I->second.removeExternalDecls();
+ Source->FindExternalVisibleDeclsByName(this, I->first);
+ }
+}
+
/// \brief Load the declarations within this lexical storage from an
/// external source.
void
@@ -950,9 +999,8 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- StoredDeclsList &List = (*Map)[Name];
- assert(List.isNull());
- (void) List;
+ // Add an entry to the map for this name, if it's not already present.
+ (*Map)[Name];
return DeclContext::lookup_result();
}
@@ -962,7 +1010,6 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
ArrayRef<NamedDecl*> Decls) {
ASTContext &Context = DC->getParentASTContext();
-
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
@@ -973,6 +1020,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
if (List.isNull())
List.setOnlyValue(*I);
else
+ // FIXME: Need declarationReplaces handling for redeclarations in modules.
List.AddSubsequentDecl(*I);
}
@@ -1114,16 +1162,18 @@ static bool shouldBeHidden(NamedDecl *D) {
StoredDeclsMap *DeclContext::buildLookup() {
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
+ // FIXME: Should we keep going if hasExternalVisibleStorage?
if (!LookupPtr.getInt())
return LookupPtr.getPointer();
- llvm::SmallVector<DeclContext *, 2> Contexts;
+ SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
buildLookupImpl(Contexts[I]);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
+ NeedToReconcileExternalVisibleStorage = false;
return LookupPtr.getPointer();
}
@@ -1162,18 +1212,33 @@ DeclContext::lookup(DeclarationName Name) {
return PrimaryContext->lookup(Name);
if (hasExternalVisibleStorage()) {
- // If a PCH has a result for this name, and we have a local declaration, we
- // will have imported the PCH result when adding the local declaration.
- // FIXME: For modules, we could have had more declarations added by module
- // imoprts since we saw the declaration of the local name.
- if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
- StoredDeclsMap::iterator I = Map->find(Name);
- if (I != Map->end())
- return I->second.getLookupResult();
- }
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt())
+ Map = buildLookup();
+ else if (NeedToReconcileExternalVisibleStorage)
+ reconcileExternalVisibleStorage();
+
+ if (!Map)
+ Map = CreateStoredDeclsMap(getParentASTContext());
+
+ // If a PCH/module has a result for this name, and we have a local
+ // declaration, we will have imported the PCH/module result when adding the
+ // local declaration or when reconciling the module.
+ std::pair<StoredDeclsMap::iterator, bool> R =
+ Map->insert(std::make_pair(Name, StoredDeclsList()));
+ if (!R.second)
+ return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- return Source->FindExternalVisibleDeclsByName(this, Name);
+ if (Source->FindExternalVisibleDeclsByName(this, Name)) {
+ if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ StoredDeclsMap::iterator I = Map->find(Name);
+ if (I != Map->end())
+ return I->second.getLookupResult();
+ }
+ }
+
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
}
StoredDeclsMap *Map = LookupPtr.getPointer();
@@ -1190,26 +1255,26 @@ DeclContext::lookup(DeclarationName Name) {
return I->second.getLookupResult();
}
-void DeclContext::localUncachedLookup(DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl *> &Results) {
+void DeclContext::localUncachedLookup(DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Results) {
Results.clear();
// If there's no external storage, just perform a normal lookup and copy
// the results.
if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) {
lookup_result LookupResults = lookup(Name);
- Results.insert(Results.end(), LookupResults.first, LookupResults.second);
+ Results.insert(Results.end(), LookupResults.begin(), LookupResults.end());
return;
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
- if (Name) {
+ if (Name && !LookupPtr.getInt()) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator Pos = Map->find(Name);
if (Pos != Map->end()) {
Results.insert(Results.end(),
- Pos->second.getLookupResult().first,
- Pos->second.getLookupResult().second);
+ Pos->second.getLookupResult().begin(),
+ Pos->second.getLookupResult().end());
return;
}
}
@@ -1361,8 +1426,8 @@ DeclContext::getUsingDirectives() 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.first),
- reinterpret_cast<udir_iterator>(Result.second));
+ return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.begin()),
+ reinterpret_cast<udir_iterator>(Result.end()));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 82e630acefba..ffad9ae93cc8 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
@@ -36,28 +36,33 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
}
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
- : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
- UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false),
+ : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
HasMutableFields(false), HasOnlyCMembers(true),
- HasInClassInitializer(false),
- HasTrivialDefaultConstructor(true),
+ HasInClassInitializer(false), HasUninitializedReferenceMember(false),
+ NeedOverloadResolutionForMoveConstructor(false),
+ NeedOverloadResolutionForMoveAssignment(false),
+ NeedOverloadResolutionForDestructor(false),
+ DefaultedMoveConstructorIsDeleted(false),
+ DefaultedMoveAssignmentIsDeleted(false),
+ DefaultedDestructorIsDeleted(false),
+ HasTrivialSpecialMembers(SMF_All),
+ DeclaredNonTrivialSpecialMembers(0),
+ HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
DefaultedDefaultConstructorIsConstexpr(true),
- HasConstexprDefaultConstructor(false), HasTrivialCopyConstructor(true),
- HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
- HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
- HasIrrelevantDestructor(true),
+ HasConstexprDefaultConstructor(false),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
- UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
- DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
- DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
- DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
- FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0),
- NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) {
+ UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
+ ImplicitCopyConstructorHasConstParam(true),
+ ImplicitCopyAssignmentHasConstParam(true),
+ HasDeclaredCopyConstructorWithConstParam(false),
+ HasDeclaredCopyAssignmentWithConstParam(false),
+ FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
+ IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -82,6 +87,7 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
bool DelayTypeCreation) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
Id, PrevDecl);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
// FIXME: DelayTypeCreation seems like such a hack
if (!DelayTypeCreation)
@@ -96,6 +102,7 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
0, 0);
R->IsBeingDefined = true;
R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+ R->MayHaveOutOfDateDef = false;
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -103,8 +110,11 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
CXXRecordDecl *
CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
- return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0,
+ SourceLocation(), SourceLocation(),
+ 0, 0);
+ R->MayHaveOutOfDateDef = false;
+ return R;
}
void
@@ -184,38 +194,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
BaseClassDecl->vbases_begin(),
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+ 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 (!VBaseDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+ }
}
if (Base->isVirtual()) {
// Add this base if it's not already in the list.
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
- VBases.push_back(Base);
-
+ VBases.push_back(Base);
+
// C++0x [meta.unary.prop] is_empty:
// T is a class type, but not a union type, with ... no virtual base
// classes
data().Empty = false;
-
- // C++ [class.ctor]p5:
- // A default constructor is trivial [...] if:
- // -- its class has [...] no virtual bases
- data().HasTrivialDefaultConstructor = false;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted and if
- // -- class X has no virtual functions and no virtual base classes, and
- data().HasTrivialCopyConstructor = false;
- data().HasTrivialMoveConstructor = false;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted and if
- // -- class X has no virtual functions and no virtual base classes, and
- data().HasTrivialCopyAssignment = false;
- data().HasTrivialMoveAssignment = false;
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor, copy/move constructor, or copy/move assignment
+ // operator for a class X] is trivial [...] if:
+ // -- class X has [...] no virtual base classes
+ data().HasTrivialSpecialMembers &= SMF_Destructor;
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
@@ -232,36 +239,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// -- all the direct base classes of its class have trivial default
// constructors.
if (!BaseClassDecl->hasTrivialDefaultConstructor())
- data().HasTrivialDefaultConstructor = false;
-
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
+
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
// [...]
// -- the constructor selected to copy/move each direct base class
// subobject is trivial, and
- // FIXME: C++0x: We need to only consider the selected constructor
- // instead of all of them. For now, we treat a move constructor as being
- // non-trivial if it calls anything other than a trivial move constructor.
if (!BaseClassDecl->hasTrivialCopyConstructor())
- data().HasTrivialCopyConstructor = false;
- if (!BaseClassDecl->hasTrivialMoveConstructor() ||
- !(BaseClassDecl->hasDeclaredMoveConstructor() ||
- BaseClassDecl->needsImplicitMoveConstructor()))
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the base class doesn't have a simple move constructor, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move constructor, this
+ // check is correct.
+ if (!BaseClassDecl->hasTrivialMoveConstructor())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
// [...]
// -- the assignment operator selected to copy/move each direct base
// class subobject is trivial, and
- // FIXME: C++0x: We need to only consider the selected operator instead
- // of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
- data().HasTrivialCopyAssignment = false;
- if (!BaseClassDecl->hasTrivialMoveAssignment() ||
- !(BaseClassDecl->hasDeclaredMoveAssignment() ||
- BaseClassDecl->needsImplicitMoveAssignment()))
- data().HasTrivialMoveAssignment = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the base class doesn't have a simple move assignment, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move assignment, this
+ // check is correct.
+ if (!BaseClassDecl->hasTrivialMoveAssignment())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
// C++11 [class.ctor]p6:
// If that user-written default constructor would satisfy the
@@ -270,24 +276,48 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasConstexprDefaultConstructor())
data().DefaultedDefaultConstructorIsConstexpr = false;
}
-
+
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
if (!BaseClassDecl->hasTrivialDestructor())
- data().HasTrivialDestructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
if (!BaseClassDecl->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if each direct base class B
+ // of X has a copy assignment operator whose parameter is of type 'const
+ // B&', 'const volatile B&', or 'B' [...]
+ if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each direct [...] base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
setHasObjectMember(true);
+
+ if (BaseClassDecl->hasVolatileMember())
+ setHasVolatileMember(true);
// Keep track of the presence of mutable fields.
if (BaseClassDecl->hasMutableFields())
data().HasMutableFields = true;
+
+ if (BaseClassDecl->hasUninitializedReferenceMember())
+ data().HasUninitializedReferenceMember = true;
+
+ addedClassSubobject(BaseClassDecl);
}
if (VBases.empty())
@@ -296,8 +326,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Create base specifier for any direct or indirect virtual bases.
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
data().NumVBases = VBases.size();
- for (int I = 0, E = VBases.size(); I != E; ++I)
+ for (int I = 0, E = VBases.size(); I != E; ++I) {
+ QualType Type = VBases[I]->getType();
+ if (!Type->isDependentType())
+ addedClassSubobject(Type->getAsCXXRecordDecl());
data().getVBases()[I] = *VBases[I];
+ }
+}
+
+void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
+ // C++11 [class.copy]p11:
+ // A defaulted copy/move constructor for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveConstructor())
+ data().NeedOverloadResolutionForMoveConstructor = true;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveAssignment())
+ data().NeedOverloadResolutionForMoveAssignment = true;
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:
+ // A defaulted [ctor or dtor] for a class X is defined as
+ // deleted if X has:
+ // -- any direct or virtual base class [...] has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ // -- any non-static data member has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ if (!Subobj->hasSimpleDestructor()) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForDestructor = true;
+ }
}
/// Callback function for CXXRecordDecl::forallBases that acknowledges
@@ -313,161 +379,29 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
return !forallBases(SawBase, 0);
}
-bool CXXRecordDecl::hasConstCopyConstructor() const {
- return getCopyConstructor(Qualifiers::Const) != 0;
-}
-
bool CXXRecordDecl::isTriviallyCopyable() const {
// C++0x [class]p5:
// A trivially copyable class is a class that:
// -- has no non-trivial copy constructors,
- if (!hasTrivialCopyConstructor()) return false;
+ if (hasNonTrivialCopyConstructor()) return false;
// -- has no non-trivial move constructors,
- if (!hasTrivialMoveConstructor()) return false;
+ if (hasNonTrivialMoveConstructor()) return false;
// -- has no non-trivial copy assignment operators,
- if (!hasTrivialCopyAssignment()) return false;
+ if (hasNonTrivialCopyAssignment()) return false;
// -- has no non-trivial move assignment operators, and
- if (!hasTrivialMoveAssignment()) return false;
+ if (hasNonTrivialMoveAssignment()) return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor()) return false;
return true;
}
-/// \brief Perform a simplistic form of overload resolution that only considers
-/// cv-qualifiers on a single parameter, and return the best overload candidate
-/// (if there is one).
-static CXXMethodDecl *
-GetBestOverloadCandidateSimple(
- const SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
- if (Cands.empty())
- return 0;
- if (Cands.size() == 1)
- return Cands[0].first;
-
- unsigned Best = 0, N = Cands.size();
- for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
- Best = I;
-
- for (unsigned I = 0; I != N; ++I)
- if (I != Best && Cands[Best].second.compatiblyIncludes(Cands[I].second))
- return 0;
-
- return Cands[Best].first;
-}
-
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
- ASTContext &Context = getASTContext();
- QualType ClassType
- = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType));
- unsigned FoundTQs;
- SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // C++ [class.copy]p2:
- // A non-template constructor for class X is a copy constructor if [...]
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isCopyConstructor(FoundTQs)) {
- if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
- (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
- Found.push_back(std::make_pair(
- const_cast<CXXConstructorDecl *>(Constructor),
- Qualifiers::fromCVRMask(FoundTQs)));
- }
- }
-
- return cast_or_null<CXXConstructorDecl>(
- GetBestOverloadCandidateSimple(Found));
-}
-
-CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const {
- for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I)
- if (I->isMoveConstructor())
- return *I;
-
- return 0;
-}
-
-CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
- ASTContext &Context = getASTContext();
- QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
- DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
-
- SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = this->lookup(Name); Op != OpEnd; ++Op) {
- // C++ [class.copy]p9:
- // A user-declared copy assignment operator is a non-static non-template
- // member function of class X with exactly one parameter of type X, X&,
- // const X&, volatile X& or const volatile X&.
- const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
- if (!Method || Method->isStatic() || Method->getPrimaryTemplate())
- continue;
-
- const FunctionProtoType *FnType
- = Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no prototype.");
- // Don't assert on this; an invalid decl might have been left in the AST.
- if (FnType->getNumArgs() != 1 || FnType->isVariadic())
- continue;
-
- QualType ArgType = FnType->getArgType(0);
- Qualifiers Quals;
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- // If we have a const argument and we have a reference to a non-const,
- // this function does not match.
- if (ArgIsConst && !ArgType.isConstQualified())
- continue;
-
- Quals = ArgType.getQualifiers();
- } else {
- // By-value copy-assignment operators are treated like const X&
- // copy-assignment operators.
- Quals = Qualifiers::fromCVRMask(Qualifiers::Const);
- }
-
- if (!Context.hasSameUnqualifiedType(ArgType, Class))
- continue;
-
- // Save this copy-assignment operator. It might be "the one".
- Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals));
- }
-
- // Use a simplistic form of overload resolution to find the candidate.
- return GetBestOverloadCandidateSimple(Found);
-}
-
-CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const {
- for (method_iterator I = method_begin(), E = method_end(); I != E; ++I)
- if (I->isMoveAssignmentOperator())
- return *I;
-
- return 0;
-}
-
void CXXRecordDecl::markedVirtualFunctionPure() {
// C++ [class.abstract]p2:
// A class is abstract if it has at least one pure virtual function.
data().Abstract = true;
}
-void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) {
- if (!CD->isCopyOrMoveConstructor())
- data().HasConstexprNonCopyMoveConstructor = true;
-
- if (CD->isDefaultConstructor())
- data().HasConstexprDefaultConstructor = true;
-}
-
void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
@@ -502,75 +436,41 @@ void CXXRecordDecl::addedMember(Decl *D) {
// A class that declares or inherits a virtual function is called a
// polymorphic class.
data().Polymorphic = true;
-
- // C++0x [class.ctor]p5
- // A default constructor is trivial [...] if:
- // -- its class has no virtual functions [...]
- data().HasTrivialDefaultConstructor = false;
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if [...]
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor, copy/move constructor, or copy/move
+ // assignment operator for a class X] is trivial [...] if:
// -- class X has no virtual functions [...]
- data().HasTrivialCopyConstructor = false;
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= SMF_Destructor;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if [...]
- // -- class X has no virtual functions [...]
- data().HasTrivialCopyAssignment = false;
- data().HasTrivialMoveAssignment = false;
-
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
// -- has no virtual functions
data().IsStandardLayout = false;
}
}
-
- if (D->isImplicit()) {
- // Notify that an implicit member was added after the definition
- // was completed.
- if (!isBeingDefined())
- if (ASTMutationListener *L = getASTMutationListener())
- L->AddedCXXImplicitMember(data().Definition, D);
-
- // If this is a special member function, note that it was added and then
- // return early.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (Constructor->isConstexpr()) {
- data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
- } else if (Constructor->isCopyConstructor()) {
- data().DeclaredCopyConstructor = true;
- } else if (Constructor->isMoveConstructor()) {
- data().DeclaredMoveConstructor = true;
- } else
- goto NotASpecialMember;
- return;
- } else if (isa<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- return;
- } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Method->isCopyAssignmentOperator())
- data().DeclaredCopyAssignment = true;
- else if (Method->isMoveAssignmentOperator())
- data().DeclaredMoveAssignment = true;
- else
- goto NotASpecialMember;
- return;
- }
-NotASpecialMember:;
- // Any other implicit declarations are handled like normal declarations.
- }
-
- // Handle (user-declared) constructors.
+ // Notify the listener if an implicit member was added after the definition
+ // was completed.
+ if (!isBeingDefined() && D->isImplicit())
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXImplicitMember(data().Definition, D);
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ // Handle constructors.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
+ if (!Constructor->isImplicit()) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ data().PlainOldData = false;
+ }
// Technically, "user-provided" is only defined for special member
// functions, but the intent of the standard is clearly that it should apply
@@ -578,47 +478,29 @@ NotASpecialMember:;
bool UserProvided = Constructor->isUserProvided();
if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (UserProvided) {
- // C++0x [class.ctor]p5:
- // A default constructor is trivial if it is not user-provided [...]
- data().HasTrivialDefaultConstructor = false;
+ SMKind |= SMF_DefaultConstructor;
+
+ if (UserProvided)
data().UserProvidedDefaultConstructor = true;
- }
- if (Constructor->isConstexpr()) {
+ if (Constructor->isConstexpr())
data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
}
- // Note when we have a user-declared copy or move constructor, which will
- // suppress the implicit declaration of those constructors.
if (!FunTmpl) {
- if (Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is not
- // user-provided [...]
- if (UserProvided)
- data().HasTrivialCopyConstructor = false;
- } else if (Constructor->isMoveConstructor()) {
- data().UserDeclaredMoveConstructor = true;
- data().DeclaredMoveConstructor = true;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is not
- // user-provided [...]
- if (UserProvided)
- data().HasTrivialMoveConstructor = false;
- }
+ unsigned Quals;
+ if (Constructor->isCopyConstructor(Quals)) {
+ SMKind |= SMF_CopyConstructor;
+
+ if (Quals & Qualifiers::Const)
+ data().HasDeclaredCopyConstructorWithConstParam = true;
+ } else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
}
- if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
- // Record if we see any constexpr constructors which are neither copy
- // nor move constructors.
+
+ // Record if we see any constexpr constructors which are neither copy
+ // nor move constructors.
+ if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
data().HasConstexprNonCopyMoveConstructor = true;
- }
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-declared
@@ -626,106 +508,99 @@ NotASpecialMember:;
// C++0x [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-provided
// constructors [...].
- if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided)
+ if (getASTContext().getLangOpts().CPlusPlus11
+ ? UserProvided : !Constructor->isImplicit())
data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- data().PlainOldData = false;
-
- return;
}
- // Handle (user-declared) destructors.
+ // Handle destructors.
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- data().UserDeclaredDestructor = true;
- data().HasIrrelevantDestructor = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class that has [...] no user-defined
- // destructor.
- // This bit is the C++03 POD bit, not the 0x one.
- data().PlainOldData = false;
-
- // C++11 [class.dtor]p5:
- // A destructor is trivial if it is not user-provided and if
- // -- the destructor is not virtual.
- if (DD->isUserProvided() || DD->isVirtual())
- data().HasTrivialDestructor = false;
+ SMKind |= SMF_Destructor;
- return;
+ if (!DD->isImplicit())
+ data().HasIrrelevantDestructor = false;
+
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if [...] the destructor is not virtual.
+ if (DD->isVirtual())
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
}
-
- // Handle (user-declared) member functions.
+
+ // Handle member functions.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isCopyAssignmentOperator()) {
- // C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined
- // copy assignment operator [...].
- // This is the C++03 bit only.
- data().PlainOldData = false;
+ SMKind |= SMF_CopyAssignment;
- // This is a copy assignment operator.
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
-
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialCopyAssignment = false;
-
- return;
+ const ReferenceType *ParamTy =
+ Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
+ if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
+ data().HasDeclaredCopyAssignmentWithConstParam = true;
}
-
- if (Method->isMoveAssignmentOperator()) {
- // This is an extension in C++03 mode, but we'll keep consistency by
- // taking a move assignment operator to induce non-POD-ness
- data().PlainOldData = false;
-
- // This is a move assignment operator.
- data().UserDeclaredMoveAssignment = true;
- data().DeclaredMoveAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialMoveAssignment = false;
- }
+ if (Method->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
// Keep the list of conversion functions up-to-date.
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
- // We don't record specializations.
- if (Conversion->getPrimaryTemplate())
- return;
-
// FIXME: We intentionally don't use the decl's access here because it
// hasn't been set yet. That's really just a misdesign in Sema.
-
- if (FunTmpl) {
+ if (Conversion->getPrimaryTemplate()) {
+ // We don't record specializations.
+ } else if (FunTmpl) {
if (FunTmpl->getPreviousDecl())
data().Conversions.replace(FunTmpl->getPreviousDecl(),
FunTmpl);
else
- data().Conversions.addDecl(FunTmpl);
+ data().Conversions.addDecl(getASTContext(), FunTmpl);
} else {
if (Conversion->getPreviousDecl())
data().Conversions.replace(Conversion->getPreviousDecl(),
Conversion);
else
- data().Conversions.addDecl(Conversion);
+ data().Conversions.addDecl(getASTContext(), Conversion);
}
}
-
+
+ if (SMKind) {
+ // If this is the first declaration of a special member, we no longer have
+ // an implicit trivial special member.
+ data().HasTrivialSpecialMembers &=
+ data().DeclaredSpecialMembers | ~SMKind;
+
+ if (!Method->isImplicit() && !Method->isUserProvided()) {
+ // This method is user-declared but not user-provided. We can't work out
+ // whether it's trivial yet (not until we get to the end of the class).
+ // We'll handle this method in finishedDefaultedOrDeletedMember.
+ } else if (Method->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+
+ // Note when we have declared a declared special member, and suppress the
+ // implicit declaration of this special member.
+ data().DeclaredSpecialMembers |= SMKind;
+
+ if (!Method->isImplicit()) {
+ data().UserDeclaredSpecialMembers |= SMKind;
+
+ // C++03 [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // copy assignment operator and no user-defined destructor.
+ //
+ // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
+ // aggregates could not have any constructors, clear it even for an
+ // explicitly defaulted or deleted constructor.
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ //
+ // Also, a user-declared move assignment operator makes a class non-POD.
+ // This is an extension in C++03.
+ data().PlainOldData = false;
+ }
+ }
+
return;
}
-
+
// Handle non-static data members.
if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// C++ [class.bit]p2:
@@ -785,7 +660,8 @@ NotASpecialMember:;
data().PlainOldData = false;
if (T->isReferenceType()) {
- data().HasTrivialDefaultConstructor = false;
+ if (!Field->hasInClassInitializer())
+ data().HasUninitializedReferenceMember = true;
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -803,7 +679,7 @@ NotASpecialMember:;
// C++11 [class]p5:
// A default constructor is trivial if [...] no non-static data member
// of its class has a brace-or-equal-initializer.
- data().HasTrivialDefaultConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
// C++11 [dcl.init.aggr]p1:
// An aggregate is a [...] class with [...] no
@@ -815,16 +691,39 @@ NotASpecialMember:;
data().PlainOldData = false;
}
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of reference type
+ if (T->isReferenceType())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
+ addedClassSubobject(FieldRec);
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11:
+ // A defaulted [special member] for a class X is defined as
+ // deleted if:
+ // -- X is a union-like class that has a variant member with a
+ // non-trivial [corresponding special member]
+ if (isUnion()) {
+ if (FieldRec->hasNonTrivialMoveConstructor())
+ data().DefaultedMoveConstructorIsDeleted = true;
+ if (FieldRec->hasNonTrivialMoveAssignment())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+ if (FieldRec->hasNonTrivialDestructor())
+ data().DefaultedDestructorIsDeleted = true;
+ }
+
// C++0x [class.ctor]p5:
// A default constructor is trivial [...] if:
// -- for all the non-static data members of its class that are of
// class type (or array thereof), each such class has a trivial
// default constructor.
if (!FieldRec->hasTrivialDefaultConstructor())
- data().HasTrivialDefaultConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -832,13 +731,13 @@ NotASpecialMember:;
// -- for each non-static data member of X that is of class type (or
// an array thereof), the constructor selected to copy/move that
// member is trivial;
- // FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
- data().HasTrivialCopyConstructor = false;
- if (!FieldRec->hasTrivialMoveConstructor() ||
- !(FieldRec->hasDeclaredMoveConstructor() ||
- FieldRec->needsImplicitMoveConstructor()))
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the field doesn't have a simple move constructor, we'll eagerly
+ // declare the move constructor for this class and we'll decide whether
+ // it's trivial then.
+ if (!FieldRec->hasTrivialMoveConstructor())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
@@ -846,20 +745,22 @@ NotASpecialMember:;
// -- for each non-static data member of X that is of class type (or
// an array thereof), the assignment operator selected to
// copy/move that member is trivial;
- // FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
- data().HasTrivialCopyAssignment = false;
- if (!FieldRec->hasTrivialMoveAssignment() ||
- !(FieldRec->hasDeclaredMoveAssignment() ||
- FieldRec->needsImplicitMoveAssignment()))
- data().HasTrivialMoveAssignment = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the field doesn't have a simple move assignment, we'll eagerly
+ // declare the move assignment for this class and we'll decide whether
+ // it's trivial then.
+ if (!FieldRec->hasTrivialMoveAssignment())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
if (!FieldRec->hasTrivialDestructor())
- data().HasTrivialDestructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
if (!FieldRec->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
if (FieldRec->hasObjectMember())
setHasObjectMember(true);
+ if (FieldRec->hasVolatileMember())
+ setHasVolatileMember(true);
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -910,12 +811,42 @@ NotASpecialMember:;
// The standard requires any in-class initializer to be a constant
// expression. We consider this to be a defect.
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if [...] for all the non-static data
+ // members of X that are of a class type M (or array thereof), each
+ // such class type has a copy constructor whose first parameter is
+ // of type 'const M&' or 'const volatile M&'.
+ if (!FieldRec->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if [...] for all the
+ // non-static data members of X that are of a class type M (or array
+ // thereof), each such class type has a copy assignment operator whose
+ // parameter is of type 'const M&', 'const volatile M&' or 'M'.
+ if (!FieldRec->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ if (FieldRec->hasUninitializedReferenceMember() &&
+ !Field->hasInClassInitializer())
+ data().HasUninitializedReferenceMember = true;
}
} else {
// Base element type of field is a non-class type.
if (!T->isLiteralType() ||
(!Field->hasInClassInitializer() && !isUnion()))
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of const non-class type (or array
+ // thereof)
+ if (T.isConstQualified())
+ data().DefaultedMoveAssignmentIsDeleted = true;
}
// C++0x [class]p7:
@@ -943,7 +874,41 @@ NotASpecialMember:;
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
if (Shadow->getDeclName().getNameKind()
== DeclarationName::CXXConversionFunctionName)
- data().Conversions.addDecl(Shadow, Shadow->getAccess());
+ data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+}
+
+void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
+ assert(!D->isImplicit() && !D->isUserProvided());
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (Constructor->isDefaultConstructor()) {
+ SMKind |= SMF_DefaultConstructor;
+ if (Constructor->isConstexpr())
+ data().HasConstexprDefaultConstructor = true;
+ }
+ if (Constructor->isCopyConstructor())
+ SMKind |= SMF_CopyConstructor;
+ else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
+ else if (Constructor->isConstexpr())
+ // We may now know that the constructor is constexpr.
+ data().HasConstexprNonCopyMoveConstructor = true;
+ } else if (isa<CXXDestructorDecl>(D))
+ SMKind |= SMF_Destructor;
+ else if (D->isCopyAssignmentOperator())
+ SMKind |= SMF_CopyAssignment;
+ else if (D->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
+
+ // Update which trivial / non-trivial special members we have.
+ // addedMember will have skipped this step for this member.
+ if (D->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
}
bool CXXRecordDecl::isCLike() const {
@@ -1004,7 +969,7 @@ static void CollectVisibleConversions(ASTContext &Context,
bool InVirtual,
AccessSpecifier Access,
const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
- UnresolvedSetImpl &Output,
+ ASTUnresolvedSet &Output,
UnresolvedSetImpl &VOutput,
llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
// The set of types which have conversions in this class or its
@@ -1015,12 +980,13 @@ static void CollectVisibleConversions(ASTContext &Context,
// Collect the direct conversions and figure out which conversions
// will be hidden in the subclasses.
- UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
- if (!Cs.empty()) {
+ CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
+ CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
+ if (ConvI != ConvE) {
HiddenTypesBuffer = ParentHiddenTypes;
HiddenTypes = &HiddenTypesBuffer;
- for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator I = ConvI; I != ConvE; ++I) {
CanQualType ConvType(GetConversionType(Context, I.getDecl()));
bool Hidden = ParentHiddenTypes.count(ConvType);
if (!Hidden)
@@ -1039,7 +1005,7 @@ static void CollectVisibleConversions(ASTContext &Context,
if (InVirtual)
VOutput.addDecl(I.getDecl(), IAccess);
else
- Output.addDecl(I.getDecl(), IAccess);
+ Output.addDecl(Context, I.getDecl(), IAccess);
}
}
}
@@ -1066,7 +1032,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// bases. It might be worth special-casing that, really.
static void CollectVisibleConversions(ASTContext &Context,
CXXRecordDecl *Record,
- UnresolvedSetImpl &Output) {
+ ASTUnresolvedSet &Output) {
// The collection of all conversions in virtual bases that we've
// found. These will be added to the output as long as they don't
// appear in the hidden-conversions set.
@@ -1081,10 +1047,11 @@ static void CollectVisibleConversions(ASTContext &Context,
// Go ahead and collect the direct conversions and add them to the
// hidden-types set.
- UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
- Output.append(Cs.begin(), Cs.end());
- for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
- HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
+ CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
+ CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
+ Output.append(Context, ConvI, ConvE);
+ for (; ConvI != ConvE; ++ConvI)
+ HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl()));
// Recursively collect conversions from base classes.
for (CXXRecordDecl::base_class_iterator
@@ -1101,22 +1068,24 @@ static void CollectVisibleConversions(ASTContext &Context,
for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
I != E; ++I) {
if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
- Output.addDecl(I.getDecl(), I.getAccess());
+ Output.addDecl(Context, I.getDecl(), I.getAccess());
}
}
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
-const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
+std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
+CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
- return &data().Conversions;
+ return std::make_pair(data().Conversions.begin(), data().Conversions.end());
// If visible conversion list is already evaluated, return it.
- if (data().ComputedVisibleConversions)
- return &data().VisibleConversions;
- CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
- data().ComputedVisibleConversions = true;
- return &data().VisibleConversions;
+ if (!data().ComputedVisibleConversions) {
+ CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
+ data().ComputedVisibleConversions = true;
+ }
+ return std::make_pair(data().VisibleConversions.begin(),
+ data().VisibleConversions.end());
}
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1131,7 +1100,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// with sufficiently large numbers of directly-declared conversions
// that asymptotic behavior matters.
- UnresolvedSetImpl &Convs = *getConversionFunctions();
+ ASTUnresolvedSet &Convs = data().Conversions;
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
@@ -1151,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
return 0;
}
-MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
- return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
-}
-
void
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
@@ -1200,12 +1165,11 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
= Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(ClassType));
- DeclContext::lookup_const_iterator I, E;
- llvm::tie(I, E) = lookup(Name);
- if (I == E)
+ DeclContext::lookup_const_result R = lookup(Name);
+ if (R.empty())
return 0;
- CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
+ CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
return Dtor;
}
@@ -1225,12 +1189,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
// non-trivial.
struct DefinitionData &Data = data();
Data.PlainOldData = false;
- Data.HasTrivialDefaultConstructor = false;
- Data.HasTrivialCopyConstructor = false;
- Data.HasTrivialMoveConstructor = false;
- Data.HasTrivialCopyAssignment = false;
- Data.HasTrivialMoveAssignment = false;
- Data.HasTrivialDestructor = false;
+ Data.HasTrivialSpecialMembers = 0;
Data.HasIrrelevantDestructor = false;
}
@@ -1270,7 +1229,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
for (UnresolvedSetIterator I = data().Conversions.begin(),
E = data().Conversions.end();
I != E; ++I)
- data().Conversions.setAccess(I, (*I)->getAccess());
+ I.setAccess((*I)->getAccess());
}
bool CXXRecordDecl::mayBeAbstract() const {
@@ -1292,6 +1251,42 @@ bool CXXRecordDecl::mayBeAbstract() const {
void CXXMethodDecl::anchor() { }
+bool CXXMethodDecl::isStatic() const {
+ const CXXMethodDecl *MD = this;
+ for (;;) {
+ const CXXMethodDecl *C = MD->getCanonicalDecl();
+ if (C != MD) {
+ MD = C;
+ continue;
+ }
+
+ FunctionTemplateSpecializationInfo *Info =
+ MD->getTemplateSpecializationInfo();
+ if (!Info)
+ break;
+ MD = cast<CXXMethodDecl>(Info->getTemplate()->getTemplatedDecl());
+ }
+
+ if (MD->getStorageClass() == SC_Static)
+ return true;
+
+ DeclarationName Name = getDeclName();
+ // [class.free]p1:
+ // Any allocation function for a class T is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New)
+ return true;
+
+ // [class.free]p6 Any deallocation function for a class X is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_Delete ||
+ Name.getCXXOverloadedOperator() == OO_Array_Delete)
+ return true;
+
+ return false;
+}
+
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
const CXXMethodDecl *BaseMD) {
for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
@@ -1324,7 +1319,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
}
lookup_const_result Candidates = RD->lookup(getDeclName());
- for (NamedDecl * const * I = Candidates.first; I != Candidates.second; ++I) {
+ for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I);
if (!MD)
continue;
@@ -1353,10 +1348,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline,
+ StorageClass SC, bool isInline,
bool isConstexpr, SourceLocation EndLocation) {
return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
- isStatic, SCAsWritten, isInline, isConstexpr,
+ SC, isInline, isConstexpr,
EndLocation);
}
@@ -1364,7 +1359,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl));
return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(),
DeclarationNameInfo(), QualType(),
- 0, false, SC_None, false, false,
+ 0, SC_None, false, false,
SourceLocation());
}
@@ -1399,9 +1394,10 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
// This function is a usual deallocation function if there are no
// single-parameter deallocation functions of the same kind.
- for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
- R.first != R.second; ++R.first) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first))
+ DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end();
+ I != E; ++I) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
if (FD->getNumParams() == 1)
return false;
}
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 553d170fc3d5..37a812e71aae 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -27,7 +27,8 @@ FriendDecl *FriendDecl::getNextFriendSlowCase() {
FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
FriendUnion Friend,
- SourceLocation FriendL) {
+ SourceLocation FriendL,
+ ArrayRef<TemplateParameterList*> FriendTypeTPLists) {
#ifndef NDEBUG
if (Friend.is<NamedDecl*>()) {
NamedDecl *D = Friend.get<NamedDecl*>();
@@ -40,15 +41,25 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
// to the original declaration when instantiating members.
assert(D->getFriendObjectKind() ||
(cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
+ // These template parameters are for friend types only.
+ assert(FriendTypeTPLists.size() == 0);
}
#endif
- FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL);
+ 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);
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
-FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendDecl));
- return new (Mem) FriendDecl(EmptyShell());
+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);
}
+
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index 036acc2d77a5..9861f2278f9a 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclGroup.h"
-#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "llvm/Support/Allocator.h"
using namespace clang;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 65a987836ff8..5f5ba52947d6 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -13,8 +13,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Stmt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -53,8 +54,9 @@ void ObjCContainerDecl::anchor() { }
///
ObjCIvarDecl *
ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
- lookup_const_iterator Ivar, IvarEnd;
- for (llvm::tie(Ivar, IvarEnd) = lookup(Id); Ivar != IvarEnd; ++Ivar) {
+ lookup_const_result R = lookup(Id);
+ for (lookup_const_iterator Ivar = R.begin(), IvarEnd = R.end();
+ Ivar != IvarEnd; ++Ivar) {
if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar))
return ivar;
}
@@ -63,7 +65,16 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
// Get the local instance/class method declared in this interface.
ObjCMethodDecl *
-ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
+ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
+ bool AllowHidden) const {
+ // If this context is a hidden protocol definition, don't find any
+ // methods there.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden() && !AllowHidden)
+ return 0;
+ }
+
// Since instance & class methods can have the same name, the loop below
// ensures we get the correct method.
//
@@ -72,8 +83,9 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
// + (float) class_method;
// @end
//
- lookup_const_iterator Meth, MethEnd;
- for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) {
+ lookup_const_result R = lookup(Sel);
+ for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
+ Meth != MethEnd; ++Meth) {
ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
if (MD && MD->isInstanceMethod() == isInstance)
return MD;
@@ -81,13 +93,86 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
return 0;
}
+/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter
+/// method was found in the class, its protocols, its super classes or categories.
+/// It also returns 'true' if one of its categories has declared a 'readwrite' property.
+/// This is because, user must provide a setter method for the category's 'readwrite'
+/// property.
+bool
+ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const {
+ Selector Sel = Property->getSetterName();
+ lookup_const_result R = lookup(Sel);
+ for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod() && !MD->isImplicit())
+ return true;
+ }
+
+ 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) {
+ if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel))
+ if (!MD->isImplicit())
+ return true;
+ if (Cat->IsClassExtension())
+ continue;
+ // 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)
+ if (P->getIdentifier() == Property->getIdentifier()) {
+ if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite)
+ return true;
+ break;
+ }
+ }
+
+ // 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);
+ if (Proto->HasUserDeclaredSetterMethod(Property))
+ return true;
+ }
+ // And in its super class.
+ ObjCInterfaceDecl *OSC = ID->getSuperClass();
+ while (OSC) {
+ if (OSC->HasUserDeclaredSetterMethod(Property))
+ return true;
+ OSC = OSC->getSuperClass();
+ }
+ }
+ 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))
+ return true;
+ }
+ return false;
+}
+
ObjCPropertyDecl *
ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
IdentifierInfo *propertyID) {
+ // If this context is a hidden protocol definition, don't find any
+ // property.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden())
+ return 0;
+ }
- DeclContext::lookup_const_iterator I, E;
- llvm::tie(I, E) = DC->lookup(propertyID);
- for ( ; I != E; ++I)
+ DeclContext::lookup_const_result R = DC->lookup(propertyID);
+ for (DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); I != E;
+ ++I)
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
return PD;
@@ -108,6 +193,12 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *
ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
+ // Don't find properties within hidden protocol definitions.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden())
+ return 0;
+ }
if (ObjCPropertyDecl *PD =
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
@@ -126,12 +217,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
}
case Decl::ObjCInterface: {
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
- // Look through categories.
- for (ObjCCategoryDecl *Cat = OID->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory())
+ // Look through categories (but not extensions).
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = OID->visible_categories_begin(),
+ CatEnd = OID->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
if (!Cat->IsClassExtension())
if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
return P;
+ }
// Look through protocols.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -190,21 +284,43 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return 0;
}
-void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const {
for (ObjCContainerDecl::prop_iterator P = prop_begin(),
E = prop_end(); P != E; ++P) {
ObjCPropertyDecl *Prop = *P;
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);
+ (*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.
}
+bool ObjCInterfaceDecl::isArcWeakrefUnavailable() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ArcWeakrefUnavailableAttr>())
+ return true;
+ Class = Class->getSuperClass();
+ }
+ return false;
+}
+
+const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>())
+ return Class;
+ Class = Class->getSuperClass();
+ }
+ return 0;
+}
+
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
@@ -254,8 +370,8 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
void ObjCInterfaceDecl::allocateDefinitionData() {
assert(!hasDefinition() && "ObjC class already has a definition");
- Data = new (getASTContext()) DefinitionData();
- Data->Definition = this;
+ Data.setPointer(new (getASTContext()) DefinitionData());
+ Data.getPointer()->Definition = this;
// Make the type point at the definition, now that we have one.
if (TypeForDecl)
@@ -273,24 +389,6 @@ void ObjCInterfaceDecl::startDefinition() {
}
}
-/// getFirstClassExtension - Find first class extension of the given class.
-ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const {
- for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- return CDecl;
- return 0;
-}
-
-/// getNextClassCategory - Find next class extension in list of categories.
-const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const {
- for (const ObjCCategoryDecl *CDecl = getNextClassCategory(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- return CDecl;
- return 0;
-}
-
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
// FIXME: Should make sure no callers ever do this.
@@ -306,9 +404,12 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
clsDeclared = ClassDecl;
return I;
}
- for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
- CDecl; CDecl = CDecl->getNextClassExtension()) {
- if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) {
+
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = ClassDecl->visible_extensions_begin(),
+ ExtEnd = ClassDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) {
clsDeclared = ClassDecl;
return I;
}
@@ -367,21 +468,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
return MethodDecl;
// Didn't find one yet - now look through categories.
- ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
- while (CatDecl) {
- if ((MethodDecl = CatDecl->getMethod(Sel, isInstance)))
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ClassDecl->visible_categories_begin(),
+ CatEnd = ClassDecl->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
return MethodDecl;
if (!shallowCategoryLookup) {
// Didn't find one yet - look through protocols.
const ObjCList<ObjCProtocolDecl> &Protocols =
- CatDecl->getReferencedProtocols();
+ Cat->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
return MethodDecl;
}
- CatDecl = CatDecl->getNextClassCategory();
}
ClassDecl = ClassDecl->getSuperClass();
@@ -753,7 +855,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
if (MovedToSuper)
if (ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
if (Method != Overridden) {
// We found an override at this category; there is no need to look
// into its protocols.
@@ -771,7 +874,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
// Check whether we have a matching method at this level.
if (const ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
if (Method != Overridden) {
// We found an override at this level; there is no need to look
// into other protocols or categories.
@@ -793,10 +897,13 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
- for (const ObjCCategoryDecl *Category = Interface->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethodsRecurse(Category, Method, Methods,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Interface->known_categories_begin(),
+ CatEnd = Interface->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CollectOverriddenMethodsRecurse(*Cat, Method, Methods,
MovedToSuper);
+ }
if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
return CollectOverriddenMethodsRecurse(Super, Method, Methods,
@@ -827,7 +934,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
@@ -839,7 +947,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
@@ -858,11 +967,14 @@ static void collectOnCategoriesAfterLocation(SourceLocation Loc,
if (!Class)
return;
- for (const ObjCCategoryDecl *Category = Class->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
- CollectOverriddenMethodsRecurse(Category, Method, Methods, true);
-
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation()))
+ CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true);
+ }
+
collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
Method, Methods);
}
@@ -924,6 +1036,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) {
const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
+ // If container is class extension, find its primary class.
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(Container))
+ if (CatDecl->IsClassExtension())
+ Container = CatDecl->getClassInterface();
+
bool IsGetter = (NumArgs == 0);
for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(),
@@ -967,6 +1084,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
bool isInternal){
ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
PrevDecl, isInternal);
+ Result->Data.setInt(!C.getLangOpts().Modules);
C.getObjCInterfaceType(Result, PrevDecl);
return Result;
}
@@ -974,8 +1092,11 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl));
- return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
- 0, false);
+ ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(),
+ 0, SourceLocation(),
+ 0, false);
+ Result->Data.setInt(!C.getLangOpts().Modules);
+ return Result;
}
ObjCInterfaceDecl::
@@ -1026,49 +1147,96 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
getASTContext().setObjCImplementation(getDefinition(), ImplD);
}
+namespace {
+ struct SynthesizeIvarChunk {
+ uint64_t Size;
+ ObjCIvarDecl *Ivar;
+ SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar)
+ : Size(size), Ivar(ivar) {}
+ };
+
+ bool operator<(const SynthesizeIvarChunk & LHS,
+ const SynthesizeIvarChunk &RHS) {
+ return LHS.Size < RHS.Size;
+ }
+}
+
/// all_declared_ivar_begin - return first ivar declared in this class,
/// its extensions and its implementation. Lazily build the list on first
/// access.
+///
+/// Caveat: The list returned by this method reflects the current
+/// state of the parser. The cache will be updated for every ivar
+/// added by an extension or the implementation when they are
+/// encountered.
+/// See also ObjCIvarDecl::Create().
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
- if (data().IvarList)
- return data().IvarList;
-
ObjCIvarDecl *curIvar = 0;
- if (!ivar_empty()) {
- ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
- data().IvarList = *I; ++I;
- for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
- }
-
- for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl;
- CDecl = CDecl->getNextClassExtension()) {
- if (!CDecl->ivar_empty()) {
- ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
- E = CDecl->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
- }
- for ( ;I != E; curIvar = *I, ++I)
+ if (!data().IvarList) {
+ if (!ivar_empty()) {
+ ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
+ data().IvarList = *I; ++I;
+ for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
+
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = known_extensions_begin(),
+ ExtEnd = known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (!Ext->ivar_empty()) {
+ ObjCCategoryDecl::ivar_iterator
+ I = Ext->ivar_begin(),
+ E = Ext->ivar_end();
+ if (!data().IvarList) {
+ data().IvarList = *I; ++I;
+ curIvar = data().IvarList;
+ }
+ for ( ;I != E; curIvar = *I, ++I)
+ curIvar->setNextIvar(*I);
+ }
+ }
+ data().IvarListMissingImplementation = true;
}
+
+ // cached and complete!
+ if (!data().IvarListMissingImplementation)
+ return data().IvarList;
if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
+ data().IvarListMissingImplementation = false;
if (!ImplDecl->ivar_empty()) {
- ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
- E = ImplDecl->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
+ SmallVector<SynthesizeIvarChunk, 16> layout;
+ for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+ E = ImplDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *IV = *I;
+ if (IV->getSynthesize() && !IV->isInvalidDecl()) {
+ layout.push_back(SynthesizeIvarChunk(
+ IV->getASTContext().getTypeSize(IV->getType()), IV));
+ continue;
+ }
+ if (!data().IvarList)
+ data().IvarList = *I;
+ else
+ curIvar->setNextIvar(*I);
+ curIvar = *I;
+ }
+
+ if (!layout.empty()) {
+ // Order synthesized ivars by their size.
+ std::stable_sort(layout.begin(), layout.end());
+ unsigned Ix = 0, EIx = layout.size();
+ if (!data().IvarList) {
+ data().IvarList = layout[0].Ivar; Ix++;
+ curIvar = data().IvarList;
+ }
+ for ( ; Ix != EIx; curIvar = layout[Ix].Ivar, Ix++)
+ curIvar->setNextIvar(layout[Ix].Ivar);
}
- for ( ;I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
}
}
return data().IvarList;
@@ -1087,29 +1255,41 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
if (data().ExternallyCompleted)
LoadExternalDefinition();
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (Category->getIdentifier() == CategoryId)
- return Category;
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (Cat->getIdentifier() == CategoryId)
+ return *Cat;
+ }
+
return 0;
}
ObjCMethodDecl *
ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const {
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel))
return MD;
+ }
+
return 0;
}
ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel))
return MD;
+ }
+
return 0;
}
@@ -1141,10 +1321,13 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
// 2nd, look up the category.
if (lookupCategory)
- for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory()) {
- for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
- E = CDecl->protocol_end(); PI != E; ++PI)
+ 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))
return true;
}
@@ -1274,15 +1457,17 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
ObjCProtocolDecl *PrevDecl) {
ObjCProtocolDecl *Result
= new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl);
-
+ Result->Data.setInt(!C.getLangOpts().Modules);
return Result;
}
ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl));
- return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(),
- 0);
+ ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(),
+ SourceLocation(), 0);
+ Result->Data.setInt(!C.getLangOpts().Modules);
+ return Result;
}
ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
@@ -1304,6 +1489,12 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
bool isInstance) const {
ObjCMethodDecl *MethodDecl = NULL;
+ // 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;
+
if ((MethodDecl = getMethod(Sel, isInstance)))
return MethodDecl;
@@ -1314,9 +1505,9 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
}
void ObjCProtocolDecl::allocateDefinitionData() {
- assert(!Data && "Protocol already has a definition!");
- Data = new (getASTContext()) DefinitionData;
- Data->Definition = this;
+ assert(!Data.getPointer() && "Protocol already has a definition!");
+ Data.setPointer(new (getASTContext()) DefinitionData);
+ Data.getPointer()->Definition = this;
}
void ObjCProtocolDecl::startDefinition() {
@@ -1328,17 +1519,22 @@ void ObjCProtocolDecl::startDefinition() {
RD->Data = this->Data;
}
-void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const {
- for (ObjCProtocolDecl::prop_iterator P = prop_begin(),
- E = prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- // Insert into PM if not there already.
- PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+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;
+ // 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);
}
- // Scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(),
- E = protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM);
}
@@ -1362,9 +1558,9 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
IvarLBraceLoc, IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
- CatDecl->NextClassCategory = IDecl->getCategoryList();
+ CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
if (IDecl->hasDefinition()) {
- IDecl->setCategoryList(CatDecl);
+ IDecl->setCategoryListRaw(CatDecl);
if (ASTMutationListener *L = C.getASTMutationListener())
L->AddedObjCCategoryToInterface(CatDecl, IDecl);
}
@@ -1450,7 +1646,7 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) {
}
/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
-/// properties implemented in this category \@implementation block and returns
+/// properties implemented in this \@implementation block and returns
/// the implemented property that uses it.
///
ObjCPropertyImplDecl *ObjCImplDecl::
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
new file mode 100644
index 000000000000..c0d10a0f418c
--- /dev/null
+++ b/lib/AST/DeclOpenMP.cpp
@@ -0,0 +1,60 @@
+//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements OMPThreadPrivateDecl class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// OMPThreadPrivateDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPThreadPrivateDecl::anchor() { }
+
+OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ ArrayRef<DeclRefExpr *> VL) {
+ unsigned Size = sizeof(OMPThreadPrivateDecl) +
+ (VL.size() * sizeof(DeclRefExpr *));
+
+ void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
+ OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
+ DC, L);
+ D->NumVars = VL.size();
+ D->setVars(VL);
+ return D;
+}
+
+OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID,
+ unsigned N) {
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
+ 0, SourceLocation());
+ D->NumVars = N;
+ return D;
+}
+
+void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+ assert(VL.size() == NumVars &&
+ "Number of variables is not the same as the preallocated buffer");
+ DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+ std::copy(VL.begin(), VL.end(), Vars);
+}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 386ad66c9917..c3bf8f89b297 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -7,15 +7,16 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Decl::dump method, which pretty print the
+// This file implements the Decl::print method, which pretty prints the
// AST back out to C/Objective-C/C++/Objective-C++ code.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
@@ -50,7 +51,9 @@ namespace {
void VisitEnumDecl(EnumDecl *D);
void VisitRecordDecl(RecordDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitEmptyDecl(EmptyDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
void VisitLabelDecl(LabelDecl *D);
@@ -79,9 +82,10 @@ namespace {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
- const TemplateArgumentList *Args);
+ const TemplateArgumentList *Args = 0);
void prettyPrintAttributes(Decl *D);
};
}
@@ -174,16 +178,6 @@ void DeclContext::dumpDeclContext() const {
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
-void Decl::dump() const {
- dump(llvm::errs());
-}
-
-void Decl::dump(raw_ostream &Out) const {
- PrintingPolicy Policy = getASTContext().getPrintingPolicy();
- Policy.DumpSourceManager = &getASTContext().getSourceManager();
- print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true);
-}
-
raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
@@ -191,7 +185,7 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
}
void DeclPrinter::prettyPrintAttributes(Decl *D) {
- if (Policy.SuppressAttributes)
+ if (Policy.PolishForDeclaration)
return;
if (D->hasAttrs()) {
@@ -240,18 +234,18 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
if (isa<ObjCIvarDecl>(*D))
continue;
- if (!Policy.DumpSourceManager) {
- // Skip over implicit declarations in pretty-printing mode.
- 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;
- }
+ // Skip over implicit declarations in pretty-printing mode.
+ 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;
}
}
@@ -298,8 +292,10 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
// FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = 0;
- if (isa<FunctionDecl>(*D) &&
- cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
+ if (isa<OMPThreadPrivateDecl>(*D))
+ Terminator = 0;
+ else if (isa<FunctionDecl>(*D) &&
+ cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
Terminator = 0;
else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
Terminator = 0;
@@ -395,8 +391,9 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
if (!Policy.SuppressSpecifiers) {
- switch (D->getStorageClassAsWritten()) {
+ switch (D->getStorageClass()) {
case SC_None: break;
case SC_Extern: Out << "extern "; break;
case SC_Static: Out << "static "; break;
@@ -408,6 +405,8 @@ 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())
+ Out << "explicit ";
}
PrintingPolicy SubPolicy(Policy);
@@ -483,7 +482,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
+ if (CDecl) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
E = CDecl->init_end();
@@ -545,9 +544,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Out << ")";
}
- }
- else
+ if (!Proto.empty())
+ Out << Proto;
+ } else {
+ if (FT && FT->hasTrailingReturn()) {
+ Out << "auto " << Proto << " -> ";
+ Proto.clear();
+ }
AFT->getResultType().print(Out, Policy, Proto);
+ }
} else {
Ty.print(Out, Policy, Proto);
}
@@ -558,6 +563,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << " = 0";
else if (D->isDeletedAsWritten())
Out << " = delete";
+ else if (D->isExplicitlyDefaulted())
+ Out << " = default";
else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
@@ -579,6 +586,31 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
+ if (TypeSourceInfo *TSI = D->getFriendType()) {
+ unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
+ for (unsigned i = 0; i < NumTPLists; ++i)
+ PrintTemplateParameters(D->getFriendTypeTemplateParameterList(i));
+ Out << "friend ";
+ Out << " " << TSI->getType().getAsString(Policy);
+ }
+ else if (FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitFunctionDecl(FD);
+ }
+ else if (FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitFunctionTemplateDecl(FTD);
+ }
+ else if (ClassTemplateDecl *CTD =
+ dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitRedeclarableTemplateDecl(CTD);
+ }
+}
+
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
if (!Policy.SuppressSpecifiers && D->isMutable())
Out << "mutable ";
@@ -609,9 +641,9 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
void DeclPrinter::VisitVarDecl(VarDecl *D) {
- StorageClass SCAsWritten = D->getStorageClassAsWritten();
- if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None)
- Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " ";
+ StorageClass SC = D->getStorageClass();
+ if (!Policy.SuppressSpecifiers && SC != SC_None)
+ Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
Out << "__thread ";
@@ -625,9 +657,14 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
bool ImplicitInit = false;
- if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
- ImplicitInit = D->getInitStyle() == VarDecl::CallInit &&
- Construct->getNumArgs() == 0 && !Construct->isListInitialization();
+ if (CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) {
+ if (D->getInitStyle() == VarDecl::CallInit &&
+ !Construct->isListInitialization()) {
+ ImplicitInit = Construct->getNumArgs() == 0 ||
+ Construct->getArg(0)->isDefaultArgument();
+ }
+ }
if (!ImplicitInit) {
if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << "(";
@@ -653,7 +690,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
}
void DeclPrinter::VisitImportDecl(ImportDecl *D) {
- Out << "@__experimental_modules_import " << D->getImportedModule()->getFullModuleName()
+ Out << "@import " << D->getImportedModule()->getFullModuleName()
<< ";\n";
}
@@ -690,6 +727,10 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
Out << *D->getAliasedNamespace();
}
+void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
+ prettyPrintAttributes(D);
+}
+
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
Out << "__module_private__ ";
@@ -746,8 +787,8 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::PrintTemplateParameters(
- const TemplateParameterList *Params, const TemplateArgumentList *Args = 0) {
+void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
+ const TemplateArgumentList *Args) {
assert(Params);
assert(!Args || Params->size() == Args->size());
@@ -882,6 +923,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
OMD->getBody()->printPretty(Out, 0, Policy);
Out << '\n';
}
+ else if (Policy.PolishForDeclaration)
+ Out << ';';
}
void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
@@ -892,7 +935,17 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
Out << "@implementation " << I << " : " << *SID;
else
Out << "@implementation " << I;
- Out << "\n";
+
+ 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) {
+ Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
VisitDeclContext(OID, false);
Out << "@end";
}
@@ -905,7 +958,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Out << "@class " << I << ";";
return;
}
-
+ bool eolnOut = false;
if (SID)
Out << "@interface " << I << " : " << *SID;
else
@@ -917,13 +970,12 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
Out << (I == Protocols.begin() ? '<' : ',') << **I;
- }
-
- if (!Protocols.empty())
Out << "> ";
+ }
if (OID->ivar_size() > 0) {
Out << "{\n";
+ eolnOut = true;
Indentation += Policy.Indentation;
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
E = OID->ivar_end(); I != E; ++I) {
@@ -932,19 +984,33 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation -= Policy.Indentation;
Out << "}\n";
}
+ else if (SID) {
+ Out << "\n";
+ eolnOut = true;
+ }
VisitDeclContext(OID, false);
+ if (!eolnOut)
+ Out << ' ';
Out << "@end";
// FIXME: implement the rest...
}
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
if (!PID->isThisDeclarationADefinition()) {
- Out << "@protocol " << PID->getIdentifier() << ";\n";
+ Out << "@protocol " << *PID << ";\n";
return;
}
-
- Out << "@protocol " << *PID << '\n';
+ // Protocols?
+ const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols();
+ if (!Protocols.empty()) {
+ Out << "@protocol " << *PID;
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ Out << (I == Protocols.begin() ? '<' : ',') << **I;
+ Out << ">\n";
+ } else
+ Out << "@protocol " << *PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
}
@@ -959,6 +1025,17 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
+ 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) {
+ Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
+
VisitDeclContext(PID, false);
Out << "@end";
@@ -1040,6 +1117,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
Out << " )";
}
Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl;
+ if (Policy.PolishForDeclaration)
+ Out << ';';
}
void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
@@ -1068,9 +1147,23 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getQualifier()->print(Out, Policy);
- Out << D->getDeclName();
+ Out << D->getName();
}
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
// ignore
}
+
+void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ Out << "#pragma omp threadprivate";
+ if (!D->varlist_empty()) {
+ for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',')
+ << *cast<NamedDecl>((*I)->getDecl());
+ }
+ Out << ")";
+ }
+}
+
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a70983f4c962..0b94f7d2c49b 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/AST/ASTMutationListener.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
#include <memory>
@@ -128,12 +128,12 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
-RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() {
+RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
if (!Common) {
// Walk the previous-declaration chain until we either find a declaration
// with a common pointer or we run out of previous declarations.
- llvm::SmallVector<RedeclarableTemplateDecl *, 2> PrevDecls;
- for (RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
Prev = Prev->getPreviousDecl()) {
if (Prev->Common) {
Common = Prev->Common;
@@ -184,9 +184,8 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
QualType ArgType = Context.getTypeDeclType(TTP);
if (TTP->isParameterPack())
- ArgType = Context.getPackExpansionType(ArgType,
- llvm::Optional<unsigned>());
-
+ ArgType = Context.getPackExpansionType(ArgType, None);
+
Arg = TemplateArgument(ArgType);
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
@@ -197,13 +196,12 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
if (NTTP->isParameterPack())
E = new (Context) PackExpansionExpr(Context.DependentTy, E,
- NTTP->getLocation(),
- llvm::Optional<unsigned>());
+ NTTP->getLocation(), None);
Arg = TemplateArgument(E);
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
else
Arg = TemplateArgument(TemplateName(TTP));
}
@@ -241,7 +239,7 @@ FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C,
}
RedeclarableTemplateDecl::CommonBase *
-FunctionTemplateDecl::newCommon(ASTContext &C) {
+FunctionTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
@@ -304,7 +302,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassTemplateDecl(EmptyShell());
}
-void ClassTemplateDecl::LoadLazySpecializations() {
+void ClassTemplateDecl::LoadLazySpecializations() const {
Common *CommonPtr = getCommonPtr();
if (CommonPtr->LazySpecializations) {
ASTContext &Context = getASTContext();
@@ -316,7 +314,7 @@ void ClassTemplateDecl::LoadLazySpecializations() {
}
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
-ClassTemplateDecl::getSpecializations() {
+ClassTemplateDecl::getSpecializations() const {
LoadLazySpecializations();
return getCommonPtr()->Specializations;
}
@@ -328,7 +326,7 @@ ClassTemplateDecl::getPartialSpecializations() {
}
RedeclarableTemplateDecl::CommonBase *
-ClassTemplateDecl::newCommon(ASTContext &C) {
+ClassTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
@@ -620,7 +618,7 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
- llvm::ArrayRef<TemplateParameterList*> Expansions) {
+ ArrayRef<TemplateParameterList *> Expansions) {
void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
sizeof(TemplateParameterList*) * Expansions.size());
return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
@@ -728,6 +726,8 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
SpecializedTemplate,
Args, NumArgs,
PrevDecl);
+ Result->MayHaveOutOfDateDef = false;
+
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
@@ -737,20 +737,19 @@ ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID,
sizeof(ClassTemplateSpecializationDecl));
- return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ ClassTemplateSpecializationDecl *Result =
+ new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ Result->MayHaveOutOfDateDef = false;
+ return Result;
}
-void
-ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S,
- const PrintingPolicy &Policy,
- bool Qualified) const {
- NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+void ClassTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
const TemplateArgumentList &TemplateArgs = getTemplateArgs();
- S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.data(),
- TemplateArgs.size(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
}
ClassTemplateDecl *
@@ -857,6 +856,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
PrevDecl,
SequenceNumber);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ Result->MayHaveOutOfDateDef = false;
Context.getInjectedClassNameType(Result, CanonInjectedType);
return Result;
@@ -867,7 +867,10 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID,
sizeof(ClassTemplatePartialSpecializationDecl));
- return new (Mem) ClassTemplatePartialSpecializationDecl();
+ ClassTemplatePartialSpecializationDecl *Result
+ = new (Mem) ClassTemplatePartialSpecializationDecl();
+ Result->MayHaveOutOfDateDef = false;
+ return Result;
}
//===----------------------------------------------------------------------===//
@@ -919,7 +922,7 @@ void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
static_cast<Common *>(Ptr)->~Common();
}
RedeclarableTemplateDecl::CommonBase *
-TypeAliasTemplateDecl::newCommon(ASTContext &C) {
+TypeAliasTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 28188d91c10a..e4a41b6ffb50 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -364,6 +364,21 @@ DeclarationNameTable::~DeclarationNameTable() {
delete LiteralNames;
}
+DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConstructorName,
+ Ty.getUnqualifiedType());
+}
+
+DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXDestructorName,
+ Ty.getUnqualifiedType());
+}
+
+DeclarationName
+DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
+}
+
DeclarationName
DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
CanQualType Ty) {
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 5f43fbc251a0..be22ae450b62 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -17,6 +17,7 @@
// Only pay for this in code size in assertions-enabled builds.
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
@@ -37,8 +38,6 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -500,8 +499,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
- for (llvm::ArrayRef<NamedDecl*>::iterator
- I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end();
+ for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(),
+ E = D->getDeclsInPrototypeScope().end();
I != E; ++I)
dispatch(*I);
if (D->doesThisDeclarationHaveABody())
@@ -749,14 +748,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
visitDeclContext(D);
}
- // ObjCInterfaceDecl
- void visitCategoryList(ObjCCategoryDecl *D) {
- if (!D) return;
-
- TemporaryContainer C(*this, "categories");
- for (; D; D = D->getNextClassCategory())
- visitDeclRef(D);
- }
void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
setPointer("typeptr", D->getTypeForDecl());
setFlag("forward_decl", !D->isThisDeclarationADefinition());
@@ -771,7 +762,17 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
visitDeclRef(*I);
}
- visitCategoryList(D->getCategoryList());
+
+ if (!D->visible_categories_empty()) {
+ TemporaryContainer C(*this, "categories");
+
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = D->visible_categories_begin(),
+ CatEnd = D->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ visitDeclRef(*Cat);
+ }
+ }
}
void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
visitDeclContext(D);
@@ -923,6 +924,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
case CC_AAPCS: return set("cc", "aapcs");
case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
case CC_PnaclCall: return set("cc", "pnaclcall");
+ case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc");
}
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index f3a2e0563872..b97f4d1d3a9a 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -11,22 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -277,7 +279,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
// - an entity with reference type and is initialized with an
// expression that is value-dependent [C++11]
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- if ((Ctx.getLangOpts().CPlusPlus0x ?
+ if ((Ctx.getLangOpts().CPlusPlus11 ?
Var->getType()->isLiteralType() :
Var->getType()->isIntegralOrEnumerationType()) &&
(Var->getType().isConstQualified() ||
@@ -444,14 +446,6 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
return new (Mem) DeclRefExpr(EmptyShell());
}
-SourceRange DeclRefExpr::getSourceRange() const {
- SourceRange R = getNameInfo().getSourceRange();
- if (hasQualifier())
- R.setBegin(getQualifierLoc().getBeginLoc());
- if (hasExplicitTemplateArgs())
- R.setEnd(getRAngleLoc());
- return R;
-}
SourceLocation DeclRefExpr::getLocStart() const {
if (hasQualifier())
return getQualifierLoc().getBeginLoc();
@@ -483,8 +477,9 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
}
PrintingPolicy Policy(Context.getLangOpts());
- std::string Proto = FD->getQualifiedNameAsString(Policy);
+ std::string Proto;
llvm::raw_string_ostream POut(Proto);
+ FD->printQualifiedName(POut, Policy);
const FunctionDecl *Decl = FD;
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
@@ -509,7 +504,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut << ")";
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const FunctionType *FT = cast<FunctionType>(MD->getType().getTypePtr());
+ const FunctionType *FT = MD->getType()->castAs<FunctionType>();
if (FT->isConst())
POut << " const";
if (FT->isVolatile())
@@ -653,16 +648,14 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
false, false), Loc(L) {
- FloatingLiteralBits.IsIEEE =
- &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ setSemantics(V.getSemantics());
FloatingLiteralBits.IsExact = isexact;
setValue(C, V);
}
FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
- FloatingLiteralBits.IsIEEE =
- &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ setRawSemantics(IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
@@ -677,6 +670,41 @@ FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
+const llvm::fltSemantics &FloatingLiteral::getSemantics() const {
+ switch(FloatingLiteralBits.Semantics) {
+ case IEEEhalf:
+ return llvm::APFloat::IEEEhalf;
+ case IEEEsingle:
+ return llvm::APFloat::IEEEsingle;
+ case IEEEdouble:
+ return llvm::APFloat::IEEEdouble;
+ case x87DoubleExtended:
+ return llvm::APFloat::x87DoubleExtended;
+ case IEEEquad:
+ return llvm::APFloat::IEEEquad;
+ case PPCDoubleDouble:
+ return llvm::APFloat::PPCDoubleDouble;
+ }
+ llvm_unreachable("Unrecognised floating semantics");
+}
+
+void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) {
+ if (&Sem == &llvm::APFloat::IEEEhalf)
+ FloatingLiteralBits.Semantics = IEEEhalf;
+ else if (&Sem == &llvm::APFloat::IEEEsingle)
+ FloatingLiteralBits.Semantics = IEEEsingle;
+ else if (&Sem == &llvm::APFloat::IEEEdouble)
+ FloatingLiteralBits.Semantics = IEEEdouble;
+ else if (&Sem == &llvm::APFloat::x87DoubleExtended)
+ FloatingLiteralBits.Semantics = x87DoubleExtended;
+ else if (&Sem == &llvm::APFloat::IEEEquad)
+ FloatingLiteralBits.Semantics = IEEEquad;
+ else if (&Sem == &llvm::APFloat::PPCDoubleDouble)
+ FloatingLiteralBits.Semantics = PPCDoubleDouble;
+ else
+ llvm_unreachable("Unknown floating semantics");
+}
+
/// getValueAsApproximateDouble - This returns the value as an inaccurate
/// double. Note that this may cause loss of precision, but is useful for
/// debugging dumps, etc.
@@ -745,7 +773,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
return SL;
}
-void StringLiteral::outputString(raw_ostream &OS) {
+void StringLiteral::outputString(raw_ostream &OS) const {
switch (getKind()) {
case Ascii: break; // no prefix.
case Wide: OS << 'L'; break;
@@ -818,7 +846,7 @@ void StringLiteral::outputString(raw_ostream &OS) {
assert(Char <= 0xff &&
"Characters above 0xff should already have been handled.");
- if (isprint(Char))
+ if (isPrintable(Char))
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -1144,6 +1172,12 @@ unsigned CallExpr::isBuiltinCall() const {
return FDecl->getBuiltinID();
}
+bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
+ if (unsigned BI = isBuiltinCall())
+ return Ctx.BuiltinInfo.isUnevaluated(BI);
+ return false;
+}
+
QualType CallExpr::getCallReturnType() const {
QualType CalleeType = getCallee()->getType();
if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>())
@@ -1158,21 +1192,9 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
-SourceRange CallExpr::getSourceRange() const {
- if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange();
-
- SourceLocation begin = getCallee()->getLocStart();
- if (begin.isInvalid() && getNumArgs() > 0)
- begin = getArg(0)->getLocStart();
- SourceLocation end = getRParenLoc();
- if (end.isInvalid() && getNumArgs() > 0)
- end = getArg(getNumArgs() - 1)->getLocEnd();
- return SourceRange(begin, end);
-}
SourceLocation CallExpr::getLocStart() const {
if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange().getBegin();
+ return cast<CXXOperatorCallExpr>(this)->getLocStart();
SourceLocation begin = getCallee()->getLocStart();
if (begin.isInvalid() && getNumArgs() > 0)
@@ -1181,7 +1203,7 @@ SourceLocation CallExpr::getLocStart() const {
}
SourceLocation CallExpr::getLocEnd() const {
if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange().getEnd();
+ return cast<CXXOperatorCallExpr>(this)->getLocEnd();
SourceLocation end = getRParenLoc();
if (end.isInvalid() && getNumArgs() > 0)
@@ -1309,9 +1331,6 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
return E;
}
-SourceRange MemberExpr::getSourceRange() const {
- return SourceRange(getLocStart(), getLocEnd());
-}
SourceLocation MemberExpr::getLocStart() const {
if (isImplicitAccess()) {
if (hasQualifier())
@@ -1416,6 +1435,7 @@ void CastExpr::CheckCastConsistency() const {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_ZeroToOCLEvent:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
@@ -1547,6 +1567,8 @@ const char *CastExpr::getCastKindName() const {
return "CopyAndAutoreleaseBlockObject";
case CK_BuiltinFnToFnPtr:
return "BuiltinFnToFnPtr";
+ case CK_ZeroToOCLEvent:
+ return "ZeroToOCLEvent";
}
llvm_unreachable("Unhandled cast kind!");
@@ -1807,10 +1829,10 @@ bool InitListExpr::isStringLiteralInit() const {
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
}
-SourceRange InitListExpr::getSourceRange() const {
+SourceLocation InitListExpr::getLocStart() const {
if (InitListExpr *SyntacticForm = getSyntacticForm())
- return SyntacticForm->getSourceRange();
- SourceLocation Beg = LBraceLoc, End = RBraceLoc;
+ return SyntacticForm->getLocStart();
+ SourceLocation Beg = LBraceLoc;
if (Beg.isInvalid()) {
// Find the first non-null initializer.
for (InitExprsTy::const_iterator I = InitExprs.begin(),
@@ -1822,18 +1844,25 @@ SourceRange InitListExpr::getSourceRange() const {
}
}
}
+ return Beg;
+}
+
+SourceLocation InitListExpr::getLocEnd() const {
+ if (InitListExpr *SyntacticForm = getSyntacticForm())
+ return SyntacticForm->getLocEnd();
+ SourceLocation End = RBraceLoc;
if (End.isInvalid()) {
// Find the first non-null initializer from the end.
for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(),
- E = InitExprs.rend();
- I != E; ++I) {
+ E = InitExprs.rend();
+ I != E; ++I) {
if (Stmt *S = *I) {
- End = S->getSourceRange().getEnd();
+ End = S->getLocEnd();
break;
- }
+ }
}
}
- return SourceRange(Beg, End);
+ return End;
}
/// getFunctionType - Return the underlying function type for this block.
@@ -2115,10 +2144,6 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
}
- // Ignore casts within macro expansions.
- if (getExprLoc().isMacroID())
- return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
-
// If this is a cast to a constructor conversion, check the operand.
// Otherwise, the result of the cast is unused.
if (CE->getCastKind() == CK_ConstructorConversion)
@@ -2581,7 +2606,7 @@ bool Expr::isImplicitCXXThis() const {
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
-bool Expr::hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs) {
+bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
for (unsigned I = 0; I < Exprs.size(); ++I)
if (Exprs[I]->isTypeDependent())
return true;
@@ -3025,9 +3050,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return Source->isNullPointerConstant(Ctx, NPC);
}
- // C++0x nullptr_t is always a null pointer constant.
+ // C++11 nullptr_t is always a null pointer constant.
if (getType()->isNullPtrType())
- return NPCK_CXX0X_nullptr;
+ return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
@@ -3045,7 +3070,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// test for the value 0. Don't use the C++11 constant expression semantics
// for this, for now; once the dust settles on core issue 903, we might only
// allow a literal 0 here in C++11 mode.
- if (Ctx.getLangOpts().CPlusPlus0x) {
+ if (Ctx.getLangOpts().CPlusPlus11) {
if (!isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
@@ -3683,11 +3708,11 @@ SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this);
if (size() == 1)
return DIE->getDesignator(0)->getSourceRange();
- return SourceRange(DIE->getDesignator(0)->getStartLocation(),
- DIE->getDesignator(size()-1)->getEndLocation());
+ return SourceRange(DIE->getDesignator(0)->getLocStart(),
+ DIE->getDesignator(size()-1)->getLocEnd());
}
-SourceRange DesignatedInitExpr::getSourceRange() const {
+SourceLocation DesignatedInitExpr::getLocStart() const {
SourceLocation StartLoc;
Designator &First =
*const_cast<DesignatedInitExpr*>(this)->designators_begin();
@@ -3699,30 +3724,37 @@ SourceRange DesignatedInitExpr::getSourceRange() const {
} else
StartLoc =
SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
- return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
+ return StartLoc;
+}
+
+SourceLocation DesignatedInitExpr::getLocEnd() const {
+ return getInit()->getLocEnd();
}
-Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const {
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ 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));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
-Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ 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));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
-Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ 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));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
@@ -3895,7 +3927,7 @@ Stmt::child_range ObjCMessageExpr::children() {
reinterpret_cast<Stmt **>(getArgs() + getNumArgs()));
}
-ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
+ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl *Method,
SourceRange SR)
: Expr(ObjCArrayLiteralClass, T, VK_RValue, OK_Ordinary,
@@ -3916,7 +3948,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
}
ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
- llvm::ArrayRef<Expr *> Elements,
+ ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR) {
void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 55722a2a99af..12a47fcd7829 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -11,12 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/IdentifierTable.h"
using namespace clang;
@@ -72,11 +73,8 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
}
// CXXScalarValueInitExpr
-SourceRange CXXScalarValueInitExpr::getSourceRange() const {
- SourceLocation Start = RParenLoc;
- if (TypeInfo)
- Start = TypeInfo->getTypeLoc().getBeginLoc();
- return SourceRange(Start, RParenLoc);
+SourceLocation CXXScalarValueInitExpr::getLocStart() const {
+ return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc;
}
// CXXNewExpr
@@ -180,7 +178,8 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
FunctionProtoType::ExtProtoInfo())),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
@@ -217,11 +216,11 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const {
return QualType();
}
-SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
+SourceLocation CXXPseudoDestructorExpr::getLocEnd() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
End = TInfo->getTypeLoc().getLocalSourceRange().getEnd();
- return SourceRange(Base->getLocStart(), End);
+ return End;
}
// UnresolvedLookupExpr
@@ -419,12 +418,18 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
return E;
}
-SourceRange CXXConstructExpr::getSourceRange() const {
+SourceLocation CXXConstructExpr::getLocStart() const {
if (isa<CXXTemporaryObjectExpr>(this))
- return cast<CXXTemporaryObjectExpr>(this)->getSourceRange();
+ return cast<CXXTemporaryObjectExpr>(this)->getLocStart();
+ return Loc;
+}
+
+SourceLocation CXXConstructExpr::getLocEnd() const {
+ if (isa<CXXTemporaryObjectExpr>(this))
+ return cast<CXXTemporaryObjectExpr>(this)->getLocEnd();
if (ParenRange.isValid())
- return SourceRange(Loc, ParenRange.getEnd());
+ return ParenRange.getEnd();
SourceLocation End = Loc;
for (unsigned I = getNumArgs(); I > 0; --I) {
@@ -438,7 +443,7 @@ SourceRange CXXConstructExpr::getSourceRange() const {
}
}
- return SourceRange(Loc, End);
+ return End;
}
SourceRange CXXOperatorCallExpr::getSourceRangeImpl() const {
@@ -522,13 +527,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXStaticCastExpr *E =
new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -546,13 +552,14 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXDynamicCastExpr *E =
new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -602,13 +609,14 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer =
C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
CXXReinterpretCastExpr *E =
new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -624,8 +632,9 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
- return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
+ return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
}
CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
@@ -716,19 +725,24 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
ArrayRef<Expr*> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
Cons, false, Args,
- HadMultipleCandidates, /*FIXME*/false, ZeroInitialization,
+ HadMultipleCandidates,
+ ListInitialization, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
}
-SourceRange CXXTemporaryObjectExpr::getSourceRange() const {
- return SourceRange(Type->getTypeLoc().getBeginLoc(),
- getParenRange().getEnd());
+SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
+ return Type->getTypeLoc().getBeginLoc();
+}
+
+SourceLocation CXXTemporaryObjectExpr::getLocEnd() const {
+ return getParenRange().getEnd();
}
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
@@ -963,9 +977,9 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
DeclarationName Name
= Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(Calls.first != Calls.second && "Missing lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(*Calls.first++);
- assert(Calls.first == Calls.second && "More than lambda one call operator?");
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+ CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
return Result;
}
@@ -1057,8 +1071,8 @@ CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs);
}
-SourceRange CXXUnresolvedConstructExpr::getSourceRange() const {
- return SourceRange(Type->getTypeLoc().getBeginLoc(), RParenLoc);
+SourceLocation CXXUnresolvedConstructExpr::getLocStart() const {
+ return Type->getTypeLoc().getBeginLoc();
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
@@ -1330,7 +1344,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
FunctionParmPackExpr *
FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
- llvm::ArrayRef<Decl*> Params) {
+ ArrayRef<Decl *> Params) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * Params.size()))
FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 24ec6bb02074..61bc3e2de5ce 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -11,14 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/ErrorHandling.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
typedef Expr::Classification Cl;
@@ -34,21 +34,6 @@ static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
Cl::Kinds Kind, SourceLocation &Loc);
-static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
- const Expr *E,
- ExprValueKind Kind) {
- switch (Kind) {
- case VK_RValue:
- return Lang.CPlusPlus && E->getType()->isRecordType() ?
- Cl::CL_ClassTemporary : Cl::CL_PRValue;
- case VK_LValue:
- return Cl::CL_LValue;
- case VK_XValue:
- return Cl::CL_XValue;
- }
- llvm_unreachable("Invalid value category of implicit cast.");
-}
-
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
assert(!TR->isReferenceType() && "Expressions can't have reference type.");
@@ -100,6 +85,20 @@ static Cl::Kinds ClassifyTemporary(QualType T) {
return Cl::CL_PRValue;
}
+static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
+ const Expr *E,
+ ExprValueKind Kind) {
+ switch (Kind) {
+ case VK_RValue:
+ return Lang.CPlusPlus ? ClassifyTemporary(E->getType()) : Cl::CL_PRValue;
+ case VK_LValue:
+ return Cl::CL_LValue;
+ case VK_XValue:
+ return Cl::CL_XValue;
+ }
+ llvm_unreachable("Invalid value category of implicit cast.");
+}
+
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// This function takes the first stab at classifying expressions.
const LangOptions &Lang = Ctx.getLangOpts();
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6e0b5fca60c0..ae86150ee2a4 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -35,15 +35,16 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/AST/Expr.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <functional>
@@ -317,7 +318,7 @@ namespace {
OptionalDiagnostic &operator<<(const APSInt &I) {
if (Diag) {
- llvm::SmallVector<char, 32> Buffer;
+ SmallVector<char, 32> Buffer;
I.toString(Buffer);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
@@ -326,7 +327,7 @@ namespace {
OptionalDiagnostic &operator<<(const APFloat &F) {
if (Diag) {
- llvm::SmallVector<char, 32> Buffer;
+ SmallVector<char, 32> Buffer;
F.toString(Buffer);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
@@ -383,13 +384,17 @@ namespace {
/// expression is a potential constant expression? If so, some diagnostics
/// are suppressed.
bool CheckingPotentialConstantExpression;
+
+ bool IntOverflowCheckMode;
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
+ bool OverflowCheckMode=false)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), NextCallIndex(1),
BottomFrame(*this, SourceLocation(), 0, 0, 0),
EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
- CheckingPotentialConstantExpression(false) {}
+ CheckingPotentialConstantExpression(false),
+ IntOverflowCheckMode(OverflowCheckMode) {}
void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
EvaluatingDecl = VD;
@@ -473,6 +478,8 @@ namespace {
return OptionalDiagnostic();
}
+ bool getIntOverflowCheckMode() { return IntOverflowCheckMode; }
+
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
template<typename LocArg>
@@ -505,8 +512,11 @@ namespace {
/// Should we continue evaluation as much as possible after encountering a
/// construct which can't be folded?
bool keepEvaluatingAfterFailure() {
- return CheckingPotentialConstantExpression &&
- EvalStatus.Diag && EvalStatus.Diag->empty();
+ // Should return true in IntOverflowCheckMode, so that we check for
+ // overflow even if some subexpressions can't be evaluated as constants.
+ return IntOverflowCheckMode ||
+ (CheckingPotentialConstantExpression &&
+ EvalStatus.Diag && EvalStatus.Diag->empty());
}
};
@@ -534,8 +544,7 @@ namespace {
public:
SpeculativeEvaluationRAII(EvalInfo &Info,
- llvm::SmallVectorImpl<PartialDiagnosticAt>
- *NewDiag = 0)
+ SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
}
@@ -586,7 +595,7 @@ CallStackFrame::~CallStackFrame() {
}
/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) {
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
unsigned ArgIndex = 0;
bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
!isa<CXXConstructorDecl>(Frame->Callee) &&
@@ -634,7 +643,7 @@ void EvalInfo::addCallStack(unsigned Limit) {
continue;
}
- llvm::SmallVector<char, 128> Buffer;
+ SmallVector<char, 128> Buffer;
llvm::raw_svector_ostream Out(Buffer);
describeCall(Frame, Out);
addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str();
@@ -737,7 +746,7 @@ namespace {
bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
// Outside C++11, do not build a designator referring to a subobject of
// any object: we won't use such a designator for anything.
- if (!Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus11)
Designator.setInvalid();
return checkNullPointer(Info, E, CSK) &&
Designator.checkSubobject(Info, E, CSK);
@@ -971,7 +980,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// manufacture when checking potential constant expressions is conservatively
// assumed to be global here.
if (!IsGlobalLValue(Base)) {
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.Diag(Loc, diag::note_constexpr_non_global, 1)
<< IsReferenceType << !Designator.Entries.empty()
@@ -1025,7 +1034,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
return true;
// Prvalue constant expressions must be of literal types.
- if (Info.getLangOpts().CPlusPlus0x)
+ if (Info.getLangOpts().CPlusPlus11)
Info.Diag(E, diag::note_constexpr_nonliteral)
<< E->getType();
else
@@ -1462,7 +1471,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Check that we can fold the initializer. In C++, we will have already done
// this in the cases where it matters for conformance.
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
if (!VD->evaluateValue(Notes)) {
Info.Diag(E, diag::note_constexpr_var_init_non_constant,
Notes.size() + 1) << VD;
@@ -1526,7 +1535,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// A diagnostic will have already been produced.
return false;
if (Sub.isOnePastTheEnd()) {
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1548,7 +1557,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
if (CAT->getSize().ule(Index)) {
// Note, it should not be possible to form a pointer with a valid
// designator which points more than one past the end of the array.
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1570,7 +1579,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// Next subobject is a complex number.
uint64_t Index = Sub.Entries[I].ArrayIndex;
if (Index > 1) {
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1795,7 +1804,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
// We support folding of const floating-point types, in order to make
// static const data members of such types (supported as an extension)
// more useful.
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -1803,7 +1812,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
} else {
// FIXME: Allow folding of values of any literal type in all languages.
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -2080,7 +2089,7 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
// call is a core constant expression whether or not the constructor is
// constexpr.
if (!CD->isConstexpr() && !IsValueInitialization) {
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
@@ -2108,7 +2117,7 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
// FIXME: If DiagDecl is an implicitly-declared special member function, we
// should be much more explicit about why it's not constexpr.
@@ -2311,7 +2320,7 @@ private:
// Speculatively evaluate both arms.
{
- llvm::SmallVector<PartialDiagnosticAt, 8> Diag;
+ SmallVector<PartialDiagnosticAt, 8> Diag;
SpeculativeEvaluationRAII Speculate(Info, &Diag);
StmtVisitorTy::Visit(E->getFalseExpr());
@@ -2482,7 +2491,7 @@ public:
const FunctionDecl *FD = 0;
LValue *This = 0, ThisVal;
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
@@ -3487,7 +3496,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (ZeroInit && !ZeroInitialization(E))
return false;
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -3629,7 +3638,6 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
SmallVector<APValue, 4> Elts;
if (EltTy->isRealFloatingType()) {
const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy);
- bool isIEESem = &Sem != &APFloat::PPCDoubleDouble;
unsigned FloatEltSize = EltSize;
if (&Sem == &APFloat::x87DoubleExtended)
FloatEltSize = 80;
@@ -3639,7 +3647,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
Elt = SValInt.rotl(i*EltSize+FloatEltSize).trunc(FloatEltSize);
else
Elt = SValInt.rotr(i*EltSize).trunc(FloatEltSize);
- Elts.push_back(APValue(APFloat(Elt, isIEESem)));
+ Elts.push_back(APValue(APFloat(Sem, Elt)));
}
} else if (EltTy->isIntegerType()) {
for (unsigned i = 0; i < NElts; i++) {
@@ -3898,7 +3906,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return false;
}
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
cast<CXXConstructorDecl>(Definition),
Info, *Value);
@@ -4317,7 +4325,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BIstrlen:
// A call to strlen is not a constant expression.
- if (Info.getLangOpts().CPlusPlus0x)
+ if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/0 << /*isConstructor*/0 << "'strlen'";
else
@@ -4419,8 +4427,14 @@ static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
APSInt Result = Value.trunc(LHS.getBitWidth());
- if (Result.extend(BitWidth) != Value)
- HandleOverflow(Info, E, Value, E->getType());
+ if (Result.extend(BitWidth) != Value) {
+ if (Info.getIntOverflowCheckMode())
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_integer_constant_overflow)
+ << Result.toString(10) << E->getType();
+ else
+ HandleOverflow(Info, E, Value, E->getType());
+ }
return Result;
}
@@ -4707,9 +4721,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
Result);
case BO_Shl: {
- // During constant-folding, a negative shift is an opposite shift. Such
- // a shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_right;
@@ -4734,9 +4753,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(LHS << SA, E, Result);
}
case BO_Shr: {
- // During constant-folding, a negative shift is an opposite shift. Such a
- // shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_left;
@@ -5362,6 +5386,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -5849,6 +5874,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -6191,12 +6217,12 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
Result = Info.CurrentCall->Temporaries[E];
} else if (E->getType()->isVoidType()) {
- if (!Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
if (!EvaluateVoid(E, Info))
return false;
- } else if (Info.getLangOpts().CPlusPlus0x) {
+ } else if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
} else {
@@ -6249,26 +6275,39 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
}
-/// EvaluateAsRValue - Return true if this is a constant which we can fold using
-/// any crazy technique (that has nothing to do with language standards) that
-/// we want to. If this function returns true, it returns the folded constant
-/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
-/// will be applied to the result.
-bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
+ const ASTContext &Ctx, bool &IsConst) {
// Fast-path evaluations of integer literals, since we sometimes see files
// containing vast quantities of these.
- if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(this)) {
+ if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(Exp)) {
Result.Val = APValue(APSInt(L->getValue(),
L->getType()->isUnsignedIntegerType()));
+ IsConst = true;
return true;
}
-
+
// FIXME: Evaluating values of large array and record types can cause
// performance problems. Only do so in C++11 for now.
- if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
- !Ctx.getLangOpts().CPlusPlus0x)
- return false;
+ if (Exp->isRValue() && (Exp->getType()->isArrayType() ||
+ Exp->getType()->isRecordType()) &&
+ !Ctx.getLangOpts().CPlusPlus11) {
+ IsConst = false;
+ return true;
+ }
+ return false;
+}
+
+/// EvaluateAsRValue - Return true if this is a constant which we can fold using
+/// any crazy technique (that has nothing to do with language standards) that
+/// we want to. If this function returns true, it returns the folded constant
+/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
+/// will be applied to the result.
+bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+ bool IsConst;
+ if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
+ return IsConst;
+
EvalInfo Info(Ctx, Result);
return ::EvaluateAsRValue(Info, this, Result.Val);
}
@@ -6309,11 +6348,11 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
- !Ctx.getLangOpts().CPlusPlus0x)
+ !Ctx.getLangOpts().CPlusPlus11)
return false;
Expr::EvalStatus EStatus;
@@ -6353,8 +6392,10 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const {
return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects;
}
-APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
+APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
EvalResult EvalResult;
+ EvalResult.Diag = Diag;
bool Result = EvaluateAsRValue(EvalResult, Ctx);
(void)Result;
assert(Result && "Could not evaluate expression");
@@ -6363,6 +6404,17 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
return EvalResult.Val.getInt();
}
+void Expr::EvaluateForOverflow(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diags) const {
+ bool IsConst;
+ EvalResult EvalResult;
+ EvalResult.Diag = Diags;
+ if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) {
+ EvalInfo Info(Ctx, EvalResult, true);
+ (void)::EvaluateAsRValue(Info, this, EvalResult.Val);
+ }
+}
+
bool Expr::EvalResult::isGlobalLValue() const {
assert(Val.isLValue());
return IsGlobalLValue(Val.getLValueBase());
@@ -6374,54 +6426,55 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
/// comma, etc
-///
-/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
-/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
-/// cast+dereference.
// CheckICE - This function does the fundamental ICE checking: the returned
-// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// ICEDiag contains an ICEKind indicating whether the expression is an ICE,
+// and a (possibly null) SourceLocation indicating the location of the problem.
+//
// Note that to reduce code duplication, this helper does no evaluation
// itself; the caller checks whether the expression is evaluatable, and
// in the rare cases where CheckICE actually cares about the evaluated
// value, it calls into Evalute.
-//
-// Meanings of Val:
-// 0: This expression is an ICE.
-// 1: This expression is not an ICE, but if it isn't evaluated, it's
-// a legal subexpression for an ICE. This return value is used to handle
-// the comma operator in C99 mode.
-// 2: This expression is not an ICE, and is not a legal subexpression for one.
namespace {
+enum ICEKind {
+ /// This expression is an ICE.
+ IK_ICE,
+ /// This expression is not an ICE, but if it isn't evaluated, it's
+ /// a legal subexpression for an ICE. This return value is used to handle
+ /// the comma operator in C99 mode, and non-constant subexpressions.
+ IK_ICEIfUnevaluated,
+ /// This expression is not an ICE, and is not a legal subexpression for one.
+ IK_NotICE
+};
+
struct ICEDiag {
- unsigned Val;
+ ICEKind Kind;
SourceLocation Loc;
- public:
- ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
- ICEDiag() : Val(0) {}
+ ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
}
-static ICEDiag NoDiag() { return ICEDiag(); }
+static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
+
+static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
Expr::EvalResult EVResult;
if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
+ !EVResult.Val.isInt())
+ return ICEDiag(IK_NotICE, E->getLocStart());
+
return NoDiag();
}
static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
- if (!E->getType()->isIntegralOrEnumerationType()) {
- return ICEDiag(2, E->getLocStart());
- }
+ if (!E->getType()->isIntegralOrEnumerationType())
+ return ICEDiag(IK_NotICE, E->getLocStart());
switch (E->getStmtClass()) {
#define ABSTRACT_STMT(Node)
@@ -6490,7 +6543,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::AtomicExprClass:
case Expr::InitListExprClass:
case Expr::LambdaExprClass:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
@@ -6525,7 +6578,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
const CallExpr *CE = cast<CallExpr>(E);
if (CE->isBuiltinCall())
return CheckEvalInICE(E, Ctx);
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
@@ -6537,14 +6590,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// getAnyInitializer() can find a default argument, which leads
// to chaos.
if (isa<ParmVarDecl>(D))
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
// C++ 7.1.5.1p2
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
if (!Dcl->getType()->isIntegralOrEnumerationType())
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
const VarDecl *VD;
// Look for a declaration of this variable that has an initializer, and
@@ -6552,10 +6605,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE())
return NoDiag();
else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
}
}
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(E);
@@ -6569,7 +6622,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// C99 6.6/3 allows increment and decrement within unevaluated
// subexpressions of constant expressions, but they can never be ICEs
// because an ICE cannot contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case UO_Extension:
case UO_LNot:
case UO_Plus:
@@ -6579,23 +6632,23 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UO_Imag:
return CheckICE(Exp->getSubExpr(), Ctx);
}
-
+
// OffsetOf falls through here.
}
case Expr::OffsetOfExprClass: {
- // Note that per C99, offsetof must be an ICE. And AFAIK, using
- // EvaluateAsRValue matches the proposed gcc behavior for cases like
- // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
- // compliance: we should warn earlier for offsetof expressions with
- // array subscripts that aren't ICEs, and if the array subscripts
- // are ICEs, the value of the offsetof must be an integer constant.
- return CheckEvalInICE(E, Ctx);
+ // Note that per C99, offsetof must be an ICE. And AFAIK, using
+ // EvaluateAsRValue matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
+ // compliance: we should warn earlier for offsetof expressions with
+ // array subscripts that aren't ICEs, and if the array subscripts
+ // are ICEs, the value of the offsetof must be an integer constant.
+ return CheckEvalInICE(E, Ctx);
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
case Expr::BinaryOperatorClass: {
@@ -6617,7 +6670,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case BO_Mul:
case BO_Div:
@@ -6642,14 +6695,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
- if (LHSResult.Val == 0 && RHSResult.Val == 0) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx);
if (REval == 0)
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
if (REval.isSigned() && REval.isAllOnesValue()) {
llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx);
if (LEval.isMinSignedValue())
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
}
}
}
@@ -6657,22 +6710,20 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Ctx.getLangOpts().C99) {
// C99 6.6p3 introduces a strange edge case: comma can be in an ICE
// if it isn't evaluated.
- if (LHSResult.Val == 0 && RHSResult.Val == 0)
- return ICEDiag(1, E->getLocStart());
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE)
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
} else {
// In both C89 and C++, commas in ICEs are illegal.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICEIfUnevaluated) {
// Rare case where the RHS has a comma "side-effect"; we need
// to actually check the condition to see whether the side
// with the comma is evaluated.
@@ -6682,9 +6733,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
}
}
@@ -6709,7 +6758,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (FL->getValue().convertToInteger(IgnoredVal,
llvm::APFloat::rmTowardZero,
&Ignored) & APFloat::opInvalidOp)
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
}
@@ -6722,18 +6771,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case CK_IntegralCast:
return CheckICE(SubExpr, Ctx);
default:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Val == 2) return CommonResult;
+ if (CommonResult.Kind == IK_NotICE) return CommonResult;
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (FalseResult.Val == 2) return FalseResult;
- if (CommonResult.Val == 1) return CommonResult;
- if (FalseResult.Val == 1 &&
- Exp->getCommon()->EvaluateKnownConstInt(Ctx) == 0) return NoDiag();
+ if (FalseResult.Kind == IK_NotICE) return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
+ if (FalseResult.Kind == IK_ICEIfUnevaluated &&
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -6747,26 +6796,25 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
- if (CondResult.Val == 2)
+ if (CondResult.Kind == IK_NotICE)
return CondResult;
ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (TrueResult.Val == 2)
+ if (TrueResult.Kind == IK_NotICE)
return TrueResult;
- if (FalseResult.Val == 2)
+ if (FalseResult.Kind == IK_NotICE)
return FalseResult;
- if (CondResult.Val == 1)
+ if (CondResult.Kind == IK_ICEIfUnevaluated)
return CondResult;
- if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ if (TrueResult.Kind == IK_ICE && FalseResult.Kind == IK_ICE)
return NoDiag();
// Rare case where the diagnostics depend on which side is evaluated
// Note that if we get here, CondResult is 0, and at least one of
// TrueResult and FalseResult is non-zero.
- if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0) {
+ if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0)
return FalseResult;
- }
return TrueResult;
}
case Expr::CXXDefaultArgExprClass:
@@ -6799,12 +6847,12 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
}
bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
- if (Ctx.getLangOpts().CPlusPlus0x)
+ if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
- ICEDiag d = CheckICE(this, Ctx);
- if (d.Val != 0) {
- if (Loc) *Loc = d.Loc;
+ ICEDiag D = CheckICE(this, Ctx);
+ if (D.Kind != IK_ICE) {
+ if (Loc) *Loc = D.Loc;
return false;
}
return true;
@@ -6812,7 +6860,7 @@ bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
- if (Ctx.getLangOpts().CPlusPlus0x)
+ if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
if (!isIntegerConstantExpr(Ctx, Loc))
@@ -6823,7 +6871,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
}
bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
- return CheckICE(this, Ctx).Val == 0;
+ return CheckICE(this, Ctx).Kind == IK_ICE;
}
bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
@@ -6834,7 +6882,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
// Build evaluation settings.
Expr::EvalStatus Status;
- llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ SmallVector<PartialDiagnosticAt, 8> Diags;
Status.Diag = &Diags;
EvalInfo Info(Ctx, Status);
@@ -6853,7 +6901,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
}
bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
- llvm::SmallVectorImpl<
+ SmallVectorImpl<
PartialDiagnosticAt> &Diags) {
// FIXME: It would be useful to check constexpr function templates, but at the
// moment the constant expression evaluator cannot cope with the non-rigorous
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 6b9fe26ccc94..96ebe92ce3ab 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -43,10 +43,10 @@ ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return 0;
}
-DeclContextLookupResult
+bool
ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
- return DeclContext::lookup_result();
+ return false;
}
void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index b70520f44dc5..e03632a71e0e 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -134,7 +134,7 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// viewInheritance - Display the inheritance hierarchy of this C++
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
- QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
+ QualType Self = Context.getTypeDeclType(this);
std::string ErrMsg;
sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
if (Filename.isEmpty()) {
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index ce1244c54272..894eb3bff5fd 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -19,8 +19,8 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -33,10 +33,15 @@ protected:
public:
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
- unsigned getMemberPointerSize(const MemberPointerType *MPT) const {
- QualType Pointee = MPT->getPointeeType();
- if (Pointee->isFunctionType()) return 2;
- return 1;
+ std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
+ const TargetInfo &Target = Context.getTargetInfo();
+ TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
+ uint64_t Width = Target.getTypeWidth(PtrDiff);
+ unsigned Align = Target.getTypeAlign(PtrDiff);
+ if (MPT->getPointeeType()->isFunctionType())
+ Width = 2 * Width;
+ return std::make_pair(Width, Align);
}
CallingConv getDefaultMethodCallConv(bool isVariadic) const {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 851944a42b6e..21c499317f5e 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -27,8 +28,8 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#define MANGLE_CHECKER 0
@@ -355,17 +356,6 @@ private:
}
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = getEffectiveDeclContext(D);
- !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
-
- return false;
-}
-
bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// In C, functions with no attributes never need to be mangled. Fastpath them.
if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
@@ -376,20 +366,38 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (D->hasAttr<AsmLabelAttr>())
return true;
- // Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always) as does passing a C++ member function and a function
- // whose name is not a simple identifier.
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
- !FD->getDeclName().isIdentifier()))
- return true;
+ if (FD) {
+ LanguageLinkage L = FD->getLanguageLinkage();
+ // Overloadable functions need mangling.
+ if (FD->hasAttr<OverloadableAttr>())
+ return true;
+
+ // "main" is not mangled.
+ if (FD->isMain())
+ return false;
+
+ // C++ functions and those whose names are not a simple identifier need
+ // mangling.
+ if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
+ return true;
+
+ // C functions are not mangled.
+ if (L == CLanguageLinkage)
+ return false;
+ }
// Otherwise, no mangling is done outside C++ mode.
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
- // Variables at global scope with non-internal linkage are not mangled
- if (!FD) {
+ const VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (VD) {
+ // C variables are not mangled.
+ if (VD->isExternC())
+ return false;
+
+ // Variables at global scope with non-internal linkage are not mangled
const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
@@ -399,14 +407,6 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
return false;
}
- // Class members are always mangled.
- if (getEffectiveDeclContext(D)->isRecord())
- return true;
-
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
-
return true;
}
@@ -656,7 +656,7 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
assert(numCharacters != 0);
// Allocate a buffer of the right number of characters.
- llvm::SmallVector<char, 20> buffer;
+ SmallVector<char, 20> buffer;
buffer.set_size(numCharacters);
// Fill the buffer left-to-right.
@@ -1117,7 +1117,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
}
}
-
+
+ int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
+ if (UnnamedMangle != -1) {
+ Out << "Ut";
+ if (UnnamedMangle != 0)
+ Out << llvm::utostr(UnnamedMangle - 1);
+ Out << '_';
+ break;
+ }
+
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
@@ -1658,7 +1667,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// where <address-space-number> is a source name consisting of 'AS'
// followed by the address space <number>.
SmallString<64> ASString;
- ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
+ ASString = "AS" + llvm::utostr_32(
+ Context.getASTContext().getTargetAddressSpace(Quals.getAddressSpace()));
Out << 'U' << ASString.size() << ASString;
}
@@ -1870,6 +1880,14 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
+ case BuiltinType::OCLImage1d: Out << "11ocl_image1d"; break;
+ case BuiltinType::OCLImage1dArray: Out << "16ocl_image1darray"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "17ocl_image1dbuffer"; break;
+ case BuiltinType::OCLImage2d: Out << "11ocl_image2d"; break;
+ case BuiltinType::OCLImage2dArray: Out << "16ocl_image2darray"; break;
+ case BuiltinType::OCLImage3d: Out << "11ocl_image3d"; break;
+ case BuiltinType::OCLSampler: Out << "11ocl_sampler"; break;
+ case BuiltinType::OCLEvent: Out << "9ocl_event"; break;
}
}
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp
index 6f4fe2d4b4eb..54f445df4b64 100644
--- a/lib/AST/LambdaMangleContext.cpp
+++ b/lib/AST/LambdaMangleContext.cpp
@@ -23,10 +23,11 @@ unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
- QualType Key = Context.getFunctionType(Context.VoidTy,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- FunctionProtoType::ExtProtoInfo());
+ QualType Key =
+ Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index d5f83719ec62..eb794124490a 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -20,8 +20,8 @@
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#define MANGLE_CHECKER 0
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 51308ea0c0f5..6553e9d74943 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "CXXABI.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -27,13 +28,14 @@ class MicrosoftCXXABI : public CXXABI {
public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
- unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
+ std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const;
CallingConv getDefaultMethodCallConv(bool isVariadic) const {
- if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+ if (!isVariadic &&
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
- else
- return CC_C;
+ return CC_C;
}
bool isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -52,17 +54,121 @@ public:
};
}
-unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const {
- QualType Pointee = MPT->getPointeeType();
- CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- if (RD->getNumVBases() > 0) {
- if (Pointee->isFunctionType())
- return 3;
- else
- return 2;
- } else if (RD->getNumBases() > 1 && Pointee->isFunctionType())
- return 2;
- return 1;
+// getNumBases() seems to only give us the number of direct bases, and not the
+// total. This function tells us if we inherit from anybody that uses MI, or if
+// we have a non-primary base class, which uses the multiple inheritance model.
+static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
+ while (RD->getNumBases() > 0) {
+ if (RD->getNumBases() > 1)
+ return true;
+ assert(RD->getNumBases() == 1);
+ const CXXRecordDecl *Base =
+ RD->bases_begin()->getType()->getAsCXXRecordDecl();
+ if (RD->isPolymorphic() && !Base->isPolymorphic())
+ return true;
+ RD = Base;
+ }
+ 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;
+ }
+}
+
+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 MSIM_Multiple;
+ return MSIM_Single;
+}
+
+// Returns the number of pointer and integer slots used to represent a member
+// pointer in the MS C++ ABI.
+//
+// Member function pointers have the following general form; however, fields
+// are dropped as permitted (under the MSVC interpretation) by the inheritance
+// model of the actual class.
+//
+// struct {
+// // A pointer to the member function to call. If the member function is
+// // virtual, this will be a thunk that forwards to the appropriate vftable
+// // slot.
+// void *FunctionPointerOrVirtualThunk;
+//
+// // An offset to add to the address of the vbtable pointer after (possibly)
+// // selecting the virtual base but before resolving and calling the function.
+// // Only needed if the class has any virtual bases or bases at a non-zero
+// // offset.
+// int NonVirtualBaseAdjustment;
+//
+// // 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 VBTableOffset;
+// };
+std::pair<unsigned, unsigned>
+MemberPointerType::getMSMemberPointerSlots() const {
+ const CXXRecordDecl *RD = this->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ unsigned Ptrs;
+ unsigned Ints = 0;
+ if (this->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_Multiple: ++Ints; // NonVirtualBaseAdjustment
+ 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_Multiple: // Nothing
+ case MSIM_Single: ++Ints; // Field offset
+ }
+ }
+ return std::make_pair(Ptrs, Ints);
+}
+
+std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
+ const MemberPointerType *MPT) const {
+ const TargetInfo &Target = Context.getTargetInfo();
+ assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
+ Target.getTriple().getArch() == llvm::Triple::x86_64);
+ unsigned Ptrs, Ints;
+ llvm::tie(Ptrs, Ints) = MPT->getMSMemberPointerSlots();
+ // 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);
+ return std::make_pair(Width, Align);
}
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5d5b83d9a30b..40f8730e61af 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -21,19 +22,31 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
-
#include <map>
using namespace clang;
namespace {
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
+
+ return fn;
+}
+
/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
/// Microsoft Visual C++ ABI.
class MicrosoftCXXNameMangler {
MangleContext &Context;
raw_ostream &Out;
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
+ unsigned StructorType;
+
// FIXME: audit the performance of BackRefMap as it might do way too many
// copying of strings.
typedef std::map<std::string, unsigned> BackRefMap;
@@ -47,7 +60,15 @@ class MicrosoftCXXNameMangler {
public:
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
- : Context(C), Out(Out_), UseNameBackReferences(true) { }
+ : Context(C), Out(Out_),
+ Structor(0), StructorType(-1),
+ UseNameBackReferences(true) { }
+
+ MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Out_),
+ Structor(getStructor(D)), StructorType(Type),
+ UseNameBackReferences(true) { }
raw_ostream &getStream() const { return Out; }
@@ -68,12 +89,13 @@ private:
void mangleSourceName(const IdentifierInfo *II);
void manglePostfix(const DeclContext *DC, bool NoFunction=false);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
+ void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
void manglePointerQualifiers(Qualifiers Quals);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleTemplateInstantiationName(const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleLocalName(const FunctionDecl *FD);
@@ -96,12 +118,12 @@ private:
void mangleExtraDimensions(QualType T);
void mangleFunctionClass(const FunctionDecl *FD);
void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
- void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number);
+ void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
- void mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ void mangleTemplateArgs(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs);
};
@@ -345,47 +367,19 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
}
static const TemplateDecl *
-isTemplate(const NamedDecl *ND,
- SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
- if (FD->getTemplateSpecializationArgsAsWritten()) {
- const ASTTemplateArgumentListInfo *ArgList =
- FD->getTemplateSpecializationArgsAsWritten();
- TemplateArgs.append(ArgList->getTemplateArgs(),
- ArgList->getTemplateArgs() +
- ArgList->NumTemplateArgs);
- } else {
- const TemplateArgumentList *ArgList =
- FD->getTemplateSpecializationArgs();
- TemplateArgumentListInfo LI;
- for (unsigned i = 0, e = ArgList->size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i),
- FD->getTypeSourceInfo()));
- }
+ TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
}
}
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- TypeSourceInfo *TSI = Spec->getTypeAsWritten();
- if (TSI) {
- TemplateSpecializationTypeLoc TSTL =
- cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
- TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
- for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
- TemplateArgs.push_back(TSTL.getArgLoc(i));
- } else {
- TemplateArgumentListInfo LI;
- const TemplateArgumentList &ArgList =
- Spec->getTemplateArgs();
- for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i],
- TemplateArgumentLocInfo()));
- }
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
@@ -399,8 +393,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <template-name>
- SmallVector<TemplateArgumentLoc, 2> TemplateArgs;
+
// Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
// We have a template.
// Here comes the tricky thing: if we need to mangle something like
@@ -430,7 +425,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
Found = NameBackReferences.find(BackReferenceKey);
}
if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- mangleTemplateInstantiationName(TD, TemplateArgs);
+ mangleTemplateInstantiationName(TD, *TemplateArgs);
if (UseNameBackReferences && NameBackReferences.size() < 10) {
size_t Size = NameBackReferences.size();
NameBackReferences[BackReferenceKey] = Size;
@@ -453,7 +448,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
- Out << "?A";
+ Out << "?A@";
break;
}
}
@@ -481,11 +476,22 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
+ if (ND == Structor) {
+ assert(StructorType == Ctor_Complete &&
+ "Should never be asked to mangle a ctor other than complete");
+ }
Out << "?0";
break;
case DeclarationName::CXXDestructorName:
- Out << "?1";
+ if (ND == Structor)
+ // If the named decl is the C++ destructor we're mangling,
+ // use the type we were given.
+ mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+ else
+ // Otherwise, use the complete destructor name. This is relevant if a
+ // class with a destructor is declared within a destructor.
+ mangleCXXDtorType(Dtor_Complete);
break;
case DeclarationName::CXXConversionFunctionName:
@@ -543,6 +549,23 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
}
}
+void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ switch (T) {
+ case Dtor_Deleting:
+ Out << "?_G";
+ return;
+ case Dtor_Base:
+ // FIXME: We should be asked to mangle base dtors.
+ // However, fixing this would require larger changes to the CodeGenModule.
+ // Please put llvm_unreachable here when CGM is changed.
+ // For now, just mangle a base dtor the same way as a complete dtor...
+ case Dtor_Complete:
+ Out << "?1";
+ return;
+ }
+ llvm_unreachable("Unsupported dtor type?");
+}
+
void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
SourceLocation Loc) {
switch (OO) {
@@ -736,19 +759,23 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ const TemplateArgumentList &TemplateArgs) {
// <template-name> ::= <unscoped-template-name> <template-args>
// ::= <substitution>
// Always start with the unqualified name.
// Templates have their own context for back references.
- BackRefMap TemplateContext;
- NameBackReferences.swap(TemplateContext);
+ ArgBackRefMap OuterArgsContext;
+ BackRefMap OuterTemplateContext;
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(TemplateArgs);
+ mangleTemplateArgs(TD, TemplateArgs);
- NameBackReferences.swap(TemplateContext);
+ // Restore the previous back reference contexts.
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
}
void
@@ -759,13 +786,13 @@ MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
}
void
-MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T,
- const llvm::APSInt &Value) {
+MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
+ bool IsBoolean) {
// <integer-literal> ::= $0 <number>
Out << "$0";
// Make sure booleans are encoded as 0/1.
- if (T->isBooleanType())
- Out << (Value.getBoolValue() ? "0" : "A@");
+ if (IsBoolean && Value.getBoolValue())
+ mangleNumber(1);
else
mangleNumber(Value);
}
@@ -775,7 +802,7 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// See if this is a constant expression.
llvm::APSInt Value;
if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
- mangleIntegerLiteral(E->getType(), Value);
+ mangleIntegerLiteral(Value, E->getType()->isBooleanType());
return;
}
@@ -788,39 +815,42 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
}
void
-MicrosoftCXXNameMangler::mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+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 TemplateArgumentLoc &TAL = TemplateArgs[i];
- const TemplateArgument &TA = TAL.getArgument();
+ const TemplateArgument &TA = TemplateArgs[i];
switch (TA.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't mangle null template arguments!");
case TemplateArgument::Type:
- mangleType(TA.getAsType(), TAL.getSourceRange());
+ mangleType(TA.getAsType(), SourceRange());
+ break;
+ case TemplateArgument::Declaration:
+ mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?");
break;
case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
+ mangleIntegerLiteral(TA.getAsIntegral(),
+ TA.getIntegralType()->isBooleanType());
break;
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr());
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
case TemplateArgument::Pack: {
// Issue a diagnostic.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|"
- "integral|template|template pack expansion|ERROR|parameter pack}0 "
- "template argument yet");
- Diags.Report(TAL.getLocation(), DiagID)
+ "cannot mangle template argument %0 of kind %select{ERROR|ERROR|"
+ "pointer/reference|nullptr|integral|template|template pack expansion|"
+ "ERROR|parameter pack}1 yet");
+ Diags.Report(TD->getLocation(), DiagID)
+ << i + 1
<< TA.getKind()
- << TAL.getSourceRange();
+ << TD->getSourceRange();
}
}
}
@@ -1048,6 +1078,15 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
+
+ case BuiltinType::OCLImage1d: Out << "PAUocl_image1d@@"; break;
+ case BuiltinType::OCLImage1dArray: Out << "PAUocl_image1darray@@"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "PAUocl_image1dbuffer@@"; break;
+ case BuiltinType::OCLImage2d: Out << "PAUocl_image2d@@"; break;
+ case BuiltinType::OCLImage2dArray: Out << "PAUocl_image2darray@@"; break;
+ 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;
@@ -1096,9 +1135,18 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
- if (IsStructor)
+ if (IsStructor) {
+ if (isa<CXXDestructorDecl>(D) && D == Structor &&
+ StructorType == Dtor_Deleting) {
+ // The scalar deleting destructor takes an extra int argument.
+ // However, the FunctionType generated has 0 arguments.
+ // FIXME: This is a temporary hack.
+ // Maybe should fix the FunctionType creation instead?
+ Out << "PAXI@Z";
+ return;
+ }
Out << '@';
- else {
+ } else {
QualType Result = Proto->getResultType();
const Type* RT = Result.getTypePtr();
if (!RT->isAnyPointerType() && !RT->isReferenceType()) {
@@ -1471,12 +1519,38 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T,
void MicrosoftCXXNameMangler::mangleType(const VectorType *T,
SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this vector type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
+ const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>();
+ assert(ET && "vectors with non-builtin elements are unsupported");
+ uint64_t Width = getASTContext().getTypeSize(T);
+ // Pattern match exactly the typedefs in our intrinsic headers. Anything that
+ // doesn't match the Intel types uses a custom mangling below.
+ bool IntelVector = true;
+ if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
+ Out << "T__m64";
+ } else if (Width == 128 || Width == 256) {
+ if (ET->getKind() == BuiltinType::Float)
+ Out << "T__m" << Width;
+ else if (ET->getKind() == BuiltinType::LongLong)
+ Out << "T__m" << Width << 'i';
+ else if (ET->getKind() == BuiltinType::Double)
+ Out << "U__m" << Width << 'd';
+ else
+ IntelVector = false;
+ } else {
+ IntelVector = false;
+ }
+
+ if (!IntelVector) {
+ // The MS ABI doesn't have a special mangling for vector types, so we define
+ // our own mangling to handle uses of __vector_size__ on user-specified
+ // types, and for extensions like __v4sf.
+ Out << "T__clang_vec" << T->getNumElements() << '_';
+ mangleType(ET, Range);
+ }
+
+ Out << "@@";
}
+
void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -1697,7 +1771,7 @@ void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
raw_ostream & Out) {
- MicrosoftCXXNameMangler mangler(*this, Out);
+ MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
mangler.mangle(D);
}
void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 0837509194bc..a862630bbf8d 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -67,7 +67,7 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
return NSStringSelectors[MK];
}
-llvm::Optional<NSAPI::NSStringMethodKind>
+Optional<NSAPI::NSStringMethodKind>
NSAPI::getNSStringMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSStringMethods; ++i) {
NSStringMethodKind MK = NSStringMethodKind(i);
@@ -75,7 +75,7 @@ NSAPI::getNSStringMethodKind(Selector Sel) const {
return MK;
}
- return llvm::Optional<NSStringMethodKind>();
+ return None;
}
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
@@ -126,15 +126,14 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
return NSArraySelectors[MK];
}
-llvm::Optional<NSAPI::NSArrayMethodKind>
-NSAPI::getNSArrayMethodKind(Selector Sel) {
+Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
NSArrayMethodKind MK = NSArrayMethodKind(i);
if (Sel == getNSArraySelector(MK))
return MK;
}
- return llvm::Optional<NSArrayMethodKind>();
+ return None;
}
Selector NSAPI::getNSDictionarySelector(
@@ -186,6 +185,14 @@ Selector NSAPI::getNSDictionarySelector(
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithObjectsAndKeys"));
break;
+ case NSDict_initWithObjectsForKeys: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("initWithObjects"),
+ &Ctx.Idents.get("forKeys")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
case NSDict_objectForKey:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
break;
@@ -204,7 +211,7 @@ Selector NSAPI::getNSDictionarySelector(
return NSDictionarySelectors[MK];
}
-llvm::Optional<NSAPI::NSDictionaryMethodKind>
+Optional<NSAPI::NSDictionaryMethodKind>
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
@@ -212,7 +219,7 @@ NSAPI::getNSDictionaryMethodKind(Selector Sel) {
return MK;
}
- return llvm::Optional<NSDictionaryMethodKind>();
+ return None;
}
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
@@ -267,7 +274,7 @@ Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
return Sels[MK];
}
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+Optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
@@ -275,14 +282,14 @@ NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
return MK;
}
- return llvm::Optional<NSNumberLiteralMethodKind>();
+ return None;
}
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+Optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (!BT)
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+ return None;
const TypedefType *TDT = T->getAs<TypedefType>();
if (TDT) {
@@ -337,6 +344,14 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::ObjCClass:
case BuiltinType::ObjCId:
case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::Overload:
@@ -348,7 +363,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
break;
}
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+ return None;
}
/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 49b119b8e05c..79cc21a062c8 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -57,7 +57,8 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix, NamespaceDecl *NS) {
+ NestedNameSpecifier *Prefix,
+ const NamespaceDecl *NS) {
assert(NS && "Namespace cannot be NULL");
assert((!Prefix ||
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
@@ -65,7 +66,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(StoredNamespaceOrAlias);
- Mockup.Specifier = NS;
+ Mockup.Specifier = const_cast<NamespaceDecl *>(NS);
return FindOrInsert(Context, Mockup);
}
@@ -248,7 +249,6 @@ NestedNameSpecifier::print(raw_ostream &OS,
// Fall through to print the type.
case TypeSpec: {
- std::string TypeStr;
const Type *T = getAsType();
PrintingPolicy InnerPolicy(Policy);
@@ -270,15 +270,12 @@ NestedNameSpecifier::print(raw_ostream &OS,
SpecType->getTemplateName().print(OS, InnerPolicy, true);
// Print the template argument list.
- TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
- SpecType->getArgs(),
- SpecType->getNumArgs(),
- InnerPolicy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, SpecType->getArgs(), SpecType->getNumArgs(), InnerPolicy);
} else {
// Print the type normally
- TypeStr = QualType(T, 0).getAsString(InnerPolicy);
+ QualType(T, 0).print(OS, InnerPolicy);
}
- OS << TypeStr;
break;
}
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 80b627293e42..f2386a56fcc7 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -10,11 +10,11 @@
#include "clang/AST/RawCommentList.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
-#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentBriefParser.h"
-#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentLexer.h"
+#include "clang/AST/CommentParser.h"
+#include "clang/AST/CommentSema.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 2ae0aab19f69..f6cfe63cd34e 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -75,10 +75,9 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
if (isPrimaryBaseVirtual()) {
- // Microsoft ABI doesn't have primary virtual base
- if (Ctx.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
- assert(getVBaseClassOffset(PrimaryBase).isZero() &&
- "Primary virtual base must be at offset 0!");
+ if (Ctx.getTargetInfo().getCXXABI().hasPrimaryVBases()) {
+ assert(getVBaseClassOffset(PrimaryBase).isZero() &&
+ "Primary virtual base must be at offset 0!");
}
} else {
assert(getBaseClassOffset(PrimaryBase).isZero() &&
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4dfffc45e49c..42c3ba31bc76 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
@@ -14,13 +15,12 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
@@ -676,8 +676,12 @@ protected:
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
+ TargetCXXABI getCXXABI() const {
+ return Context.getTargetInfo().getCXXABI();
+ }
+
bool isMicrosoftCXXABI() const {
- return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft;
+ return getCXXABI().isMicrosoft();
}
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
@@ -791,8 +795,6 @@ protected:
RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
-public:
- static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
} // end anonymous namespace
@@ -2343,8 +2345,8 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
<< D->getIdentifier();
}
-const CXXMethodDecl *
-RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+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;
@@ -2362,6 +2364,9 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
TSK == TSK_ExplicitInstantiationDefinition)
return 0;
+ 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;
@@ -2387,6 +2392,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (!MD->isUserProvided())
continue;
+ // In certain ABIs, ignore functions with out-of-line inline definitions.
+ if (!allowInlineFunctions) {
+ const FunctionDecl *Def;
+ if (MD->hasBody(Def) && Def->isInlineSpecified())
+ continue;
+ }
+
// We found it.
return MD;
}
@@ -2399,6 +2411,48 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
return Context.getDiagnostics().Report(Loc, DiagID);
}
+/// Does the target C++ ABI require us to skip over the tail-padding
+/// of the given class (considering it as a base class) when allocating
+/// objects?
+static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
+ switch (ABI.getTailPaddingUseRules()) {
+ case TargetCXXABI::AlwaysUseTailPadding:
+ return false;
+
+ case TargetCXXABI::UseTailPaddingUnlessPOD03:
+ // FIXME: To the extent that this is meant to cover the Itanium ABI
+ // rules, we should implement the restrictions about over-sized
+ // bitfields:
+ //
+ // http://mentorembedded.github.com/cxx-abi/abi.html#POD :
+ // In general, a type is considered a POD for the purposes of
+ // layout if it is a POD type (in the sense of ISO C++
+ // [basic.types]). However, a POD-struct or POD-union (in the
+ // sense of ISO C++ [class]) with a bitfield member whose
+ // declared width is wider than the declared type of the
+ // bitfield is not a POD for the purpose of layout. Similarly,
+ // an array type is not a POD for the purpose of layout if the
+ // element type of the array is not a POD for the purpose of
+ // layout.
+ //
+ // Where references to the ISO C++ are made in this paragraph,
+ // the Technical Corrigendum 1 version of the standard is
+ // intended.
+ return RD->isPOD();
+
+ case TargetCXXABI::UseTailPaddingUnlessPOD11:
+ // This is equivalent to RD->getTypeForDecl().isCXX11PODType(),
+ // but with a lot of abstraction penalty stripped off. This does
+ // assume that these properties are set correctly even in C++98
+ // mode; fortunately, that is true because we want to assign
+ // consistently semantics to the type-traits intrinsics (or at
+ // least as many of them as possible).
+ return RD->isTrivial() && RD->isStandardLayout();
+ }
+
+ llvm_unreachable("bad tail-padding use kind");
+}
+
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
@@ -2443,18 +2497,17 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder.Layout(RD);
}
- // FIXME: This is not always correct. See the part about bitfields at
- // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
- // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
- // This does not affect the calculations of MSVC layouts
- bool IsPODForThePurposeOfLayout =
- (!Builder.isMicrosoftCXXABI() && cast<CXXRecordDecl>(D)->isPOD());
+ // In certain situations, we are allowed to lay out objects in the
+ // tail-padding of base classes. This is ABI-dependent.
+ // FIXME: this should be stored in the record layout.
+ bool skipTailPadding =
+ mustSkipTailPadding(getTargetInfo().getCXXABI(), cast<CXXRecordDecl>(D));
// FIXME: This should be done in FinalizeLayout.
CharUnits DataSize =
- IsPODForThePurposeOfLayout ? Builder.getSize() : Builder.getDataSize();
+ skipTailPadding ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+ skipTailPadding ? DataSize : Builder.NonVirtualSize;
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
@@ -2492,15 +2545,37 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
return *NewEntry;
}
-const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
+ assert(RD->getDefinition() && "Cannot get key function for forward decl!");
RD = cast<CXXRecordDecl>(RD->getDefinition());
- assert(RD && "Cannot get key function for forward declarations!");
- const CXXMethodDecl *&Entry = KeyFunctions[RD];
- if (!Entry)
- Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
+ const CXXMethodDecl *&entry = KeyFunctions[RD];
+ if (!entry) {
+ entry = computeKeyFunction(*this, RD);
+ }
- return Entry;
+ return entry;
+}
+
+void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
+ assert(method == method->getFirstDeclaration() &&
+ "not working with method declaration from class definition");
+
+ // Look up the cache entry. Since we're working with the first
+ // declaration, its parent must be the class definition, which is
+ // the correct key for the KeyFunctions hash.
+ llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
+ i = KeyFunctions.find(method->getParent());
+
+ // If it's not cached, there's nothing to do.
+ 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 == method) {
+ // FIXME: remember that we did this for module / chained PCH state?
+ KeyFunctions.erase(i);
+ }
}
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {
@@ -2577,6 +2652,11 @@ static void PrintOffset(raw_ostream &OS,
OS.indent(IndentLevel * 2);
}
+static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) {
+ OS << " | ";
+ OS.indent(IndentLevel * 2);
+}
+
static void DumpCXXRecordLayout(raw_ostream &OS,
const CXXRecordDecl *RD, const ASTContext &C,
CharUnits Offset,
@@ -2601,7 +2681,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
// Vtable pointer.
if (RD->isDynamicClass() && !PrimaryBase &&
- C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ !C.getTargetInfo().getCXXABI().isMicrosoft()) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
}
@@ -2680,11 +2760,14 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
/*IncludeVirtualBases=*/false);
}
- OS << " sizeof=" << Layout.getSize().getQuantity();
+ PrintIndentNoOffset(OS, IndentLevel - 1);
+ OS << "[sizeof=" << Layout.getSize().getQuantity();
OS << ", dsize=" << Layout.getDataSize().getQuantity();
OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
- OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
- OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n';
+
+ PrintIndentNoOffset(OS, IndentLevel - 1);
+ OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
+ OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n";
OS << '\n';
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index eafcf92eee82..2ae5a1266c18 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -11,15 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Stmt.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Token.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -46,6 +48,16 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
return StmtClassInfo[E];
}
+void *Stmt::operator new(size_t bytes, ASTContext& C,
+ unsigned alignment) throw() {
+ return ::operator new(bytes, C, alignment);
+}
+
+void *Stmt::operator new(size_t bytes, ASTContext* C,
+ unsigned alignment) throw() {
+ return ::operator new(bytes, *C, alignment);
+}
+
const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
}
@@ -131,18 +143,28 @@ namespace {
return bad();
}
- typedef SourceRange getSourceRange_t() const;
- template <class T> good implements_getSourceRange(getSourceRange_t T::*) {
+ typedef SourceLocation getLocStart_t() const;
+ template <class T> good implements_getLocStart(getLocStart_t T::*) {
return good();
}
- static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) {
+ static inline bad implements_getLocStart(getLocStart_t Stmt::*) {
+ return bad();
+ }
+
+ typedef SourceLocation getLocEnd_t() const;
+ template <class T> good implements_getLocEnd(getLocEnd_t T::*) {
+ return good();
+ }
+ static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) {
return bad();
}
#define ASSERT_IMPLEMENTS_children(type) \
(void) sizeof(is_good(implements_children(&type::children)))
-#define ASSERT_IMPLEMENTS_getSourceRange(type) \
- (void) sizeof(is_good(implements_getSourceRange(&type::getSourceRange)))
+#define ASSERT_IMPLEMENTS_getLocStart(type) \
+ (void) sizeof(is_good(implements_getLocStart(&type::getLocStart)))
+#define ASSERT_IMPLEMENTS_getLocEnd(type) \
+ (void) sizeof(is_good(implements_getLocEnd(&type::getLocEnd)))
}
/// Check whether the various Stmt classes implement their member
@@ -151,7 +173,8 @@ static inline void check_implementations() {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
ASSERT_IMPLEMENTS_children(type); \
- ASSERT_IMPLEMENTS_getSourceRange(type);
+ ASSERT_IMPLEMENTS_getLocStart(type); \
+ ASSERT_IMPLEMENTS_getLocEnd(type);
#include "clang/AST/StmtNodes.inc"
}
@@ -167,67 +190,51 @@ Stmt::child_range Stmt::children() {
llvm_unreachable("unknown statement kind!");
}
-SourceRange Stmt::getSourceRange() const {
- switch (getStmtClass()) {
- case Stmt::NoStmtClass: llvm_unreachable("statement without class");
-#define ABSTRACT_STMT(type)
-#define STMT(type, base) \
- case Stmt::type##Class: \
- return static_cast<const type*>(this)->getSourceRange();
-#include "clang/AST/StmtNodes.inc"
- }
- llvm_unreachable("unknown statement kind!");
-}
-
// Amusing macro metaprogramming hack: check whether a class provides
-// a more specific implementation of getLocStart() and getLocEnd().
+// a more specific implementation of getSourceRange.
//
// See also Expr.cpp:getExprLoc().
namespace {
/// This implementation is used when a class provides a custom
- /// implementation of getLocStart.
+ /// implementation of getSourceRange.
template <class S, class T>
- SourceLocation getLocStartImpl(const Stmt *stmt,
- SourceLocation (T::*v)() const) {
- return static_cast<const S*>(stmt)->getLocStart();
+ SourceRange getSourceRangeImpl(const Stmt *stmt,
+ SourceRange (T::*v)() const) {
+ return static_cast<const S*>(stmt)->getSourceRange();
}
/// This implementation is used when a class doesn't provide a custom
- /// implementation of getLocStart. Overload resolution should pick it over
+ /// implementation of getSourceRange. Overload resolution should pick it over
/// the implementation above because it's more specialized according to
/// function template partial ordering.
template <class S>
- SourceLocation getLocStartImpl(const Stmt *stmt,
- SourceLocation (Stmt::*v)() const) {
- return static_cast<const S*>(stmt)->getSourceRange().getBegin();
- }
-
- /// This implementation is used when a class provides a custom
- /// implementation of getLocEnd.
- template <class S, class T>
- SourceLocation getLocEndImpl(const Stmt *stmt,
- SourceLocation (T::*v)() const) {
- return static_cast<const S*>(stmt)->getLocEnd();
+ SourceRange getSourceRangeImpl(const Stmt *stmt,
+ SourceRange (Stmt::*v)() const) {
+ return SourceRange(static_cast<const S*>(stmt)->getLocStart(),
+ static_cast<const S*>(stmt)->getLocEnd());
}
+}
- /// This implementation is used when a class doesn't provide a custom
- /// implementation of getLocEnd. Overload resolution should pick it over
- /// the implementation above because it's more specialized according to
- /// function template partial ordering.
- template <class S>
- SourceLocation getLocEndImpl(const Stmt *stmt,
- SourceLocation (Stmt::*v)() const) {
- return static_cast<const S*>(stmt)->getSourceRange().getEnd();
+SourceRange Stmt::getSourceRange() const {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: \
+ return getSourceRangeImpl<type>(this, &type::getSourceRange);
+#include "clang/AST/StmtNodes.inc"
}
+ llvm_unreachable("unknown statement kind!");
}
SourceLocation Stmt::getLocStart() const {
+// llvm::errs() << "getLocStart() for " << getStmtClassName() << "\n";
switch (getStmtClass()) {
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
case Stmt::type##Class: \
- return getLocStartImpl<type>(this, &type::getLocStart);
+ return static_cast<const type*>(this)->getLocStart();
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
@@ -239,26 +246,26 @@ SourceLocation Stmt::getLocEnd() const {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
case Stmt::type##Class: \
- return getLocEndImpl<type>(this, &type::getLocEnd);
+ return static_cast<const type*>(this)->getLocEnd();
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
}
-CompoundStmt::CompoundStmt(ASTContext &C, Stmt **StmtStart, unsigned NumStmts,
+CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB)
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
- CompoundStmtBits.NumStmts = NumStmts;
- assert(CompoundStmtBits.NumStmts == NumStmts &&
+ CompoundStmtBits.NumStmts = Stmts.size();
+ assert(CompoundStmtBits.NumStmts == Stmts.size() &&
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
- if (NumStmts == 0) {
+ if (Stmts.size() == 0) {
Body = 0;
return;
}
- Body = new (C) Stmt*[NumStmts];
- memcpy(Body, StmtStart, NumStmts * sizeof(*Body));
+ Body = new (C) Stmt*[Stmts.size()];
+ std::copy(Stmts.begin(), Stmts.end(), Body);
}
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
@@ -291,14 +298,6 @@ AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
}
-// This is defined here to avoid polluting Stmt.h with importing Expr.h
-SourceRange ReturnStmt::getSourceRange() const {
- if (RetExpr)
- return SourceRange(RetLoc, RetExpr->getLocEnd());
- else
- return SourceRange(RetLoc);
-}
-
bool Stmt::hasImplicitControlFlow() const {
switch (StmtBits.sClass) {
default:
@@ -541,7 +540,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
// Handle %x4 and %x[foo] by capturing x as the modifier character.
char Modifier = '\0';
- if (isalpha(EscapedChar)) {
+ if (isLetter(EscapedChar)) {
if (CurPtr == StrEnd) { // Premature end.
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_escape;
@@ -550,12 +549,12 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
EscapedChar = *CurPtr++;
}
- if (isdigit(EscapedChar)) {
+ if (isDigit(EscapedChar)) {
// %n - Assembler operand n
unsigned N = 0;
--CurPtr;
- while (CurPtr != StrEnd && isdigit(*CurPtr))
+ while (CurPtr != StrEnd && isDigit(*CurPtr))
N = N*10 + ((*CurPtr++)-'0');
unsigned NumOperands =
@@ -762,26 +761,21 @@ ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
}
-SourceRange ObjCAtTryStmt::getSourceRange() const {
- SourceLocation EndLoc;
+SourceLocation ObjCAtTryStmt::getLocEnd() const {
if (HasFinally)
- EndLoc = getFinallyStmt()->getLocEnd();
- else if (NumCatchStmts)
- EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
- else
- EndLoc = getTryBody()->getLocEnd();
-
- return SourceRange(AtTryLoc, EndLoc);
+ return getFinallyStmt()->getLocEnd();
+ if (NumCatchStmts)
+ return getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+ return getTryBody()->getLocEnd();
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
- Stmt *tryBlock, Stmt **handlers,
- unsigned numHandlers) {
+ Stmt *tryBlock, ArrayRef<Stmt*> handlers) {
std::size_t Size = sizeof(CXXTryStmt);
- Size += ((numHandlers + 1) * sizeof(Stmt));
+ Size += ((handlers.size() + 1) * sizeof(Stmt));
void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
- return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
+ return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers);
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
@@ -794,11 +788,11 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
}
CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
- Stmt **handlers, unsigned numHandlers)
- : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
+ ArrayRef<Stmt*> handlers)
+ : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) {
Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
Stmts[0] = tryBlock;
- std::copy(handlers, handlers + NumHandlers, Stmts + 1);
+ std::copy(handlers.begin(), handlers.end(), Stmts + 1);
}
CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
deleted file mode 100644
index fbc990f6b3c2..000000000000
--- a/lib/AST/StmtDumper.cpp
+++ /dev/null
@@ -1,760 +0,0 @@
-//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Stmt::dump method, which dumps out the
-// AST in a form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// StmtDumper Visitor
-//===----------------------------------------------------------------------===//
-
-namespace {
- class StmtDumper : public StmtVisitor<StmtDumper> {
- SourceManager *SM;
- raw_ostream &OS;
- unsigned IndentLevel;
- bool IsFirstLine;
-
- /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
- /// the first few levels of an AST. This keeps track of how many ast levels
- /// are left.
- unsigned MaxDepth;
-
- /// LastLocFilename/LastLocLine - Keep track of the last location we print
- /// out so that we can print out deltas from then on out.
- const char *LastLocFilename;
- unsigned LastLocLine;
-
- class IndentScope {
- StmtDumper &Dumper;
- public:
- IndentScope(StmtDumper &Dumper) : Dumper(Dumper) {
- Dumper.indent();
- }
- ~IndentScope() {
- Dumper.unindent();
- }
- };
-
- public:
- StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
- : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) {
- LastLocFilename = "";
- LastLocLine = ~0U;
- }
-
- ~StmtDumper() {
- OS << "\n";
- }
-
- void DumpSubTree(Stmt *S) {
- // Prune the recursion if not using dump all.
- if (MaxDepth == 0) return;
-
- IndentScope Indent(*this);
-
- if (!S) {
- OS << "<<<NULL>>>";
- return;
- }
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
- VisitDeclStmt(DS);
- return;
- }
-
- Visit(S);
- for (Stmt::child_range CI = S->children(); CI; CI++)
- DumpSubTree(*CI);
- }
-
- void DumpDeclarator(Decl *D);
-
- void indent() {
- if (IsFirstLine)
- IsFirstLine = false;
- else
- OS << "\n";
- OS.indent(IndentLevel * 2);
- OS << "(";
- IndentLevel++;
- }
-
- void unindent() {
- OS << ")";
- IndentLevel--;
- }
-
- void DumpType(QualType T) {
- SplitQualType T_split = T.split();
- OS << "'" << QualType::getAsString(T_split) << "'";
-
- if (!T.isNull()) {
- // If the type is sugared, also dump a (shallow) desugared type.
- SplitQualType D_split = T.getSplitDesugaredType();
- if (T_split != D_split)
- OS << ":'" << QualType::getAsString(D_split) << "'";
- }
- }
- void DumpDeclRef(Decl *node);
- void DumpStmt(const Stmt *Node) {
- OS << Node->getStmtClassName()
- << " " << (const void*)Node;
- DumpSourceRange(Node);
- }
- void DumpValueKind(ExprValueKind K) {
- switch (K) {
- case VK_RValue: break;
- case VK_LValue: OS << " lvalue"; break;
- case VK_XValue: OS << " xvalue"; break;
- }
- }
- void DumpObjectKind(ExprObjectKind K) {
- switch (K) {
- case OK_Ordinary: break;
- case OK_BitField: OS << " bitfield"; break;
- case OK_ObjCProperty: OS << " objcproperty"; break;
- case OK_ObjCSubscript: OS << " objcsubscript"; break;
- case OK_VectorComponent: OS << " vectorcomponent"; break;
- }
- }
- void DumpExpr(const Expr *Node) {
- DumpStmt(Node);
- OS << ' ';
- DumpType(Node->getType());
- DumpValueKind(Node->getValueKind());
- DumpObjectKind(Node->getObjectKind());
- }
- void DumpSourceRange(const Stmt *Node);
- void DumpLocation(SourceLocation Loc);
-
- // Stmts.
- void VisitStmt(Stmt *Node);
- void VisitDeclStmt(DeclStmt *Node);
- void VisitLabelStmt(LabelStmt *Node);
- void VisitGotoStmt(GotoStmt *Node);
-
- // Exprs
- void VisitExpr(Expr *Node);
- void VisitCastExpr(CastExpr *Node);
- void VisitDeclRefExpr(DeclRefExpr *Node);
- void VisitPredefinedExpr(PredefinedExpr *Node);
- void VisitCharacterLiteral(CharacterLiteral *Node);
- void VisitIntegerLiteral(IntegerLiteral *Node);
- void VisitFloatingLiteral(FloatingLiteral *Node);
- void VisitStringLiteral(StringLiteral *Str);
- void VisitUnaryOperator(UnaryOperator *Node);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
- void VisitMemberExpr(MemberExpr *Node);
- void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
- void VisitBinaryOperator(BinaryOperator *Node);
- void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
- void VisitAddrLabelExpr(AddrLabelExpr *Node);
- void VisitBlockExpr(BlockExpr *Node);
- void VisitOpaqueValueExpr(OpaqueValueExpr *Node);
-
- // C++
- void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
- void VisitCXXThisExpr(CXXThisExpr *Node);
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
- void VisitCXXConstructExpr(CXXConstructExpr *Node);
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
- void VisitExprWithCleanups(ExprWithCleanups *Node);
- void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node);
- void DumpCXXTemporary(CXXTemporary *Temporary);
-
- // ObjC
- void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
- void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
- void VisitObjCMessageExpr(ObjCMessageExpr* Node);
- void VisitObjCBoxedExpr(ObjCBoxedExpr* Node);
- void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
- void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
- void VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
- void VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node);
- };
-}
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::DumpLocation(SourceLocation Loc) {
- SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
-
- // The general format we print out is filename:line:col, but we drop pieces
- // that haven't changed since the last loc printed.
- PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
-
- if (PLoc.isInvalid()) {
- OS << "<invalid sloc>";
- return;
- }
-
- if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
- OS << PLoc.getFilename() << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocFilename = PLoc.getFilename();
- LastLocLine = PLoc.getLine();
- } else if (PLoc.getLine() != LastLocLine) {
- OS << "line" << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocLine = PLoc.getLine();
- } else {
- OS << "col" << ':' << PLoc.getColumn();
- }
-}
-
-void StmtDumper::DumpSourceRange(const Stmt *Node) {
- // Can't translate locations if a SourceManager isn't available.
- if (SM == 0) return;
-
- // TODO: If the parent expression is available, we can print a delta vs its
- // location.
- SourceRange R = Node->getSourceRange();
-
- OS << " <";
- DumpLocation(R.getBegin());
- if (R.getBegin() != R.getEnd()) {
- OS << ", ";
- DumpLocation(R.getEnd());
- }
- OS << ">";
-
- // <t2.c:123:421[blah], t2.c:412:321>
-
-}
-
-
-//===----------------------------------------------------------------------===//
-// Stmt printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitStmt(Stmt *Node) {
- DumpStmt(Node);
-}
-
-void StmtDumper::DumpDeclarator(Decl *D) {
- // FIXME: Need to complete/beautify this... this code simply shows the
- // nodes are where they need to be.
- if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
- OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << ' ' << *localType << '"';
- } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
- OS << "\"using " << *localType << " = "
- << localType->getUnderlyingType().getAsString() << '"';
- } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- OS << "\"";
- // Emit storage class for vardecls.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getStorageClass() != SC_None)
- OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
- << " ";
- }
-
- std::string Name = VD->getNameAsString();
- VD->getType().getAsStringInternal(Name,
- PrintingPolicy(VD->getASTContext().getLangOpts()));
- OS << Name;
-
- // If this is a vardecl with an initializer, emit it.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getInit()) {
- OS << " =";
- DumpSubTree(V->getInit());
- }
- }
- OS << '"';
- } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- // print a free standing tag decl (e.g. "struct x;").
- const char *tagname;
- if (const IdentifierInfo *II = TD->getIdentifier())
- tagname = II->getNameStart();
- else
- tagname = "<anonymous>";
- OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
- // FIXME: print tag bodies.
- } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
- // print using-directive decl (e.g. "using namespace x;")
- const char *ns;
- if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
- ns = II->getNameStart();
- else
- ns = "<anonymous>";
- OS << '"' << UD->getDeclKindName() << ns << ";\"";
- } else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
- // print using decl (e.g. "using std::string;")
- const char *tn = UD->isTypeName() ? "typename " : "";
- OS << '"' << UD->getDeclKindName() << tn;
- UD->getQualifier()->print(OS,
- PrintingPolicy(UD->getASTContext().getLangOpts()));
- OS << ";\"";
- } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
- OS << "label " << *LD;
- } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
- OS << "\"static_assert(";
- DumpSubTree(SAD->getAssertExpr());
- OS << ",";
- DumpSubTree(SAD->getMessage());
- OS << ");\"";
- } else {
- llvm_unreachable("Unexpected decl");
- }
-}
-
-void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
- DumpStmt(Node);
- for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
- DI != DE; ++DI) {
- IndentScope Indent(*this);
- Decl* D = *DI;
- OS << (void*) D << " ";
- DumpDeclarator(D);
- }
-}
-
-void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
- DumpStmt(Node);
- OS << " '" << Node->getName() << "'";
-}
-
-void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
- DumpStmt(Node);
- OS << " '" << Node->getLabel()->getName()
- << "':" << (void*)Node->getLabel();
-}
-
-//===----------------------------------------------------------------------===//
-// Expr printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitExpr(Expr *Node) {
- DumpExpr(Node);
-}
-
-static void DumpBasePath(raw_ostream &OS, CastExpr *Node) {
- if (Node->path_empty())
- return;
-
- OS << " (";
- bool First = true;
- for (CastExpr::path_iterator
- I = Node->path_begin(), E = Node->path_end(); I != E; ++I) {
- const CXXBaseSpecifier *Base = *I;
- if (!First)
- OS << " -> ";
-
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (Base->isVirtual())
- OS << "virtual ";
- OS << RD->getName();
- First = false;
- }
-
- OS << ')';
-}
-
-void StmtDumper::VisitCastExpr(CastExpr *Node) {
- DumpExpr(Node);
- OS << " <" << Node->getCastKindName();
- DumpBasePath(OS, Node);
- OS << ">";
-}
-
-void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
- DumpExpr(Node);
-
- OS << " ";
- DumpDeclRef(Node->getDecl());
- if (Node->getDecl() != Node->getFoundDecl()) {
- OS << " (";
- DumpDeclRef(Node->getFoundDecl());
- OS << ")";
- }
-}
-
-void StmtDumper::DumpDeclRef(Decl *d) {
- OS << d->getDeclKindName() << ' ' << (void*) d;
-
- if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
- OS << " '";
- nd->getDeclName().printName(OS);
- OS << "'";
- }
-
- if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
- OS << ' '; DumpType(vd->getType());
- }
-}
-
-void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
- DumpExpr(Node);
- OS << " (";
- if (!Node->requiresADL()) OS << "no ";
- OS << "ADL) = '" << Node->getName() << '\'';
-
- UnresolvedLookupExpr::decls_iterator
- I = Node->decls_begin(), E = Node->decls_end();
- if (I == E) OS << " empty";
- for (; I != E; ++I)
- OS << " " << (void*) *I;
-}
-
-void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
- DumpExpr(Node);
-
- OS << " " << Node->getDecl()->getDeclKindName()
- << "Decl='" << *Node->getDecl()
- << "' " << (void*)Node->getDecl();
- if (Node->isFreeIvar())
- OS << " isFreeIvar";
-}
-
-void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
- DumpExpr(Node);
- switch (Node->getIdentType()) {
- default: llvm_unreachable("unknown case");
- case PredefinedExpr::Func: OS << " __func__"; break;
- case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
- case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
- case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
- }
-}
-
-void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
- DumpExpr(Node);
- OS << " " << Node->getValue();
-}
-
-void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
- DumpExpr(Node);
-
- bool isSigned = Node->getType()->isSignedIntegerType();
- OS << " " << Node->getValue().toString(10, isSigned);
-}
-void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
- DumpExpr(Node);
- OS << " " << Node->getValueAsApproximateDouble();
-}
-
-void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
- DumpExpr(Str);
- OS << " ";
- Str->outputString(OS);
-}
-
-void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
- DumpExpr(Node);
- OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
- << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
- DumpExpr(Node);
- switch(Node->getKind()) {
- case UETT_SizeOf:
- OS << " sizeof ";
- break;
- case UETT_AlignOf:
- OS << " alignof ";
- break;
- case UETT_VecStep:
- OS << " vec_step ";
- break;
- }
- if (Node->isArgumentType())
- DumpType(Node->getArgumentType());
-}
-
-void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->isArrow() ? "->" : ".")
- << *Node->getMemberDecl() << ' '
- << (void*)Node->getMemberDecl();
-}
-void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getAccessor().getNameStart();
-}
-void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
- DumpExpr(Node);
- OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
- DumpExpr(Node);
- OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
- << "' ComputeLHSTy=";
- DumpType(Node->getComputationLHSType());
- OS << " ComputeResultTy=";
- DumpType(Node->getComputationResultType());
-}
-
-void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
- DumpExpr(Node);
-
- BlockDecl *block = Node->getBlockDecl();
- OS << " decl=" << block;
-
- if (block->capturesCXXThis()) {
- IndentScope Indent(*this);
- OS << "capture this";
- }
- for (BlockDecl::capture_iterator
- i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
- IndentScope Indent(*this);
- OS << "capture ";
- if (i->isByRef()) OS << "byref ";
- if (i->isNested()) OS << "nested ";
- if (i->getVariable())
- DumpDeclRef(i->getVariable());
- if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
- }
-
- DumpSubTree(block->getBody());
-}
-
-void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
- DumpExpr(Node);
-
- if (Expr *Source = Node->getSourceExpr())
- DumpSubTree(Source);
-}
-
-// GNU extensions.
-
-void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getLabel()->getName()
- << " " << (void*)Node->getLabel();
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getCastName()
- << "<" << Node->getTypeAsWritten().getAsString() << ">"
- << " <" << Node->getCastKindName();
- DumpBasePath(OS, Node);
- OS << ">";
-}
-
-void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->getValue() ? "true" : "false");
-}
-
-void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
- DumpExpr(Node);
- OS << " this";
-}
-
-void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- DumpExpr(Node);
- OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
- << " <" << Node->getCastKindName() << ">";
-}
-
-void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
- DumpExpr(Node);
- CXXConstructorDecl *Ctor = Node->getConstructor();
- DumpType(Ctor->getType());
- if (Node->isElidable())
- OS << " elidable";
- if (Node->requiresZeroInitialization())
- OS << " zeroing";
-}
-
-void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpCXXTemporary(Node->getTemporary());
-}
-
-void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
- DumpExpr(Node);
- for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
- IndentScope Indent(*this);
- OS << "cleanup ";
- DumpDeclRef(Node->getObject(i));
- }
-}
-
-void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
- OS << "(CXXTemporary " << (void *)Temporary << ")";
-}
-
-//===----------------------------------------------------------------------===//
-// Obj-C Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
- DumpExpr(Node);
- OS << " selector=" << Node->getSelector().getAsString();
- switch (Node->getReceiverKind()) {
- case ObjCMessageExpr::Instance:
- break;
-
- case ObjCMessageExpr::Class:
- OS << " class=";
- DumpType(Node->getClassReceiver());
- break;
-
- case ObjCMessageExpr::SuperInstance:
- OS << " super (instance)";
- break;
-
- case ObjCMessageExpr::SuperClass:
- OS << " super (class)";
- break;
- }
-}
-
-void StmtDumper::VisitObjCBoxedExpr(ObjCBoxedExpr* Node) {
- DumpExpr(Node);
- OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
-}
-
-void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
- DumpStmt(Node);
- if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
- OS << " catch parm = ";
- DumpDeclarator(CatchParam);
- } else {
- OS << " catch all";
- }
-}
-
-void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpType(Node->getEncodedType());
-}
-
-void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
- DumpExpr(Node);
-
- OS << " " << Node->getSelector().getAsString();
-}
-
-void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- DumpExpr(Node);
-
- OS << ' ' <<* Node->getProtocol();
-}
-
-void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
- DumpExpr(Node);
- if (Node->isImplicitProperty()) {
- OS << " Kind=MethodRef Getter=\"";
- if (Node->getImplicitPropertyGetter())
- OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
- else
- OS << "(null)";
-
- OS << "\" Setter=\"";
- if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
- OS << Setter->getSelector().getAsString();
- else
- OS << "(null)";
- OS << "\"";
- } else {
- OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
- }
-
- if (Node->isSuperReceiver())
- OS << " super";
-
- OS << " Messaging=";
- if (Node->isMessagingGetter() && Node->isMessagingSetter())
- OS << "Getter&Setter";
- else if (Node->isMessagingGetter())
- OS << "Getter";
- else if (Node->isMessagingSetter())
- OS << "Setter";
-}
-
-void StmtDumper::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
- DumpExpr(Node);
- if (Node->isArraySubscriptRefExpr())
- OS << " Kind=ArraySubscript GetterForArray=\"";
- else
- OS << " Kind=DictionarySubscript GetterForDictionary=\"";
- if (Node->getAtIndexMethodDecl())
- OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
- else
- OS << "(null)";
-
- if (Node->isArraySubscriptRefExpr())
- OS << "\" SetterForArray=\"";
- else
- OS << "\" SetterForDictionary=\"";
- if (Node->setAtIndexMethodDecl())
- OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
- else
- OS << "(null)";
-}
-
-void StmtDumper::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
-}
-
-//===----------------------------------------------------------------------===//
-// Stmt method implementations
-//===----------------------------------------------------------------------===//
-
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
-void Stmt::dump(SourceManager &SM) const {
- dump(llvm::errs(), SM);
-}
-
-void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
- StmtDumper P(&SM, OS, 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
-void Stmt::dump() const {
- StmtDumper P(0, llvm::errs(), 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll(SourceManager &SM) const {
- StmtDumper P(&SM, llvm::errs(), ~0U);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll() const {
- StmtDumper P(0, llvm::errs(), ~0U);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 57eb1a95181c..7df7fdb92bf2 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -13,14 +13,17 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -583,10 +586,8 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitDependentScopeDeclRefExpr(
@@ -597,10 +598,8 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr(
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
@@ -610,10 +609,8 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
@@ -709,15 +706,14 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
OS << "'\\v'";
break;
default:
- if (value < 256 && isprint(value)) {
+ if (value < 256 && isPrintable((unsigned char)value))
OS << "'" << (char)value << "'";
- } else if (value < 256) {
- OS << "'\\x";
- OS.write_hex(value) << "'";
- } else {
- // FIXME what to really do here?
- OS << value;
- }
+ else if (value < 256)
+ OS << "'\\x" << llvm::format("%02x", value) << "'";
+ else if (value <= 0xFFFF)
+ OS << "'\\u" << llvm::format("%04x", value) << "'";
+ else
+ OS << "'\\U" << llvm::format("%08x", value) << "'";
}
}
@@ -810,7 +806,8 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
OS << "__builtin_offsetof(";
- OS << Node->getTypeSourceInfo()->getType().getAsString(Policy) << ", ";
+ Node->getTypeSourceInfo()->getType().print(OS, Policy);
+ OS << ", ";
bool PrintedSomething = false;
for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
@@ -858,9 +855,11 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
OS << "vec_step";
break;
}
- if (Node->isArgumentType())
- OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
- else {
+ if (Node->isArgumentType()) {
+ OS << '(';
+ Node->getArgumentType().print(OS, Policy);
+ OS << ')';
+ } else {
OS << " ";
PrintExpr(Node->getArgumentExpr());
}
@@ -875,7 +874,7 @@ void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
if (T.isNull())
OS << "default";
else
- OS << T.getAsString(Policy);
+ T.print(OS, Policy);
OS << ": ";
PrintExpr(Node->getAssocExpr(i));
}
@@ -910,20 +909,26 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
// FIXME: Suppress printing implicit bases (like "this")
PrintExpr(Node->getBase());
+
+ MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
+ FieldDecl *ParentDecl = ParentMember
+ ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : NULL;
+
+ if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
+ OS << (Node->isArrow() ? "->" : ".");
+
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
if (FD->isAnonymousStructOrUnion())
return;
- OS << (Node->isArrow() ? "->" : ".");
+
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
PrintExpr(Node->getBase());
@@ -936,11 +941,15 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
OS << Node->getAccessor().getName();
}
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
- OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")";
+ OS << '(';
+ Node->getTypeAsWritten().print(OS, Policy);
+ OS << ')';
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
- OS << "(" << Node->getType().getAsString(Policy) << ")";
+ OS << '(';
+ Node->getType().print(OS, Policy);
+ OS << ')';
PrintExpr(Node->getInitializer());
}
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
@@ -1059,10 +1068,14 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
}
void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
- if (Policy.LangOpts.CPlusPlus)
- OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()";
- else {
- OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")";
+ if (Policy.LangOpts.CPlusPlus) {
+ OS << "/*implicit*/";
+ Node->getType().print(OS, Policy);
+ OS << "()";
+ } else {
+ OS << "/*implicit*/(";
+ Node->getType().print(OS, Policy);
+ OS << ')';
if (Node->getType()->isRecordType())
OS << "{}";
else
@@ -1074,7 +1087,7 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << "__builtin_va_arg(";
PrintExpr(Node->getSubExpr());
OS << ", ";
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << ")";
}
@@ -1183,7 +1196,8 @@ void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
- OS << Node->getTypeAsWritten().getAsString(Policy) << ">(";
+ Node->getTypeAsWritten().print(OS, Policy);
+ OS << ">(";
PrintExpr(Node->getSubExpr());
OS << ")";
}
@@ -1207,7 +1221,7 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
- OS << Node->getTypeOperand().getAsString(Policy);
+ Node->getTypeOperand().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1217,7 +1231,7 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << "__uuidof(";
if (Node->isTypeOperand()) {
- OS << Node->getTypeOperand().getAsString(Policy);
+ Node->getTypeOperand().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1288,7 +1302,7 @@ void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
}
void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << "(";
PrintExpr(Node->getSubExpr());
OS << ")";
@@ -1299,7 +1313,7 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
}
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << "(";
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
@@ -1369,8 +1383,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
NeedComma = true;
}
std::string ParamStr = (*P)->getNameAsString();
- (*P)->getOriginalType().getAsStringInternal(ParamStr, Policy);
- OS << ParamStr;
+ (*P)->getOriginalType().print(OS, Policy, ParamStr);
}
if (Method->isVariadic()) {
if (NeedComma)
@@ -1384,17 +1397,15 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
const FunctionProtoType *Proto
= Method->getType()->getAs<FunctionProtoType>();
- {
- std::string ExceptionSpec;
- Proto->printExceptionSpecification(ExceptionSpec, Policy);
- OS << ExceptionSpec;
- }
+ Proto->printExceptionSpecification(OS, Policy);
// FIXME: Attributes
// Print the trailing return type if it was specified in the source.
- if (Node->hasExplicitResultType())
- OS << " -> " << Proto->getResultType().getAsString(Policy);
+ if (Node->hasExplicitResultType()) {
+ OS << " -> ";
+ Proto->getResultType().print(OS, Policy);
+ }
}
// Print the body.
@@ -1405,9 +1416,10 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
- OS << TSInfo->getType().getAsString(Policy) << "()";
+ TSInfo->getType().print(OS, Policy);
else
- OS << Node->getType().getAsString(Policy) << "()";
+ Node->getType().print(OS, Policy);
+ OS << "()";
}
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
@@ -1431,12 +1443,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
std::string TypeS;
if (Expr *Size = E->getArraySize()) {
llvm::raw_string_ostream s(TypeS);
+ s << '[';
Size->printPretty(s, Helper, Policy);
- s.flush();
- TypeS = "[" + TypeS + "]";
+ s << ']';
}
- E->getAllocatedType().getAsStringInternal(TypeS, Policy);
- OS << TypeS;
+ E->getAllocatedType().print(OS, Policy, TypeS);
if (E->isParenTypeId())
OS << ")";
@@ -1469,15 +1480,16 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->getQualifier()->print(OS, Policy);
OS << "~";
- std::string TypeS;
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
- E->getDestroyedType().getAsStringInternal(TypeS, Policy);
- OS << TypeS;
+ E->getDestroyedType().print(OS, Policy);
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (E->isListInitialization())
+ OS << "{ ";
+
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(E->getArg(i))) {
// Don't print any defaulted arguments
@@ -1487,6 +1499,9 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
if (i) OS << ", ";
PrintExpr(E->getArg(i));
}
+
+ if (E->isListInitialization())
+ OS << " }";
}
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
@@ -1497,7 +1512,7 @@ void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
void
StmtPrinter::VisitCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *Node) {
- OS << Node->getTypeAsWritten().getAsString(Policy);
+ Node->getTypeAsWritten().print(OS, Policy);
OS << "(";
for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
@@ -1520,12 +1535,9 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
- if (Node->hasExplicitTemplateArgs()) {
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
- }
+ if (Node->hasExplicitTemplateArgs())
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
@@ -1538,20 +1550,20 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
- if (Node->hasExplicitTemplateArgs()) {
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
- }
+ if (Node->hasExplicitTemplateArgs())
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ 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";
@@ -1631,14 +1643,17 @@ static const char *getExpressionTraitName(ExpressionTrait ET) {
}
void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getQueriedType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getQueriedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getLhsType().getAsString(Policy) << ","
- << E->getRhsType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getLhsType().print(OS, Policy);
+ OS << ',';
+ E->getRhsType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
@@ -1646,20 +1661,21 @@ void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
if (I > 0)
OS << ", ";
- OS << E->getArg(I)->getType().getAsString(Policy);
+ E->getArg(I)->getType().print(OS, Policy);
}
OS << ")";
}
void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getQueriedType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getQueriedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
- OS << getExpressionTraitName(E->getTrait()) << "(";
- PrintExpr(E->getQueriedExpression());
- OS << ")";
+ OS << getExpressionTraitName(E->getTrait()) << '(';
+ PrintExpr(E->getQueriedExpression());
+ OS << ')';
}
void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
@@ -1738,7 +1754,9 @@ void StmtPrinter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
}
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- OS << "@encode(" << Node->getEncodedType().getAsString(Policy) << ')';
+ OS << "@encode(";
+ Node->getEncodedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
@@ -1757,7 +1775,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
break;
case ObjCMessageExpr::Class:
- OS << Mess->getClassReceiver().getAsString(Policy);
+ Mess->getClassReceiver().print(OS, Policy);
break;
case ObjCMessageExpr::SuperInstance:
@@ -1798,8 +1816,9 @@ StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
void
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
- OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy)
- << ")";
+ OS << '(' << E->getBridgeKindName();
+ E->getType().print(OS, Policy);
+ OS << ')';
PrintExpr(E->getSubExpr());
}
@@ -1813,13 +1832,11 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
OS << "()";
} else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) {
OS << '(';
- std::string ParamStr;
for (BlockDecl::param_iterator AI = BD->param_begin(),
E = BD->param_end(); AI != E; ++AI) {
if (AI != BD->param_begin()) OS << ", ";
- ParamStr = (*AI)->getNameAsString();
- (*AI)->getType().getAsStringInternal(ParamStr, Policy);
- OS << ParamStr;
+ std::string ParamStr = (*AI)->getNameAsString();
+ (*AI)->getType().print(OS, Policy, ParamStr);
}
const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
@@ -1829,6 +1846,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
OS << ')';
}
+ OS << "{ }";
}
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
@@ -1838,7 +1856,8 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
OS << "__builtin_astype(";
PrintExpr(Node->getSrcExpr());
- OS << ", " << Node->getType().getAsString();
+ OS << ", ";
+ Node->getType().print(OS, Policy);
OS << ")";
}
@@ -1859,11 +1878,6 @@ void Stmt::printPretty(raw_ostream &OS,
return;
}
- if (Policy.DumpSourceManager) {
- dump(OS, *Policy.DumpSourceManager);
- return;
- }
-
StmtPrinter P(OS, Helper, Policy, Indentation);
P.Visit(const_cast<Stmt*>(this));
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index e9ee385457f8..d68b95edb730 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -23,8 +23,8 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <cctype>
using namespace clang;
@@ -224,12 +224,12 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return false;
}
-llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
assert(Kind == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
- return llvm::Optional<unsigned>();
+ return None;
}
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
@@ -347,9 +347,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
case Type: {
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressStrongLifetime = true;
- std::string TypeStr;
- getAsType().getAsStringInternal(TypeStr, SubPolicy);
- Out << TypeStr;
+ getAsType().print(Out, SubPolicy);
break;
}
@@ -451,10 +449,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-TemplateArgumentLoc
-TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
- llvm::Optional<unsigned> &NumExpansions,
- ASTContext &Context) const {
+TemplateArgumentLoc TemplateArgumentLoc::getPackExpansionPattern(
+ SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions,
+ ASTContext &Context) const {
assert(Argument.isPackExpansion());
switch (Argument.getKind()) {
@@ -466,8 +463,8 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
ExpansionTSInfo = Context.getTrivialTypeSourceInfo(
getArgument().getAsType(),
Ellipsis);
- PackExpansionTypeLoc Expansion
- = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc());
+ PackExpansionTypeLoc Expansion =
+ ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
Ellipsis = Expansion.getEllipsisLoc();
TypeLoc Pattern = Expansion.getPatternLoc();
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index e89ba5399b6b..8767c635f675 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -1,4 +1,4 @@
-//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===//
+//===--- TemplateName.cpp - C++ Template Name Representation---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/TemplateName.h"
-#include "clang/AST/TemplateBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/Support/raw_ostream.h"
@@ -163,14 +163,20 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
+ OS << '\'';
N.print(OS, PrintingPolicy(LO));
+ OS << '\'';
OS.flush();
return DB << NameStr;
}
-void TemplateName::dump() const {
+void TemplateName::dump(raw_ostream &OS) const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
LO.Bool = true;
- print(llvm::errs(), PrintingPolicy(LO));
+ print(OS, PrintingPolicy(LO));
+}
+
+void TemplateName::dump() const {
+ dump(llvm::errs());
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 580ec50ca1f8..0c5636d84067 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/Type.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/APSInt.h"
@@ -75,16 +76,35 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) {
unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements) {
+ uint64_t ElementSize = Context.getTypeSizeInChars(ElementType).getQuantity();
+
+ // Fast path the common cases so we can avoid the conservative computation
+ // below, which in common cases allocates "large" APSInt values, which are
+ // slow.
+
+ // If the element size is a power of 2, we can directly compute the additional
+ // number of addressing bits beyond those required for the element count.
+ if (llvm::isPowerOf2_64(ElementSize)) {
+ return NumElements.getActiveBits() + llvm::Log2_64(ElementSize);
+ }
+
+ // If both the element count and element size fit in 32-bits, we can do the
+ // computation directly in 64-bits.
+ if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 &&
+ (NumElements.getZExtValue() >> 32) == 0) {
+ uint64_t TotalSize = NumElements.getZExtValue() * ElementSize;
+ return 64 - llvm::CountLeadingZeros_64(TotalSize);
+ }
+
+ // Otherwise, use APSInt to handle arbitrary sized values.
llvm::APSInt SizeExtended(NumElements, true);
unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType());
SizeExtended = SizeExtended.extend(std::max(SizeTypeBits,
SizeExtended.getBitWidth()) * 2);
- uint64_t ElementSize
- = Context.getTypeSizeInChars(ElementType).getQuantity();
llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize));
TotalSize *= SizeExtended;
-
+
return TotalSize.getActiveBits();
}
@@ -939,7 +959,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
bool QualType::isPODType(ASTContext &Context) const {
// C++11 has a more relaxed definition of POD.
- if (Context.getLangOpts().CPlusPlus0x)
+ if (Context.getLangOpts().CPlusPlus11)
return isCXX11PODType(Context);
return isCXX98PODType(Context);
@@ -1052,11 +1072,13 @@ bool QualType::isTrivialType(ASTContext &Context) const {
if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++0x [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
- // and is trivially copyable.
- if (!ClassDecl->isTriviallyCopyable()) return false;
+ // C++11 [class]p6:
+ // A trivial class is a class that has a default constructor,
+ // has no non-trivial default constructors, and is trivially
+ // copyable.
+ return ClassDecl->hasDefaultConstructor() &&
+ !ClassDecl->hasNonTrivialDefaultConstructor() &&
+ ClassDecl->isTriviallyCopyable();
}
return true;
@@ -1509,6 +1531,14 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
+ case OCLImage1d: return "image1d_t";
+ case OCLImage1dArray: return "image1d_array_t";
+ case OCLImage1dBuffer: return "image1d_buffer_t";
+ case OCLImage2d: return "image2d_t";
+ case OCLImage2dArray: return "image2d_array_t";
+ case OCLImage3d: return "image3d_t";
+ case OCLSampler: return "sampler_t";
+ case OCLEvent: return "event_t";
}
llvm_unreachable("Invalid builtin type.");
@@ -1543,29 +1573,33 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
case CC_PnaclCall: return "pnaclcall";
+ case CC_IntelOclBicc: return "intel_ocl_bicc";
}
llvm_unreachable("Invalid calling convention.");
}
-FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
- unsigned numArgs, QualType canonical,
+FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
+ QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.TypeQuals, epi.RefQualifier,
+ : FunctionType(FunctionProto, result, epi.TypeQuals,
canonical,
result->isDependentType(),
result->isInstantiationDependentType(),
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
- NumArgs(numArgs), NumExceptions(epi.NumExceptions),
+ NumArgs(args.size()), NumExceptions(epi.NumExceptions),
ExceptionSpecType(epi.ExceptionSpecType),
HasAnyConsumedArgs(epi.ConsumedArguments != 0),
- Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn)
+ Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
+ RefQualifier(epi.RefQualifier)
{
+ assert(NumArgs == args.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) {
+ for (unsigned i = 0; i != NumArgs; ++i) {
if (args[i]->isDependentType())
setDependent();
else if (args[i]->isInstantiationDependentType())
@@ -1579,7 +1613,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
if (getExceptionSpecType() == EST_Dynamic) {
// Fill in the exception array.
- QualType *exnSlot = argSlot + numArgs;
+ QualType *exnSlot = argSlot + NumArgs;
for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
if (epi.Exceptions[i]->isDependentType())
setDependent();
@@ -1593,7 +1627,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const 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 + NumArgs);
*noexSlot = epi.NoexceptExpr;
if (epi.NoexceptExpr) {
@@ -1606,7 +1640,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const 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 + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
slot[1] = epi.ExceptionSpecTemplate;
// This exception specification doesn't make the type dependent, because
@@ -1614,13 +1648,13 @@ FunctionProtoType::FunctionProtoType(QualType result, const 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 + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
}
if (epi.ConsumedArguments) {
bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
- for (unsigned i = 0; i != numArgs; ++i)
+ for (unsigned i = 0; i != NumArgs; ++i)
consumedArgs[i] = epi.ConsumedArguments[i];
}
}
@@ -1987,22 +2021,18 @@ namespace {
/// \brief The cached properties of a type.
class CachedProperties {
- NamedDecl::LinkageInfo LV;
+ Linkage L;
bool local;
-
+
public:
- CachedProperties(NamedDecl::LinkageInfo LV, bool local)
- : LV(LV), local(local) {}
-
- Linkage getLinkage() const { return LV.linkage(); }
- Visibility getVisibility() const { return LV.visibility(); }
- bool isVisibilityExplicit() const { return LV.visibilityExplicit(); }
+ CachedProperties(Linkage L, bool local) : L(L), local(local) {}
+
+ Linkage getLinkage() const { return L; }
bool hasLocalOrUnnamedType() const { return local; }
-
+
friend CachedProperties merge(CachedProperties L, CachedProperties R) {
- NamedDecl::LinkageInfo MergedLV = L.LV;
- MergedLV.merge(R.LV);
- return CachedProperties(MergedLV,
+ Linkage MergedLinkage = minLinkage(L.L, R.L);
+ return CachedProperties(MergedLinkage,
L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType());
}
};
@@ -2022,10 +2052,8 @@ public:
static CachedProperties get(const Type *T) {
ensure(T);
- NamedDecl::LinkageInfo LV(T->TypeBits.getLinkage(),
- T->TypeBits.getVisibility(),
- T->TypeBits.isVisibilityExplicit());
- return CachedProperties(LV, T->TypeBits.hasLocalOrUnnamedType());
+ return CachedProperties(T->TypeBits.getLinkage(),
+ T->TypeBits.hasLocalOrUnnamedType());
}
static void ensure(const Type *T) {
@@ -2037,10 +2065,7 @@ public:
if (!T->isCanonicalUnqualified()) {
const Type *CT = T->getCanonicalTypeInternal().getTypePtr();
ensure(CT);
- T->TypeBits.CacheValidAndVisibility =
- CT->TypeBits.CacheValidAndVisibility;
- T->TypeBits.CachedExplicitVisibility =
- CT->TypeBits.CachedExplicitVisibility;
+ T->TypeBits.CacheValid = true;
T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage;
T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed;
return;
@@ -2048,10 +2073,7 @@ public:
// Compute the cached properties and then set the cache.
CachedProperties Result = computeCachedProperties(T);
- T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U;
- T->TypeBits.CachedExplicitVisibility = Result.isVisibilityExplicit();
- assert(T->TypeBits.isCacheValid() &&
- T->TypeBits.getVisibility() == Result.getVisibility());
+ T->TypeBits.CacheValid = true;
T->TypeBits.CachedLinkage = Result.getLinkage();
T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType();
}
@@ -2077,13 +2099,13 @@ static CachedProperties computeCachedProperties(const Type *T) {
#include "clang/AST/TypeNodes.def"
// Treat instantiation-dependent types as external.
assert(T->isInstantiationDependentType());
- return CachedProperties(NamedDecl::LinkageInfo(), false);
+ return CachedProperties(ExternalLinkage, false);
case Type::Builtin:
// C++ [basic.link]p8:
// A type is said to have linkage if and only if:
// - it is a fundamental type (3.9.1); or
- return CachedProperties(NamedDecl::LinkageInfo(), false);
+ return CachedProperties(ExternalLinkage, false);
case Type::Record:
case Type::Enum: {
@@ -2093,11 +2115,11 @@ static CachedProperties computeCachedProperties(const Type *T) {
// - it is a class or enumeration type that is named (or has a name
// for linkage purposes (7.1.3)) and the name has linkage; or
// - it is a specialization of a class template (14); or
- NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility();
+ Linkage L = Tag->getLinkage();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
- (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
- return CachedProperties(LV, IsLocalOrUnnamed);
+ !Tag->hasNameForLinkage();
+ return CachedProperties(L, IsLocalOrUnnamed);
}
// C++ [basic.link]p8:
@@ -2135,9 +2157,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return result;
}
case Type::ObjCInterface: {
- NamedDecl::LinkageInfo LV =
- cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
- return CachedProperties(LV, false);
+ Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage();
+ return CachedProperties(L, false);
}
case Type::ObjCObject:
return Cache::get(cast<ObjCObjectType>(T)->getBaseType());
@@ -2156,31 +2177,99 @@ Linkage Type::getLinkage() const {
return TypeBits.getLinkage();
}
-/// \brief Determine the linkage of this type.
-Visibility Type::getVisibility() const {
+bool Type::hasUnnamedOrLocalType() const {
Cache::ensure(this);
- return TypeBits.getVisibility();
+ return TypeBits.hasLocalOrUnnamedType();
}
-bool Type::isVisibilityExplicit() const {
- Cache::ensure(this);
- return TypeBits.isVisibilityExplicit();
+static LinkageInfo computeLinkageInfo(QualType T);
+
+static LinkageInfo computeLinkageInfo(const Type *T) {
+ switch (T->getTypeClass()) {
+#define TYPE(Class,Base)
+#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("didn't expect a non-canonical type here");
+
+#define TYPE(Class,Base)
+#define DEPENDENT_TYPE(Class,Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ // Treat instantiation-dependent types as external.
+ assert(T->isInstantiationDependentType());
+ return LinkageInfo::external();
+
+ case Type::Builtin:
+ return LinkageInfo::external();
+
+ case Type::Record:
+ case Type::Enum:
+ return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
+
+ case Type::Complex:
+ return computeLinkageInfo(cast<ComplexType>(T)->getElementType());
+ case Type::Pointer:
+ return computeLinkageInfo(cast<PointerType>(T)->getPointeeType());
+ case Type::BlockPointer:
+ return computeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType());
+ case Type::LValueReference:
+ case Type::RValueReference:
+ return computeLinkageInfo(cast<ReferenceType>(T)->getPointeeType());
+ case Type::MemberPointer: {
+ const MemberPointerType *MPT = cast<MemberPointerType>(T);
+ LinkageInfo LV = computeLinkageInfo(MPT->getClass());
+ LV.merge(computeLinkageInfo(MPT->getPointeeType()));
+ return LV;
+ }
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ return computeLinkageInfo(cast<ArrayType>(T)->getElementType());
+ case Type::Vector:
+ case Type::ExtVector:
+ return computeLinkageInfo(cast<VectorType>(T)->getElementType());
+ case Type::FunctionNoProto:
+ return computeLinkageInfo(cast<FunctionType>(T)->getResultType());
+ 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));
+ return LV;
+ }
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
+ case Type::ObjCObject:
+ return computeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType());
+ case Type::ObjCObjectPointer:
+ return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
+ case Type::Atomic:
+ return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
+ }
+
+ llvm_unreachable("unhandled type class");
}
-bool Type::hasUnnamedOrLocalType() const {
- Cache::ensure(this);
- return TypeBits.hasLocalOrUnnamedType();
+static LinkageInfo computeLinkageInfo(QualType T) {
+ return computeLinkageInfo(T.getTypePtr());
}
-std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const {
- Cache::ensure(this);
- return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility());
+bool Type::isLinkageValid() const {
+ if (!TypeBits.isCacheValid())
+ return true;
+
+ return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() ==
+ TypeBits.getLinkage();
}
-void Type::ClearLinkageCache() {
- TypeBits.CacheValidAndVisibility = 0;
- if (QualType(this, 0) != CanonicalType)
- CanonicalType->TypeBits.CacheValidAndVisibility = 0;
+LinkageInfo Type::getLinkageAndVisibility() const {
+ if (!isCanonicalUnqualified())
+ return computeLinkageInfo(getCanonicalTypeInternal());
+
+ LinkageInfo LV = computeLinkageInfo(this);
+ assert(LV.getLinkage() == getLinkage());
+ return LV;
}
Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
@@ -2296,25 +2385,3 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_none;
}
-
-bool QualType::hasTrivialAssignment(ASTContext &Context, bool Copying) const {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_None:
- break;
-
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- return !Context.getLangOpts().ObjCAutoRefCount;
- }
-
- if (const CXXRecordDecl *Record
- = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
- return Copying ? Record->hasTrivialCopyAssignment() :
- Record->hasTrivialMoveAssignment();
-
- return true;
-}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 58c4cbd00c8a..03d40309f53a 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -11,11 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/raw_ostream.h"
-#include "clang/AST/TypeLocVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLocVisitor.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -85,7 +86,7 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case CLASS: { \
- CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
+ CLASS##TypeLoc TLCasted = TL.castAs<CLASS##TypeLoc>(); \
TLCasted.initializeLocal(Context, Loc); \
TL = TLCasted.getNextTypeLoc(); \
if (!TL) return; \
@@ -105,7 +106,8 @@ SourceLocation TypeLoc::getBeginLoc() const {
LeftMost = Cur;
break;
case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
+ if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()
+ ->hasTrailingReturn()) {
LeftMost = Cur;
break;
}
@@ -150,7 +152,7 @@ SourceLocation TypeLoc::getEndLoc() const {
Last = Cur;
break;
case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
+ if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()->hasTrailingReturn())
Last = TypeLoc();
else
Last = Cur;
@@ -197,9 +199,9 @@ namespace {
/// because it's a convenient base class. Ideally we would not accept
/// those here, but ideally we would have better implementations for
/// them.
-bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
- if (TL->getType().hasLocalQualifiers()) return false;
- return TSTChecker().Visit(*TL);
+bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) {
+ if (TL.getType().hasLocalQualifiers()) return false;
+ return TSTChecker().Visit(TL);
}
// Reimplemented to account for GNU/C++ extension
@@ -261,6 +263,14 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
case BuiltinType::BuiltinFn:
return TST_unspecified;
}
@@ -269,8 +279,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
}
TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
- while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL))
- TL = PTL->getInnerLoc();
+ while (ParenTypeLoc PTL = TL.getAs<ParenTypeLoc>())
+ TL = PTL.getInnerLoc();
return TL;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 90b2ca9cce15..9d1717a220cd 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -11,19 +11,19 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
-#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
@@ -647,6 +647,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_PnaclCall:
OS << " __attribute__((pnaclcall))";
break;
+ case CC_IntelOclBicc:
+ OS << " __attribute__((intel_ocl_bicc))";
+ break;
}
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
@@ -1168,6 +1171,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
break;
}
case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
+ case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
}
OS << "))";
}
@@ -1344,132 +1348,6 @@ PrintTemplateArgumentList(raw_ostream &OS,
OS << '>';
}
-void
-FunctionProtoType::printExceptionSpecification(std::string &S,
- const PrintingPolicy &Policy)
- const {
-
- if (hasDynamicExceptionSpec()) {
- S += " throw(";
- if (getExceptionSpecType() == EST_MSAny)
- S += "...";
- else
- for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
- if (I)
- S += ", ";
-
- S += getExceptionType(I).getAsString(Policy);
- }
- S += ")";
- } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
- S += " noexcept";
- if (getExceptionSpecType() == EST_ComputedNoexcept) {
- S += "(";
- llvm::raw_string_ostream EOut(S);
- getNoexceptExpr()->printPretty(EOut, 0, Policy);
- EOut.flush();
- S += EOut.str();
- S += ")";
- }
- }
-}
-
-std::string TemplateSpecializationType::
- PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
- const PrintingPolicy &Policy) {
- return PrintTemplateArgumentList(Args.getArgumentArray(),
- Args.size(),
- Policy);
-}
-
-std::string
-TemplateSpecializationType::PrintTemplateArgumentList(
- const TemplateArgument *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy,
- bool SkipBrackets) {
- std::string SpecString;
- if (!SkipBrackets)
- SpecString += '<';
-
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > unsigned(!SkipBrackets))
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- if (Args[Arg].getKind() == TemplateArgument::Pack) {
- ArgString = PrintTemplateArgumentList(Args[Arg].pack_begin(),
- Args[Arg].pack_size(),
- Policy, true);
- } else {
- llvm::raw_string_ostream ArgOut(ArgString);
- Args[Arg].print(Policy, ArgOut);
- }
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (!SpecString.empty() && SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- if (!SkipBrackets)
- SpecString += '>';
-
- return SpecString;
-}
-
-// Sadly, repeat all that with TemplateArgLoc.
-std::string TemplateSpecializationType::
-PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > 1)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) {
- ArgString = PrintTemplateArgumentList(
- Args[Arg].getArgument().pack_begin(),
- Args[Arg].getArgument().pack_size(),
- Policy, true);
- } else {
- llvm::raw_string_ostream ArgOut(ArgString);
- Args[Arg].getArgument().print(Policy, ArgOut);
- }
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
void QualType::dump(const char *msg) const {
if (msg)
llvm::errs() << msg << ": ";
@@ -1599,11 +1477,7 @@ void QualType::print(const Type *ty, Qualifiers qs,
raw_ostream &OS, const PrintingPolicy &policy,
const Twine &PlaceHolder) {
SmallString<128> PHBuf;
- StringRef PH;
- if (PlaceHolder.isSingleStringRef())
- PH = PlaceHolder.getSingleStringRef();
- else
- PH = PlaceHolder.toStringRef(PHBuf);
+ StringRef PH = PlaceHolder.toStringRef(PHBuf);
TypePrinter(policy).print(ty, qs, OS, PH);
}
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 33dad40c0c50..f80232f44c98 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
@@ -256,11 +257,9 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
const CXXRecordDecl *DerivedRD) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
-
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
llvm_unreachable("Class must be derived from the passed in base class!");
- }
return ComputeBaseOffset(Context, DerivedRD, Paths.front());
}
@@ -1001,6 +1000,10 @@ public:
dumpLayout(llvm::errs());
}
+ bool isMicrosoftABI() const {
+ return VTables.isMicrosoftABI();
+ }
+
uint64_t getNumThunks() const {
return Thunks.size();
}
@@ -1157,6 +1160,8 @@ void VTableBuilder::ComputeThisAdjustments() {
break;
case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
+ // FIXME: check how this works in the Microsoft ABI
+ // while working on the multiple inheritance patch.
continue;
}
@@ -1197,10 +1202,8 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
CXXBasePaths Paths(/*FindAmbiguities=*/true,
/*RecordPaths=*/true, /*DetectVirtual=*/true);
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
llvm_unreachable("Class must be derived from the passed in base class!");
- }
// We have to go through all the paths, and see which one leads us to the
// right base subobject.
@@ -1295,9 +1298,15 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
- // Add both the complete destructor and the deleting destructor.
- Components.push_back(VTableComponent::MakeCompleteDtor(DD));
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ // FIXME: Should probably add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ } else {
+ // Add the scalar deleting destructor.
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ }
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
@@ -1612,14 +1621,19 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
if (Base.getBase() == MostDerivedClass)
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
- // Add the offset to top.
- CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
- Components.push_back(
- VTableComponent::MakeOffsetToTop(OffsetToTop));
-
- // Next, add the RTTI.
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
-
+ // FIXME: Should probably add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ // Add the offset to top.
+ CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
+
+ // Next, add the RTTI.
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
+ } else {
+ // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere
+ // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway.
+ }
+
uint64_t AddressPoint = Components.size();
// Now go through all virtual member functions and add them.
@@ -1936,6 +1950,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << DD->getQualifiedNameAsString();
if (IsComplete)
Out << "() [complete]";
+ else if (isMicrosoftABI())
+ Out << "() [scalar deleting]";
else
Out << "() [deleting]";
@@ -2120,10 +2136,16 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
MD);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] =
- MethodName + " [complete]";
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] =
- MethodName + " [deleting]";
+ // FIXME: Should add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
+ = MethodName + " [complete]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [deleting]";
+ } else {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [scalar deleting]";
+ }
} else {
IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
}
@@ -2154,12 +2176,14 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
const VTableComponent *VTableComponents,
uint64_t NumVTableThunks,
const VTableThunkTy *VTableThunks,
- const AddressPointsMapTy &AddressPoints)
+ const AddressPointsMapTy &AddressPoints,
+ bool IsMicrosoftABI)
: NumVTableComponents(NumVTableComponents),
VTableComponents(new VTableComponent[NumVTableComponents]),
NumVTableThunks(NumVTableThunks),
VTableThunks(new VTableThunkTy[NumVTableThunks]),
- AddressPoints(AddressPoints) {
+ AddressPoints(AddressPoints),
+ IsMicrosoftABI(IsMicrosoftABI) {
std::copy(VTableComponents, VTableComponents+NumVTableComponents,
this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
@@ -2168,6 +2192,11 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
VTableLayout::~VTableLayout() { }
+VTableContext::VTableContext(ASTContext &Context)
+ : Context(Context),
+ IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+}
+
VTableContext::~VTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts);
}
@@ -2239,12 +2268,18 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
const CXXDestructorDecl *OverriddenDD =
cast<CXXDestructorDecl>(OverriddenMD);
-
- // Add both the complete and deleting entries.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+
+ if (!isMicrosoftABI()) {
+ // Add both the complete and deleting entries.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ // Add the scalar deleting destructor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ }
} else {
MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
}
@@ -2262,11 +2297,16 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
continue;
}
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ if (!isMicrosoftABI()) {
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the scalar deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ }
} else {
// Add the entry.
MethodVTableIndices[MD] = CurrentIndex++;
@@ -2278,6 +2318,11 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
// If a class has an implicitly-defined virtual destructor,
// its entries come after the declared virtual function pointers.
+ if (isMicrosoftABI()) {
+ ErrorUnsupported("implicit virtual destructor in the Microsoft ABI",
+ ImplicitVirtualDtor->getLocation());
+ }
+
// Add the complete dtor.
MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
CurrentIndex++;
@@ -2357,7 +2402,8 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
Builder.vtable_component_begin(),
VTableThunks.size(),
VTableThunks.data(),
- Builder.getAddressPoints());
+ Builder.getAddressPoints(),
+ Builder.isMicrosoftABI());
}
void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
@@ -2397,6 +2443,14 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
}
}
+void VTableContext::ErrorUnsupported(StringRef Feature,
+ SourceLocation Location) {
+ clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "v-table layout for %0 is not supported yet");
+ Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+}
+
VTableLayout *VTableContext::createConstructionVTableLayout(
const CXXRecordDecl *MostDerivedClass,
CharUnits MostDerivedClassOffset,
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 8ecb26e8c19d..6ebd736e3ce4 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include <deque>
#include <set>
namespace clang {
@@ -29,62 +30,6 @@ namespace {
typedef MatchFinder::MatchCallback MatchCallback;
-/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
-/// parents as defined by the \c RecursiveASTVisitor.
-///
-/// Note that the relationship described here is purely in terms of AST
-/// traversal - there are other relationships (for example declaration context)
-/// in the AST that are better modeled by special matchers.
-///
-/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
-class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
-public:
- /// \brief Maps from a node to its parent.
- typedef llvm::DenseMap<const void*, ast_type_traits::DynTypedNode> ParentMap;
-
- /// \brief Builds and returns the translation unit's parent map.
- ///
- /// The caller takes ownership of the returned \c ParentMap.
- static ParentMap *buildMap(TranslationUnitDecl &TU) {
- ParentMapASTVisitor Visitor(new ParentMap);
- Visitor.TraverseDecl(&TU);
- return Visitor.Parents;
- }
-
-private:
- typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
-
- ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {}
-
- bool shouldVisitTemplateInstantiations() const { return true; }
- bool shouldVisitImplicitCode() const { return true; }
-
- template <typename T>
- bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) {
- if (Node == NULL)
- return true;
- if (ParentStack.size() > 0)
- (*Parents)[Node] = ParentStack.back();
- ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
- bool Result = (this->*traverse)(Node);
- ParentStack.pop_back();
- return Result;
- }
-
- bool TraverseDecl(Decl *DeclNode) {
- return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
- }
-
- bool TraverseStmt(Stmt *StmtNode) {
- return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
- }
-
- ParentMap *Parents;
- llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
-
- friend class RecursiveASTVisitor<ParentMapASTVisitor>;
-};
-
// We use memoization to avoid running the same matcher on the same
// AST node twice. This pair is the key for looking up match
// result. It consists of an ID of the MatcherInterface (for
@@ -183,6 +128,8 @@ public:
// We assume that the QualType and the contained type are on the same
// hierarchy level. Thus, we try to match either of them.
bool TraverseType(QualType TypeNode) {
+ if (TypeNode.isNull())
+ return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
// Match the Type.
if (!match(*TypeNode))
@@ -193,6 +140,8 @@ public:
// We assume that the TypeLoc, contained QualType and contained Type all are
// on the same hierarchy level. Thus, we try to match all of them.
bool TraverseTypeLoc(TypeLoc TypeLocNode) {
+ if (TypeLocNode.isNull())
+ return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
// Match the Type.
if (!match(*TypeLocNode.getType()))
@@ -208,14 +157,19 @@ public:
return (NNS == NULL) || traverse(*NNS);
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ if (!NNS)
+ return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
if (!match(*NNS.getNestedNameSpecifier()))
return false;
- return !NNS || traverse(NNS);
+ return traverse(NNS);
}
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
// Used for updating the depth during traversal.
@@ -435,38 +389,118 @@ public:
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
- if (!Parents) {
- // We always need to run over the whole translation unit, as
- // \c hasAncestor can escape any subtree.
- Parents.reset(ParentMapASTVisitor::buildMap(
- *ActiveASTContext->getTranslationUnitDecl()));
- }
- ast_type_traits::DynTypedNode Ancestor = Node;
- while (Ancestor.get<TranslationUnitDecl>() !=
- ActiveASTContext->getTranslationUnitDecl()) {
- assert(Ancestor.getMemoizationData() &&
- "Invariant broken: only nodes that support memoization may be "
- "used in the parent map.");
- ParentMapASTVisitor::ParentMap::const_iterator I =
- Parents->find(Ancestor.getMemoizationData());
- if (I == Parents->end()) {
- assert(false &&
- "Found node that is not in the parent map.");
- return false;
+ return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
+ MatchMode);
+ }
+
+ // Matches all registered matchers on the given node and calls the
+ // result callback for every node that matches.
+ void match(const ast_type_traits::DynTypedNode& Node) {
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ I != E; ++I) {
+ BoundNodesTreeBuilder Builder;
+ if (I->first->matches(Node, this, &Builder)) {
+ BoundNodesTree BoundNodes = Builder.build();
+ MatchVisitor Visitor(ActiveASTContext, I->second);
+ BoundNodes.visitMatches(&Visitor);
}
- Ancestor = I->second;
- if (Matcher.matches(Ancestor, this, Builder))
- return true;
- if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
- return false;
}
- return false;
}
+ template <typename T> void match(const T &Node) {
+ match(ast_type_traits::DynTypedNode::create(Node));
+ }
+
+ // Implements ASTMatchFinder::getASTContext.
+ virtual ASTContext &getASTContext() const { return *ActiveASTContext; }
+
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
+ // Returns whether an ancestor of \p Node matches \p Matcher.
+ //
+ // The order of matching ((which can lead to different nodes being bound in
+ // case there are multiple matches) is breadth first search.
+ //
+ // To allow memoization in the very common case of having deeply nested
+ // expressions inside a template function, we first walk up the AST, memoizing
+ // the result of the match along the way, as long as there is only a single
+ // parent.
+ //
+ // Once there are multiple parents, the breadth first search order does not
+ // allow simple memoization on the ancestors. Thus, we only memoize as long
+ // as there is a single parent.
+ bool memoizedMatchesAncestorOfRecursively(
+ const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
+ if (Node.get<TranslationUnitDecl>() ==
+ ActiveASTContext->getTranslationUnitDecl())
+ return false;
+ assert(Node.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);
+ if (Parents.empty()) {
+ assert(false && "Found node that is not in the parent map.");
+ return false;
+ }
+ const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
+ MemoizationMap::iterator I = ResultCache.find(input);
+ if (I == ResultCache.end()) {
+ BoundNodesTreeBuilder AncestorBoundNodesBuilder;
+ bool Matches = false;
+ if (Parents.size() == 1) {
+ // Only one parent - do recursive memoization.
+ const ast_type_traits::DynTypedNode Parent = Parents[0];
+ if (Matcher.matches(Parent, this, &AncestorBoundNodesBuilder)) {
+ Matches = true;
+ } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+ Matches = memoizedMatchesAncestorOfRecursively(
+ Parent, Matcher, &AncestorBoundNodesBuilder, MatchMode);
+ }
+ } else {
+ // Multiple parents - BFS over the rest of the nodes.
+ llvm::DenseSet<const void *> Visited;
+ std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
+ Parents.end());
+ while (!Queue.empty()) {
+ if (Matcher.matches(Queue.front(), this,
+ &AncestorBoundNodesBuilder)) {
+ Matches = true;
+ break;
+ }
+ if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+ ASTContext::ParentVector Ancestors =
+ ActiveASTContext->getParents(Queue.front());
+ for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
+ E = Ancestors.end();
+ I != E; ++I) {
+ // Make sure we do not visit the same node twice.
+ // Otherwise, we'll visit the common ancestors as often as there
+ // are splits on the way down.
+ if (Visited.insert(I->getMemoizationData()).second)
+ Queue.push_back(*I);
+ }
+ }
+ Queue.pop_front();
+ }
+ }
+
+ I = ResultCache.insert(std::make_pair(input, MemoizedMatchResult()))
+ .first;
+ I->second.Nodes = AncestorBoundNodesBuilder.build();
+ I->second.ResultOfMatch = Matches;
+ }
+ I->second.Nodes.copyTo(Builder);
+ return I->second.ResultOfMatch;
+ }
+
// Implements a BoundNodesTree::Visitor that calls a MatchCallback with
// the aggregated bound nodes for each match.
class MatchVisitor : public BoundNodesTree::Visitor {
@@ -501,24 +535,6 @@ private:
return false;
}
- // Matches all registered matchers on the given node and calls the
- // result callback for every node that matches.
- template <typename T>
- void match(const T &node) {
- for (std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> >::const_iterator
- I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
- I != E; ++I) {
- BoundNodesTreeBuilder Builder;
- if (I->first->matches(ast_type_traits::DynTypedNode::create(node),
- this, &Builder)) {
- BoundNodesTree BoundNodes = Builder.build();
- MatchVisitor Visitor(ActiveASTContext, I->second);
- BoundNodes.visitMatches(&Visitor);
- }
- }
- }
-
std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> > *const MatcherCallbackPairs;
ASTContext *ActiveASTContext;
@@ -529,8 +545,6 @@ private:
// Maps (matcher, node) -> the match result for memoization.
typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
MemoizationMap ResultCache;
-
- llvm::OwningPtr<ParentMapASTVisitor::ParentMap> Parents;
};
// Returns true if the given class is directly or indirectly derived
@@ -579,7 +593,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
if (SpecializationDecl != NULL) {
ClassDecl = SpecializationDecl;
} else {
- ClassDecl = llvm::dyn_cast<CXXRecordDecl>(
+ ClassDecl = dyn_cast<CXXRecordDecl>(
TemplateType->getTemplateName()
.getAsTemplateDecl()->getTemplatedDecl());
}
@@ -587,7 +601,12 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
ClassDecl = TypeNode->getAsCXXRecordDecl();
}
assert(ClassDecl != NULL);
- assert(ClassDecl != Declaration);
+ if (ClassDecl == Declaration) {
+ // This can happen for recursive template definitions; if the
+ // current declaration did not match, we can safely return false.
+ assert(TemplateType);
+ return false;
+ }
if (Base.matches(*ClassDecl, this, Builder))
return true;
if (classIsDerivedFrom(ClassDecl, Base, Builder))
@@ -729,16 +748,11 @@ ASTConsumer *MatchFinder::newASTConsumer() {
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
}
-void MatchFinder::findAll(const Decl &Node, ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
- Visitor.set_active_ast_context(&Context);
- Visitor.TraverseDecl(const_cast<Decl*>(&Node));
-}
-
-void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) {
+void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context) {
internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
Visitor.set_active_ast_context(&Context);
- Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
+ Visitor.match(Node);
}
void MatchFinder::registerTestCallbackAfterParsing(
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 408195d36902..f1a9ff2e09cb 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -27,8 +27,11 @@ void BoundNodesMap::copyTo(BoundNodesTreeBuilder *Builder) const {
}
void BoundNodesMap::copyTo(BoundNodesMap *Other) const {
- copy(NodeMap.begin(), NodeMap.end(),
- inserter(Other->NodeMap, Other->NodeMap.begin()));
+ for (IDToNodeMap::const_iterator I = NodeMap.begin(),
+ E = NodeMap.end();
+ I != E; ++I) {
+ Other->NodeMap[I->first] = I->second;
+ }
}
BoundNodesTree::BoundNodesTree() {}
diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt
index 8fc7d4b208e8..86560d61c9d3 100644
--- a/lib/ASTMatchers/CMakeLists.txt
+++ b/lib/ASTMatchers/CMakeLists.txt
@@ -1,5 +1,4 @@
set(LLVM_LINK_COMPONENTS support)
-set(LLVM_USED_LIBS clangBasic clangAST)
add_clang_library(clangASTMatchers
ASTMatchFinder.cpp
@@ -15,3 +14,8 @@ add_dependencies(clangASTMatchers
ClangDiagnosticCommon
ClangStmtNodes
)
+
+target_link_libraries(clangASTMatchers
+ clangBasic
+ clangAST
+ )
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index e7df0a813b37..5ff7842407a9 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -12,24 +12,24 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/AnalysisContext.h"
+#include "BodyFarm.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
-#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Support/BumpVector.h"
-#include "llvm/Support/SaveAndRestore.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
-
-#include "BodyFarm.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -67,13 +67,15 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addImplicitDtors,
bool addInitializers,
bool addTemporaryDtors,
- bool synthesizeBodies)
+ bool synthesizeBodies,
+ bool addStaticInitBranch)
: SynthesizeBodies(synthesizeBodies)
{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
+ cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
}
void AnalysisDeclContextManager::clear() {
@@ -87,11 +89,14 @@ static BodyFarm &getBodyFarm(ASTContext &C) {
return *BF;
}
-Stmt *AnalysisDeclContext::getBody() const {
+Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
+ IsAutosynthesized = false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
- if (!Body && Manager && Manager->synthesizeBodies())
+ if (!Body && Manager && Manager->synthesizeBodies()) {
+ IsAutosynthesized = true;
return getBodyFarm(getASTContext()).getBody(FD);
+ }
return Body;
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -105,6 +110,17 @@ Stmt *AnalysisDeclContext::getBody() const {
llvm_unreachable("unknown code decl");
}
+Stmt *AnalysisDeclContext::getBody() const {
+ bool Tmp;
+ return getBody(Tmp);
+}
+
+bool AnalysisDeclContext::isBodyAutosynthesized() const {
+ bool Tmp;
+ getBody(Tmp);
+ return Tmp;
+}
+
const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSelfDecl();
@@ -371,6 +387,31 @@ bool LocationContext::isParentOf(const LocationContext *LC) const {
return false;
}
+void LocationContext::dumpStack() const {
+ ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
+ PrintingPolicy PP(Ctx.getLangOpts());
+ PP.TerseOutput = 1;
+
+ unsigned Frame = 0;
+ for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
+ switch (LCtx->getKind()) {
+ case StackFrame:
+ llvm::errs() << '#' << Frame++ << ' ';
+ cast<StackFrameContext>(LCtx)->getDecl()->print(llvm::errs(), PP);
+ llvm::errs() << '\n';
+ break;
+ case Scope:
+ llvm::errs() << " (scope)\n";
+ break;
+ case Block:
+ llvm::errs() << " (block context: "
+ << cast<BlockInvocationContext>(LCtx)->getContextData()
+ << ")\n";
+ break;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// Lazily generated map to query the external variables referenced by a Block.
//===----------------------------------------------------------------------===//
@@ -403,9 +444,6 @@ public:
if (!VD->hasLocalStorage()) {
if (Visited.insert(VD))
BEVals.push_back(VD, BC);
- } else if (DR->refersToEnclosingLocal()) {
- if (Visited.insert(VD) && IsTrackedDecl(VD))
- BEVals.push_back(VD, BC);
}
}
}
@@ -440,7 +478,13 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
new (BV) DeclVec(BC, 10);
- // Find the referenced variables.
+ // 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);
+ }
+
+ // Find the referenced global/static variables.
FindBlockDeclRefExprsVals F(*BV, BC);
F.Visit(BD->getBody());
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 794ff9cc2bb1..dda26bfab894 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -12,12 +12,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringSwitch.h"
+#include "BodyFarm.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "BodyFarm.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -103,9 +103,7 @@ BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
}
CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
- return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
- Stmts.size(),
- SourceLocation(), SourceLocation());
+ return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());
}
DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
@@ -270,7 +268,11 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
if (D->param_size() != 3)
return 0;
- // Body for:
+ // Signature:
+ // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
+ // void *__newValue,
+ // void * volatile *__theValue)
+ // Generate body:
// if (oldValue == *theValue) {
// *theValue = newValue;
// return YES;
@@ -342,7 +344,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
Stmt *BodyFarm::getBody(const FunctionDecl *D) {
D = D->getCanonicalDecl();
- llvm::Optional<Stmt *> &Val = Bodies[D];
+ Optional<Stmt *> &Val = Bodies[D];
if (Val.hasValue())
return Val.getValue();
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
index d503cc1bcd07..96f61df40d7f 100644
--- a/lib/Analysis/BodyFarm.h
+++ b/lib/Analysis/BodyFarm.h
@@ -15,8 +15,9 @@
#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H
#define LLVM_CLANG_ANALYSIS_BODYFARM_H
-#include "llvm/ADT/Optional.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
namespace clang {
@@ -33,7 +34,7 @@ public:
Stmt *getBody(const FunctionDecl *D);
private:
- typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap;
+ typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap;
ASTContext &C;
BodyMap Bodies;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 315e54380b2f..1adb8b84e462 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -12,20 +12,20 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/SaveAndRestore.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/Basic/AttrKinds.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Format.h"
+#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -233,6 +233,44 @@ public:
}
};
+class reverse_children {
+ llvm::SmallVector<Stmt *, 12> childrenBuf;
+ ArrayRef<Stmt*> children;
+public:
+ reverse_children(Stmt *S);
+
+ typedef ArrayRef<Stmt*>::reverse_iterator iterator;
+ iterator begin() const { return children.rbegin(); }
+ iterator end() const { return children.rend(); }
+};
+
+
+reverse_children::reverse_children(Stmt *S) {
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ children = CE->getRawSubExprs();
+ return;
+ }
+ switch (S->getStmtClass()) {
+ // Note: Fill in this switch with more cases we want to optimize.
+ case Stmt::InitListExprClass: {
+ InitListExpr *IE = cast<InitListExpr>(S);
+ children = llvm::makeArrayRef(reinterpret_cast<Stmt**>(IE->getInits()),
+ IE->getNumInits());
+ return;
+ }
+ default:
+ break;
+ }
+
+ // Default case for all other statements.
+ for (Stmt::child_range I = S->children(); I; ++I) {
+ childrenBuf.push_back(*I);
+ }
+
+ // This needs to be done *after* childrenBuf has been populated.
+ children = childrenBuf;
+}
+
/// CFGBuilder - This class implements CFG construction from an AST.
/// The builder is stateful: an instance of the builder should be used to only
/// construct a single CFG.
@@ -637,7 +675,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
E = BackpatchBlocks.end(); I != E; ++I ) {
CFGBlock *B = I->block;
- GotoStmt *G = cast<GotoStmt>(B->getTerminator());
+ const GotoStmt *G = cast<GotoStmt>(B->getTerminator());
LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
// If there is no target for the goto, then we are looking at an
@@ -807,7 +845,7 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
Ty = Context->getBaseElementType(Ty);
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
- if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
+ if (Dtor->isNoReturn())
Block = createNoReturnBlock();
else
autoCreateBlock();
@@ -1166,14 +1204,19 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
}
/// VisitChildren - Visit the children of a Stmt.
-CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) {
- CFGBlock *lastBlock = Block;
- for (Stmt::child_range I = Terminator->children(); I; ++I)
- if (Stmt *child = *I)
- if (CFGBlock *b = Visit(child))
- lastBlock = b;
+CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
+ CFGBlock *B = Block;
- return lastBlock;
+ // Visit the children in their reverse order so that they appear in
+ // left-to-right (natural) order in the CFG.
+ reverse_children RChildren(S);
+ for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end();
+ I != E; ++I) {
+ if (Stmt *Child = *I)
+ if (CFGBlock *R = Visit(Child))
+ B = R;
+ }
+ return B;
}
CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
@@ -1402,7 +1445,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
}
if (FunctionDecl *FD = C->getDirectCallee()) {
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->isNoReturn())
NoReturn = true;
if (FD->hasAttr<NoThrowAttr>())
AddEHEdge = false;
@@ -1610,6 +1653,21 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
bool IsReference = false;
bool HasTemporaries = false;
+ // Guard static initializers under a branch.
+ CFGBlock *blockAfterStaticInit = 0;
+
+ 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;
+ if (badCFG)
+ return 0;
+ }
+ blockAfterStaticInit = Succ;
+ }
+
// Destructors of temporaries in initialization expression should be called
// after initialization finishes.
Expr *Init = VD->getInit();
@@ -1657,7 +1715,17 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
if (ScopePos && VD == *ScopePos)
++ScopePos;
- return Block ? Block : LastBlock;
+ CFGBlock *B = LastBlock;
+ if (blockAfterStaticInit) {
+ Succ = B;
+ Block = createBlock(false);
+ Block->setTerminator(DS);
+ addSuccessor(Block, blockAfterStaticInit);
+ addSuccessor(Block, B);
+ B = Block;
+ }
+
+ return B;
}
CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
@@ -3093,19 +3161,14 @@ tryAgain:
CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
// When visiting children for destructors we want to visit them in reverse
- // order. Because there's no reverse iterator for children must to reverse
- // them in helper vector.
- typedef SmallVector<Stmt *, 4> ChildrenVect;
- ChildrenVect ChildrenRev;
- for (Stmt::child_range I = E->children(); I; ++I) {
- if (*I) ChildrenRev.push_back(*I);
- }
-
+ // order that they will appear in the CFG. Because the CFG is built
+ // bottom-up, this means we visit them in their natural order, which
+ // reverses them in the CFG.
CFGBlock *B = Block;
- for (ChildrenVect::reverse_iterator I = ChildrenRev.rbegin(),
- L = ChildrenRev.rend(); I != L; ++I) {
- if (CFGBlock *R = VisitForTemporaryDtors(*I))
- B = R;
+ for (Stmt::child_range I = E->children(); I; ++I) {
+ if (Stmt *Child = *I)
+ if (CFGBlock *R = VisitForTemporaryDtors(Child))
+ B = R;
}
return B;
}
@@ -3190,7 +3253,7 @@ 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 (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
+ if (Dtor->isNoReturn())
Block = createNoReturnBlock();
else
autoCreateBlock();
@@ -3294,13 +3357,12 @@ CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
const CXXDestructorDecl *
CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
switch (getKind()) {
- case CFGElement::Invalid:
case CFGElement::Statement:
case CFGElement::Initializer:
llvm_unreachable("getDestructorDecl should only be used with "
"ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
- const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl();
+ const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
QualType ty = var->getType();
ty = ty.getNonReferenceType();
while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
@@ -3313,7 +3375,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
}
case CFGElement::TemporaryDtor: {
const CXXBindTemporaryExpr *bindExpr =
- cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr();
+ castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
const CXXTemporary *temp = bindExpr->getTemporary();
return temp->getDestructor();
}
@@ -3327,10 +3389,8 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
}
bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
- if (const CXXDestructorDecl *decl = getDestructorDecl(astContext)) {
- QualType ty = decl->getType();
- return cast<FunctionType>(ty)->getNoReturnAttr();
- }
+ if (const CXXDestructorDecl *DD = getDestructorDecl(astContext))
+ return DD->isNoReturn();
return false;
}
@@ -3370,7 +3430,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
- if (const CFGStmt *S = BI->getAs<CFGStmt>())
+ if (Optional<CFGStmt> S = BI->getAs<CFGStmt>())
FindSubExprAssignments(S->getStmt(), SubExprAssignments);
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
@@ -3379,7 +3439,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// block-level that are block-level expressions.
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
- const CFGStmt *CS = BI->getAs<CFGStmt>();
+ Optional<CFGStmt> CS = BI->getAs<CFGStmt>();
if (!CS)
continue;
if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) {
@@ -3495,7 +3555,7 @@ public:
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j ) {
- if (const CFGStmt *SE = BI->getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
const Stmt *stmt= SE->getStmt();
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
StmtMap[stmt] = P;
@@ -3607,6 +3667,11 @@ public:
Terminator->printPretty(OS, Helper, Policy);
}
+ void VisitDeclStmt(DeclStmt *DS) {
+ VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ OS << "static init " << VD->getName();
+ }
+
void VisitForStmt(ForStmt *F) {
OS << "for (" ;
if (F->getInit())
@@ -3685,7 +3750,7 @@ public:
static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
const CFGElement &E) {
- if (const CFGStmt *CS = E.getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> CS = E.getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (Helper) {
@@ -3733,7 +3798,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
if (isa<Expr>(S))
OS << '\n';
- } else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) {
+ } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
const CXXCtorInitializer *I = IE->getInitializer();
if (I->isBaseInitializer())
OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
@@ -3748,7 +3813,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
OS << " (Base initializer)\n";
else OS << " (Member initializer)\n";
- } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){
+ } else if (Optional<CFGAutomaticObjDtor> DE =
+ E.getAs<CFGAutomaticObjDtor>()) {
const VarDecl *VD = DE->getVarDecl();
Helper->handleDecl(VD, OS);
@@ -3760,19 +3826,19 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
- } else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) {
+ } else if (Optional<CFGBaseDtor> BE = E.getAs<CFGBaseDtor>()) {
const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Base object destructor)\n";
- } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) {
+ } else if (Optional<CFGMemberDtor> ME = E.getAs<CFGMemberDtor>()) {
const FieldDecl *FD = ME->getFieldDecl();
const Type *T = FD->getType()->getBaseElementTypeUnsafe();
OS << "this->" << FD->getName();
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
OS << " (Member object destructor)\n";
- } else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) {
+ } else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Temporary object destructor)\n";
@@ -3893,7 +3959,7 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
I != E; ++I, ++i) {
- if (i == 8 || (i-8) == 0)
+ if (i % 10 == 8)
OS << "\n ";
OS << " B" << (*I)->getBlockID();
@@ -3922,7 +3988,7 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
I != E; ++I, ++i) {
- if (i == 8 || (i-8) % 10 == 0)
+ if (i % 10 == 8)
OS << "\n ";
if (*I)
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 16df67678df5..87c2f5bdc130 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -50,7 +50,7 @@ static void Accumulate(SMap &SM, CFGBlock *B) {
// First walk the block-level expressions.
for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) {
const CFGElement &CE = *I;
- const CFGStmt *CS = CE.getAs<CFGStmt>();
+ Optional<CFGStmt> CS = CE.getAs<CFGStmt>();
if (!CS)
continue;
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 6b759567889e..33870158b384 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -10,16 +10,21 @@
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/CallGraph.h"
+#define DEBUG_TYPE "CallGraph"
+#include "clang/Analysis/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/StmtVisitor.h"
-
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/GraphWriter.h"
using namespace clang;
+STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
+STATISTIC(NumBlockCallEdges, "Number of block call edges");
+
namespace {
/// A helper class, which walks the AST and locates all the call sites in the
/// given function body.
@@ -33,13 +38,48 @@ public:
void VisitStmt(Stmt *S) { VisitChildren(S); }
- void VisitCallExpr(CallExpr *CE) {
- // TODO: We need to handle ObjC method calls as well.
+ Decl *getDeclFromCall(CallExpr *CE) {
if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
- if (G->includeInGraph(CalleeDecl)) {
- CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl);
- CallerNode->addCallee(CalleeNode, G);
+ return CalleeDecl;
+
+ // Simple detection of a call through a block.
+ Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
+ if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {
+ NumBlockCallEdges++;
+ return Block->getBlockDecl();
+ }
+
+ return 0;
+ }
+
+ void addCalledDecl(Decl *D) {
+ if (G->includeInGraph(D)) {
+ CallGraphNode *CalleeNode = G->getOrInsertNode(D);
+ CallerNode->addCallee(CalleeNode, G);
+ }
+ }
+
+ void VisitCallExpr(CallExpr *CE) {
+ if (Decl *D = getDeclFromCall(CE))
+ addCalledDecl(D);
+ }
+
+ // Adds may-call edges for the ObjC message sends.
+ void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
+ Selector Sel = ME->getSelector();
+
+ // Find the callee definition within the same translation unit.
+ Decl *D = 0;
+ if (ME->isInstanceMessage())
+ D = IDecl->lookupPrivateMethod(Sel);
+ else
+ D = IDecl->lookupPrivateClassMethod(Sel);
+ if (D) {
+ addCalledDecl(D);
+ NumObjCCallEdges++;
}
+ }
}
void VisitChildren(Stmt *S) {
@@ -51,6 +91,16 @@ public:
} // end anonymous namespace
+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))
+ addNodesForBlocks(DC);
+}
+
CallGraph::CallGraph() {
Root = getOrInsertNode(0);
}
@@ -65,6 +115,10 @@ CallGraph::~CallGraph() {
}
bool CallGraph::includeInGraph(const Decl *D) {
+ assert(D);
+ if (!D->getBody())
+ return false;
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
@@ -88,14 +142,8 @@ bool CallGraph::includeInGraph(const Decl *D) {
void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
assert(D);
- // Do nothing if the node already exists.
- if (FunctionMap.find(D) != FunctionMap.end())
- return;
-
// Allocate a new node, mark it as root, and process it's calls.
CallGraphNode *Node = getOrInsertNode(D);
- if (IsGlobal)
- Root->addCallee(Node, this);
// Process all the calls by this function as well.
CGBuilder builder(this, Node);
@@ -115,23 +163,31 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
return Node;
Node = new CallGraphNode(F);
- // If not root, add to the parentless list.
+ // Make Root node a parent of all functions to make sure all are reachable.
if (F != 0)
- ParentlessNodes.insert(Node);
+ Root->addCallee(Node, this);
return Node;
}
void CallGraph::print(raw_ostream &OS) const {
OS << " --- Call graph Dump --- \n";
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
+
+ // We are going to print the graph in reverse post order, partially, to make
+ // sure the output is deterministic.
+ llvm::ReversePostOrderTraversal<const clang::CallGraph*> RPOT(this);
+ for (llvm::ReversePostOrderTraversal<const clang::CallGraph*>::rpo_iterator
+ I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
+ const CallGraphNode *N = *I;
+
OS << " Function: ";
- if (I->second == Root)
+ if (N == Root)
OS << "< root >";
else
- I->second->print(OS);
+ N->print(OS);
+
OS << " calls: ";
- for (CallGraphNode::iterator CI = I->second->begin(),
- CE = I->second->end(); CI != CE; ++CI) {
+ for (CallGraphNode::const_iterator CI = N->begin(),
+ CE = N->end(); CI != CE; ++CI) {
assert(*CI != Root && "No one can call the root node.");
(*CI)->print(OS);
OS << " ";
@@ -149,15 +205,10 @@ void CallGraph::viewGraph() const {
llvm::ViewGraph(this, "CallGraph");
}
-StringRef CallGraphNode::getName() const {
- if (const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(FD))
- if (const IdentifierInfo *II = D->getIdentifier())
- return II->getName();
- return "< >";
-}
-
void CallGraphNode::print(raw_ostream &os) const {
- os << getName();
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
+ return ND->printName(os);
+ os << "< >";
}
void CallGraphNode::dump() const {
@@ -176,7 +227,10 @@ struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
if (CG->getRoot() == Node) {
return "< root >";
}
- return Node->getName();
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
+ return ND->getNameAsString();
+ else
+ return "< >";
}
};
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index ce973af6d431..0db3cac58b56 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -12,12 +12,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
using namespace clang;
using namespace ento;
@@ -106,7 +106,7 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
char ch = *it;
if (ch == 'C' || ch == 'c') {
// Make sure this isn't something like 'recreate' or 'Scopy'.
- if (ch == 'c' && it != start && isalpha(*(it - 1)))
+ if (ch == 'c' && it != start && isLetter(*(it - 1)))
continue;
++it;
@@ -131,7 +131,7 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
continue;
}
- if (it == endI || !islower(*it))
+ if (it == endI || !isLowercase(*it))
return true;
// If we matched a lowercase character, it isn't the end of the
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 73063b5132c8..ad0dce4444b6 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -204,7 +204,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
case 'a':
- if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) {
+ if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
// For scanf in C90, look at the next character to see if this should
// be parsed as the GNU extension 'a' length modifier. If not, this
// will be parsed as a conversion specifier.
@@ -527,13 +527,13 @@ const char *ConversionSpecifier::toString() const {
return NULL;
}
-llvm::Optional<ConversionSpecifier>
+Optional<ConversionSpecifier>
ConversionSpecifier::getStandardSpecifier() const {
ConversionSpecifier::Kind NewKind;
switch (getKind()) {
default:
- return llvm::Optional<ConversionSpecifier>();
+ return None;
case DArg:
NewKind = dArg;
break;
@@ -756,8 +756,7 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
-llvm::Optional<LengthModifier>
-FormatSpecifier::getCorrectedLengthModifier() const {
+Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
if (LM.getKind() == LengthModifier::AsLongDouble ||
LM.getKind() == LengthModifier::AsQuad) {
@@ -767,7 +766,7 @@ FormatSpecifier::getCorrectedLengthModifier() const {
}
}
- return llvm::Optional<LengthModifier>();
+ return None;
}
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h
index f483ec6facff..6b251230136a 100644
--- a/lib/Analysis/FormatStringParsing.h
+++ b/lib/Analysis/FormatStringParsing.h
@@ -1,9 +1,9 @@
#ifndef LLVM_CLANG_FORMAT_PARSING_H
#define LLVM_CLANG_FORMAT_PARSING_H
-#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/FormatString.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 38f8199bffce..b43892a30938 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -1,15 +1,25 @@
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs ----------*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Live Variables analysis for source-level CFGs.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Stmt.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
-
-#include "llvm/ADT/PostOrderIterator.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "llvm/ADT/DenseMap.h"
-
-#include <deque>
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <vector>
@@ -464,15 +474,16 @@ LiveVariablesImpl::runOnBlock(const CFGBlock *block,
ei = block->rend(); it != ei; ++it) {
const CFGElement &elem = *it;
- if (const CFGAutomaticObjDtor *Dtor = dyn_cast<CFGAutomaticObjDtor>(&elem)){
+ if (Optional<CFGAutomaticObjDtor> Dtor =
+ elem.getAs<CFGAutomaticObjDtor>()) {
val.liveDecls = DSetFact.add(val.liveDecls, Dtor->getVarDecl());
continue;
}
- if (!isa<CFGStmt>(elem))
+ if (!elem.getAs<CFGStmt>())
continue;
- const Stmt *S = cast<CFGStmt>(elem).getStmt();
+ const Stmt *S = elem.castAs<CFGStmt>().getStmt();
TF.Visit(const_cast<Stmt*>(S));
stmtsToLiveness[S] = val;
}
@@ -524,8 +535,9 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
if (killAtAssign)
for (CFGBlock::const_iterator bi = block->begin(), be = block->end();
bi != be; ++bi) {
- if (const CFGStmt *cs = bi->getAs<CFGStmt>()) {
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(cs->getStmt())) {
+ if (Optional<CFGStmt> cs = bi->getAs<CFGStmt>()) {
+ if (const BinaryOperator *BO =
+ dyn_cast<BinaryOperator>(cs->getStmt())) {
if (BO->getOpcode() == BO_Assign) {
if (const DeclRefExpr *DR =
dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) {
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 2fa5a88f2c71..8f151b9358e6 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
-#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -359,17 +359,19 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case ConversionSpecifier::sArg:
if (LM.getKind() == LengthModifier::AsWideChar) {
if (IsObjCLiteral)
- return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
+ return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
+ "const unichar *");
return ArgType(ArgType::WCStrTy, "wchar_t *");
}
return ArgType::CStrTy;
case ConversionSpecifier::SArg:
if (IsObjCLiteral)
- return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
+ return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
+ "const unichar *");
return ArgType(ArgType::WCStrTy, "wchar_t *");
case ConversionSpecifier::CArg:
if (IsObjCLiteral)
- return Ctx.UnsignedShortTy;
+ return ArgType(Ctx.UnsignedShortTy, "unichar");
return ArgType(Ctx.WCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgType::CPointerTy;
@@ -494,11 +496,29 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
namedTypeToLengthModifier(QT, LM);
- // If fixing the length modifier was enough, we are done.
+ // If fixing the length modifier was enough, we might be done.
if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ // If we're going to offer a fix anyway, make sure the sign matches.
+ switch (CS.getKind()) {
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
+ if (QT->isSignedIntegerType())
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
+ break;
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::iArg:
+ if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
+ break;
+ default:
+ // Other specifiers do not have signed/unsigned variants.
+ break;
+ }
+
const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
if (ATR.isValid() && ATR.matchesType(Ctx, QT))
return true;
@@ -506,7 +526,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
- if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
+ if (!isa<TypedefType>(QT) && QT->isCharType()) {
CS.setKind(ConversionSpecifier::cArg);
LM.setKind(LengthModifier::None);
Precision.setHowSpecified(OptionalAmount::NotSpecified);
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 11f2ebe9ad2d..a90aebbe28ed 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -12,16 +12,16 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/Analysis/Analyses/ReachableCode.h"
-#include "clang/Analysis/CFG.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -29,9 +29,9 @@ namespace {
class DeadCodeScan {
llvm::BitVector Visited;
llvm::BitVector &Reachable;
- llvm::SmallVector<const CFGBlock *, 10> WorkList;
+ SmallVector<const CFGBlock *, 10> WorkList;
- typedef llvm::SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
+ typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
DeferredLocsTy;
DeferredLocsTy DeferredLocs;
@@ -95,7 +95,7 @@ static bool isValidDeadStmt(const Stmt *S) {
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
- if (const CFGStmt *CS = I->getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (isValidDeadStmt(S))
return S;
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 574e56a5e068..2dbc9e494881 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
-#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -445,7 +445,7 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index c7f1f62cb57d..4fe342dcc8c2 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -16,17 +16,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/ThreadSafety.h"
-#include "clang/Analysis/Analyses/PostOrderCFGView.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/CFGStmtMap.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/Basic/SourceManager.h"
-#include "clang/Basic/SourceLocation.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -164,15 +165,16 @@ private:
/// should be evaluated; multiple calling contexts can be chained together
/// by the lock_returned attribute.
struct CallingContext {
- const NamedDecl* AttrDecl; // The decl to which the attribute is attached.
- Expr* SelfArg; // Implicit object argument -- e.g. 'this'
- bool SelfArrow; // is Self referred to with -> or .?
- unsigned NumArgs; // Number of funArgs
- Expr** FunArgs; // Function arguments
- CallingContext* PrevCtx; // The previous context; or 0 if none.
-
- CallingContext(const NamedDecl *D = 0, Expr *S = 0,
- unsigned N = 0, Expr **A = 0, CallingContext *P = 0)
+ const NamedDecl* AttrDecl; // The decl to which the attribute is attached.
+ const Expr* SelfArg; // Implicit object argument -- e.g. 'this'
+ bool SelfArrow; // is Self referred to with -> or .?
+ unsigned NumArgs; // Number of funArgs
+ 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)
{ }
@@ -272,15 +274,16 @@ private:
/// NDeref returns the number of Derefence and AddressOf operations
/// preceeding the Expr; this is used to decide whether to pretty-print
/// SExprs with . or ->.
- unsigned buildSExpr(Expr *Exp, CallingContext* CallCtx, int* NDeref = 0) {
+ unsigned buildSExpr(const Expr *Exp, CallingContext* CallCtx,
+ int* NDeref = 0) {
if (!Exp)
return 0;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
- NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
- ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND);
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
+ const NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
+ const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND);
if (PV) {
- FunctionDecl *FD =
+ const FunctionDecl *FD =
cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
unsigned i = PV->getFunctionScopeIndex();
@@ -309,18 +312,18 @@ private:
makeThis();
return 1;
}
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
- NamedDecl *ND = ME->getMemberDecl();
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+ const NamedDecl *ND = ME->getMemberDecl();
int ImplicitDeref = ME->isArrow() ? 1 : 0;
unsigned Root = makeDot(ND, false);
unsigned Sz = buildSExpr(ME->getBase(), CallCtx, &ImplicitDeref);
NodeVec[Root].setArrow(ImplicitDeref > 0);
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
- } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+ } else if (const CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
// When calling a function with a lock_returned attribute, replace
// the function call with the expression in lock_returned.
- CXXMethodDecl* MD =
+ const CXXMethodDecl* MD =
cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl());
if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CMCE->getMethodDecl());
@@ -343,14 +346,14 @@ private:
unsigned NumCallArgs = CMCE->getNumArgs();
unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl());
unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx);
- Expr** CallArgs = CMCE->getArgs();
+ const Expr* const* CallArgs = CMCE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
Sz += buildSExpr(CallArgs[i], CallCtx);
}
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
- } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- FunctionDecl* FD =
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
+ const FunctionDecl* FD =
cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl());
if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CE->getDirectCallee());
@@ -361,7 +364,7 @@ private:
}
// Treat smart pointers and iterators as pointers;
// ignore the * and -> operators.
- if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) {
+ if (const CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) {
OverloadedOperatorKind k = OE->getOperator();
if (k == OO_Star) {
if (NDeref) ++(*NDeref);
@@ -374,19 +377,19 @@ private:
unsigned NumCallArgs = CE->getNumArgs();
unsigned Root = makeCall(NumCallArgs, 0);
unsigned Sz = buildSExpr(CE->getCallee(), CallCtx);
- Expr** CallArgs = CE->getArgs();
+ const Expr* const* CallArgs = CE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
Sz += buildSExpr(CallArgs[i], CallCtx);
}
NodeVec[Root].setSize(Sz+1);
return Sz+1;
- } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
+ } else if (const BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
unsigned Root = makeBinary();
unsigned Sz = buildSExpr(BOE->getLHS(), CallCtx);
Sz += buildSExpr(BOE->getRHS(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
+ } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
// Ignore & and * operators -- they're no-ops.
// However, we try to figure out whether the expression is a pointer,
// so we can use . and -> appropriately in error messages.
@@ -412,13 +415,14 @@ private:
unsigned Sz = buildSExpr(UOE->getSubExpr(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) {
+ } else if (const ArraySubscriptExpr *ASE =
+ dyn_cast<ArraySubscriptExpr>(Exp)) {
unsigned Root = makeIndex();
unsigned Sz = buildSExpr(ASE->getBase(), CallCtx);
Sz += buildSExpr(ASE->getIdx(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (AbstractConditionalOperator *CE =
+ } else if (const AbstractConditionalOperator *CE =
dyn_cast<AbstractConditionalOperator>(Exp)) {
unsigned Root = makeUnknown(3);
unsigned Sz = buildSExpr(CE->getCond(), CallCtx);
@@ -426,20 +430,20 @@ private:
Sz += buildSExpr(CE->getFalseExpr(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
+ } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
unsigned Root = makeUnknown(3);
unsigned Sz = buildSExpr(CE->getCond(), CallCtx);
Sz += buildSExpr(CE->getLHS(), CallCtx);
Sz += buildSExpr(CE->getRHS(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
+ } else if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
return buildSExpr(CE->getSubExpr(), CallCtx, NDeref);
- } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
+ } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
return buildSExpr(PE->getSubExpr(), CallCtx, NDeref);
- } else if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) {
+ } else if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) {
return buildSExpr(EWC->getSubExpr(), CallCtx, NDeref);
- } else if (CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) {
+ } else if (const CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) {
return buildSExpr(E->getSubExpr(), CallCtx, NDeref);
} else if (isa<CharacterLiteral>(Exp) ||
isa<CXXNullPtrLiteralExpr>(Exp) ||
@@ -463,12 +467,12 @@ private:
/// \param DeclExp An expression involving the Decl on which the attribute
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
- void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D,
- VarDecl *SelfDecl = 0) {
+ void buildSExprFromExpr(const Expr *MutexExp, const Expr *DeclExp,
+ const NamedDecl *D, VarDecl *SelfDecl = 0) {
CallingContext CallCtx(D);
if (MutexExp) {
- if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
+ if (const StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
if (SLit->getString() == StringRef("*"))
// The "*" expr is a universal lock, which essentially turns off
// checks until it is removed from the lockset.
@@ -488,18 +492,21 @@ private:
// Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
// for formal parameters when we call buildMutexID later.
- if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
CallCtx.SelfArg = ME->getBase();
CallCtx.SelfArrow = ME->isArrow();
- } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
+ } else if (const CXXMemberCallExpr *CE =
+ dyn_cast<CXXMemberCallExpr>(DeclExp)) {
CallCtx.SelfArg = CE->getImplicitObjectArgument();
CallCtx.SelfArrow = dyn_cast<MemberExpr>(CE->getCallee())->isArrow();
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
- } else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
+ } else if (const CallExpr *CE =
+ dyn_cast<CallExpr>(DeclExp)) {
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
- } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
+ } else if (const CXXConstructExpr *CE =
+ dyn_cast<CXXConstructExpr>(DeclExp)) {
CallCtx.SelfArg = 0; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
@@ -543,7 +550,7 @@ public:
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
/// Caller must check isValid() after construction.
- SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D,
+ SExpr(const Expr* MutexExp, const Expr *DeclExp, const NamedDecl* D,
VarDecl *SelfDecl=0) {
buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
@@ -566,8 +573,9 @@ public:
}
/// Issue a warning about an invalid lock expression
- static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
- Expr *DeclExp, const NamedDecl* D) {
+ static void warnInvalidLock(ThreadSafetyHandler &Handler,
+ const Expr *MutexExp,
+ const Expr *DeclExp, const NamedDecl* D) {
SourceLocation Loc;
if (DeclExp)
Loc = DeclExp->getExprLoc();
@@ -776,7 +784,7 @@ struct LockData {
/// \brief A FactEntry stores a single fact that is known at a particular point
/// in the program execution. Currently, this is information regarding a lock
-/// that is held at that point.
+/// that is held at that point.
struct FactEntry {
SExpr MutID;
LockData LDat;
@@ -789,7 +797,7 @@ struct FactEntry {
typedef unsigned short FactID;
-/// \brief FactManager manages the memory for all facts that are created during
+/// \brief FactManager manages the memory for all facts that are created during
/// the analysis of a single routine.
class FactManager {
private:
@@ -807,9 +815,9 @@ public:
/// \brief A FactSet is the set of facts that are known to be true at a
-/// particular program point. FactSets must be small, because they are
+/// particular program point. FactSets must be small, because they are
/// frequently copied, and are thus implemented as a set of indices into a
-/// table maintained by a FactManager. A typical FactSet only holds 1 or 2
+/// table maintained by a FactManager. A typical FactSet only holds 1 or 2
/// locks, so we can get away with doing a linear search for lookup. Note
/// that a hashtable or map is inappropriate in this case, because lookups
/// may involve partial pattern matches, rather than exact matches.
@@ -1342,8 +1350,8 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
BE = CurrBlock->end(); BI != BE; ++BI) {
switch (BI->getKind()) {
case CFGElement::Statement: {
- const CFGStmt *CS = cast<CFGStmt>(&*BI);
- VMapBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+ CFGStmt CS = BI->castAs<CFGStmt>();
+ VMapBuilder.Visit(const_cast<Stmt*>(CS.getStmt()));
break;
}
default:
@@ -1389,7 +1397,7 @@ static void findBlockLocations(CFG *CFGraph,
for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(),
BE = CurrBlock->rend(); BI != BE; ++BI) {
// FIXME: Handle other CFGElement kinds.
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+ if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) {
CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart();
break;
}
@@ -1402,7 +1410,7 @@ static void findBlockLocations(CFG *CFGraph,
for (CFGBlock::const_iterator BI = CurrBlock->begin(),
BE = CurrBlock->end(); BI != BE; ++BI) {
// FIXME: Handle other CFGElement kinds.
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+ if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) {
CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart();
break;
}
@@ -1733,14 +1741,15 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
unsigned CtxIndex;
// Helper functions
- const ValueDecl *getValueDecl(Expr *Exp);
+ const ValueDecl *getValueDecl(const Expr *Exp);
- void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,
+ void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
- void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);
+ void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp);
+
+ void checkAccess(const Expr *Exp, AccessKind AK);
+ void checkPtAccess(const Expr *Exp, AccessKind AK);
- void checkAccess(Expr *Exp, AccessKind AK);
- void checkDereference(Expr *Exp, AccessKind AK);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
public:
@@ -1762,7 +1771,10 @@ public:
/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
-const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
+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();
@@ -1774,7 +1786,7 @@ const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
/// \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, Expr *Exp,
+void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
AccessKind AK, Expr *MutexExp,
ProtectedOperationKind POK) {
LockKind LK = getLockKindFromAccessKind(AK);
@@ -1813,7 +1825,7 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
}
/// \brief Warn if the LSet contains the given lock.
-void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr* Exp,
Expr *MutexExp) {
SExpr Mutex(MutexExp, Exp, D);
if (!Mutex.isValid()) {
@@ -1831,51 +1843,61 @@ void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
}
-/// \brief This method identifies variable dereferences and checks pt_guarded_by
-/// and pt_guarded_var annotations. Note that we only check these annotations
-/// at the time a pointer is dereferenced.
-/// FIXME: We need to check for other types of pointer dereferences
-/// (e.g. [], ->) and deal with them here.
-/// \param Exp An expression that has been read or written.
-void BuildLockset::checkDereference(Expr *Exp, AccessKind AK) {
- UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp);
- if (!UO || UO->getOpcode() != clang::UO_Deref)
+/// \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.
+/// Similarly, we check if the access is to an expression that dereferences
+/// a pointer marked with pt_guarded_by.
+void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
+ Exp = Exp->IgnoreParenCasts();
+
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) {
+ // For dereferences
+ if (UO->getOpcode() == clang::UO_Deref)
+ checkPtAccess(UO->getSubExpr(), AK);
return;
- Exp = UO->getSubExpr()->IgnoreParenCasts();
+ }
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+ if (ME->isArrow())
+ checkPtAccess(ME->getBase(), AK);
+ else
+ checkAccess(ME->getBase(), AK);
+ }
const ValueDecl *D = getValueDecl(Exp);
- if(!D || !D->hasAttrs())
+ if (!D || !D->hasAttrs())
return;
- if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK,
+ if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty())
+ Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK,
Exp->getExprLoc());
const AttrVec &ArgAttrs = D->getAttrs();
- for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
- if (PtGuardedByAttr *PGBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i]))
- warnIfMutexNotHeld(D, Exp, AK, PGBAttr->getArg(), POK_VarDereference);
+ 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);
}
-/// \brief Checks guarded_by and guarded_var attributes.
-/// Whenever we identify an access (read or write) of a DeclRefExpr or
-/// MemberExpr, we need to check whether there are any guarded_by or
-/// guarded_var attributes, and make sure we hold the appropriate mutexes.
-void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) {
+/// \brief Checks pt_guarded_by and pt_guarded_var attributes.
+void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
+ Exp = Exp->IgnoreParenCasts();
+
const ValueDecl *D = getValueDecl(Exp);
- if(!D || !D->hasAttrs())
+ if (!D || !D->hasAttrs())
return;
- if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK,
+ if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty())
+ Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, 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 (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);
}
+
/// \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,
@@ -2009,9 +2031,7 @@ void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) {
case clang::UO_PostInc:
case clang::UO_PreDec:
case clang::UO_PreInc: {
- Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts();
- checkAccess(SubExp, AK_Written);
- checkDereference(SubExp, AK_Written);
+ checkAccess(UO->getSubExpr(), AK_Written);
break;
}
default:
@@ -2029,9 +2049,7 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
// adjust the context
LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
- Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
- checkAccess(LHSExp, AK_Written);
- checkDereference(LHSExp, AK_Written);
+ checkAccess(BO->getLHS(), AK_Written);
}
/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
@@ -2040,13 +2058,46 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
void BuildLockset::VisitCastExpr(CastExpr *CE) {
if (CE->getCastKind() != CK_LValueToRValue)
return;
- Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts();
- checkAccess(SubExp, AK_Read);
- checkDereference(SubExp, AK_Read);
+ checkAccess(CE->getSubExpr(), AK_Read);
}
void BuildLockset::VisitCallExpr(CallExpr *Exp) {
+ if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee());
+ // ME can be null when calling a method pointer
+ CXXMethodDecl *MD = CE->getMethodDecl();
+
+ if (ME && MD) {
+ if (ME->isArrow()) {
+ if (MD->isConst()) {
+ checkPtAccess(CE->getImplicitObjectArgument(), AK_Read);
+ } else { // FIXME -- should be AK_Written
+ checkPtAccess(CE->getImplicitObjectArgument(), AK_Read);
+ }
+ } else {
+ if (MD->isConst())
+ checkAccess(CE->getImplicitObjectArgument(), AK_Read);
+ else // FIXME -- should be AK_Written
+ checkAccess(CE->getImplicitObjectArgument(), AK_Read);
+ }
+ }
+ } else if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) {
+ switch (OE->getOperator()) {
+ case OO_Equal: {
+ const Expr *Target = OE->getArg(0);
+ const Expr *Source = OE->getArg(1);
+ checkAccess(Target, AK_Written);
+ checkAccess(Source, AK_Read);
+ break;
+ }
+ default: {
+ const Expr *Source = OE->getArg(0);
+ checkAccess(Source, AK_Read);
+ break;
+ }
+ }
+ }
NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
if(!D || !D->hasAttrs())
return;
@@ -2054,6 +2105,11 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
}
void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) {
+ const CXXConstructorDecl *D = Exp->getConstructor();
+ if (D && D->isCopyConstructor()) {
+ const Expr* Source = Exp->getArg(0);
+ checkAccess(Source, AK_Read);
+ }
// FIXME -- only handles constructors in DeclStmt below.
}
@@ -2164,6 +2220,21 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
}
+// Return true if block B never continues to its successors.
+inline bool neverReturns(const CFGBlock* B) {
+ if (B->hasNoReturnElement())
+ return true;
+ if (B->empty())
+ return false;
+
+ CFGElement Last = B->back();
+ if (Optional<CFGStmt> S = Last.getAs<CFGStmt>()) {
+ if (isa<CXXThrowExpr>(S->getStmt()))
+ return true;
+ }
+ return false;
+}
+
/// \brief Check a function's CFG for thread-safety violations.
///
@@ -2281,7 +2352,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// union because the real error is probably that we forgot to unlock M on
// all code paths.
bool LocksetInitialized = false;
- llvm::SmallVector<CFGBlock*, 8> SpecialBlocks;
+ SmallVector<CFGBlock *, 8> SpecialBlocks;
for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
@@ -2293,7 +2364,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
// Ignore edges from blocks that can't return.
- if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable)
+ if (neverReturns(*PI) || !PrevBlockInfo->Reachable)
continue;
// Okay, we can reach this block from the entry.
@@ -2310,7 +2381,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
-
FactSet PrevLockset;
getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
@@ -2368,22 +2438,22 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
BE = CurrBlock->end(); BI != BE; ++BI) {
switch (BI->getKind()) {
case CFGElement::Statement: {
- const CFGStmt *CS = cast<CFGStmt>(&*BI);
- LocksetBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+ CFGStmt CS = BI->castAs<CFGStmt>();
+ LocksetBuilder.Visit(const_cast<Stmt*>(CS.getStmt()));
break;
}
// Ignore BaseDtor, MemberDtor, and TemporaryDtor for now.
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor *AD = cast<CFGAutomaticObjDtor>(&*BI);
- CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
- AD->getDestructorDecl(AC.getASTContext()));
+ CFGAutomaticObjDtor AD = BI->castAs<CFGAutomaticObjDtor>();
+ CXXDestructorDecl *DD = const_cast<CXXDestructorDecl *>(
+ AD.getDestructorDecl(AC.getASTContext()));
if (!DD->hasAttrs())
break;
// Create a dummy expression,
- VarDecl *VD = const_cast<VarDecl*>(AD->getVarDecl());
+ VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());
DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue,
- AD->getTriggerStmt()->getLocEnd());
+ AD.getTriggerStmt()->getLocEnd());
LocksetBuilder.handleCall(&DRE, DD);
break;
}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index b2e27cad1f39..730aa6ba212c 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -11,20 +11,22 @@
//
//===----------------------------------------------------------------------===//
-#include <utility>
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallBitVector.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/PackedVector.h"
-#include "llvm/ADT/DenseMap.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PackedVector.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/SaveAndRestore.h"
+#include <utility>
using namespace clang;
@@ -57,7 +59,7 @@ public:
unsigned size() const { return map.size(); }
/// Returns the bit vector index for a given declaration.
- llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const;
+ Optional<unsigned> getValueIndex(const VarDecl *d) const;
};
}
@@ -72,10 +74,10 @@ void DeclToIndex::computeMap(const DeclContext &dc) {
}
}
-llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
+Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
if (I == map.end())
- return llvm::Optional<unsigned>();
+ return None;
return I->second;
}
@@ -130,7 +132,7 @@ public:
Value getValue(const CFGBlock *block, const CFGBlock *dstBlock,
const VarDecl *vd) {
- const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
+ const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
assert(idx.hasValue());
return getValueVector(block)[idx.getValue()];
}
@@ -191,7 +193,7 @@ void CFGBlockValues::resetScratch() {
}
ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
- const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
+ const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
assert(idx.hasValue());
return scratch[idx.getValue()];
}
@@ -202,10 +204,20 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
namespace {
class DataflowWorklist {
+ PostOrderCFGView::iterator PO_I, PO_E;
SmallVector<const CFGBlock *, 20> worklist;
llvm::BitVector enqueuedBlocks;
public:
- DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
+ DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
+ : PO_I(view.begin()), PO_E(view.end()),
+ enqueuedBlocks(cfg.getNumBlockIDs(), true) {
+ // Treat the first block as already analyzed.
+ if (PO_I != PO_E) {
+ assert(*PO_I == &cfg.getEntry());
+ enqueuedBlocks[(*PO_I)->getBlockID()] = false;
+ ++PO_I;
+ }
+ }
void enqueueSuccessors(const CFGBlock *block);
const CFGBlock *dequeue();
@@ -213,7 +225,6 @@ public:
}
void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
- unsigned OldWorklistSize = worklist.size();
for (CFGBlock::const_succ_iterator I = block->succ_begin(),
E = block->succ_end(); I != E; ++I) {
const CFGBlock *Successor = *I;
@@ -222,22 +233,30 @@ void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
worklist.push_back(Successor);
enqueuedBlocks[Successor->getBlockID()] = true;
}
- if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
- return;
-
- // Rotate the newly added blocks to the start of the worklist so that it forms
- // a proper queue when we pop off the end of the worklist.
- std::rotate(worklist.begin(), worklist.begin() + OldWorklistSize,
- worklist.end());
}
const CFGBlock *DataflowWorklist::dequeue() {
- if (worklist.empty())
+ const CFGBlock *B = 0;
+
+ // First dequeue from the worklist. This can represent
+ // updates along backedges that we want propagated as quickly as possible.
+ if (!worklist.empty()) {
+ B = worklist.back();
+ worklist.pop_back();
+ }
+ // Next dequeue from the initial reverse post order. This is the
+ // theoretical ideal in the presence of no back edges.
+ else if (PO_I != PO_E) {
+ B = *PO_I;
+ ++PO_I;
+ }
+ else {
return 0;
- const CFGBlock *b = worklist.back();
- worklist.pop_back();
- enqueuedBlocks[b->getBlockID()] = false;
- return b;
+ }
+
+ assert(enqueuedBlocks[B->getBlockID()] == true);
+ enqueuedBlocks[B->getBlockID()] = false;
+ return B;
}
//------------------------------------------------------------------------====//
@@ -339,6 +358,16 @@ static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
}
void ClassifyRefs::classify(const Expr *E, Class C) {
+ // The result of a ?: could also be an lvalue.
+ E = E->IgnoreParens();
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ const Expr *TrueExpr = CO->getTrueExpr();
+ if (!isa<OpaqueValueExpr>(TrueExpr))
+ classify(TrueExpr, C);
+ classify(CO->getFalseExpr(), C);
+ return;
+ }
+
FindVarResult Var = findVar(E, DC);
if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
Classification[DRE] = std::max(Classification[DRE], C);
@@ -408,13 +437,13 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
AnalysisDeclContext &ac;
const ClassifyRefs &classification;
ObjCNoReturn objCNoRet;
- UninitVariablesHandler *handler;
+ UninitVariablesHandler &handler;
public:
TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
const CFGBlock *block, AnalysisDeclContext &ac,
const ClassifyRefs &classification,
- UninitVariablesHandler *handler)
+ UninitVariablesHandler &handler)
: vals(vals), cfg(cfg), block(block), ac(ac),
classification(classification), objCNoRet(ac.getASTContext()),
handler(handler) {}
@@ -490,8 +519,8 @@ public:
// 'n' is definitely uninitialized for two edges into block 7 (from blocks 2
// and 4), so we report that any time either of those edges is taken (in
// each case when 'b == false'), 'n' is used uninitialized.
- llvm::SmallVector<const CFGBlock*, 32> Queue;
- llvm::SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
+ SmallVector<const CFGBlock*, 32> Queue;
+ SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
Queue.push_back(block);
// Specify that we've already visited all successors of the starting block.
// This has the dual purpose of ensuring we never add it to the queue, and
@@ -571,11 +600,9 @@ public:
}
void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
- if (!handler)
- return;
Value v = vals[vd];
if (isUninitialized(v))
- handler->handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
+ handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
}
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
@@ -636,8 +663,7 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
vals[cast<VarDecl>(dr->getDecl())] = Initialized;
break;
case ClassifyRefs::SelfInit:
- if (handler)
- handler->handleSelfInit(cast<VarDecl>(dr->getDecl()));
+ handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
break;
}
}
@@ -703,7 +729,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
AnalysisDeclContext &ac, CFGBlockValues &vals,
const ClassifyRefs &classification,
llvm::BitVector &wasAnalyzed,
- UninitVariablesHandler *handler = 0) {
+ UninitVariablesHandler &handler) {
wasAnalyzed[block->getBlockID()] = true;
vals.resetScratch();
// Merge in values of predecessor blocks.
@@ -720,13 +746,49 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
TransferFunctions tf(vals, cfg, block, ac, classification, handler);
for (CFGBlock::const_iterator I = block->begin(), E = block->end();
I != E; ++I) {
- if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
+ if (Optional<CFGStmt> cs = I->getAs<CFGStmt>())
tf.Visit(const_cast<Stmt*>(cs->getStmt()));
- }
}
return vals.updateValueVectorWithScratch(block);
}
+/// PruneBlocksHandler is a special UninitVariablesHandler that is used
+/// to detect when a CFGBlock has any *potential* use of an uninitialized
+/// variable. It is mainly used to prune out work during the final
+/// reporting pass.
+namespace {
+struct PruneBlocksHandler : public UninitVariablesHandler {
+ PruneBlocksHandler(unsigned numBlocks)
+ : hadUse(numBlocks, false), hadAnyUse(false),
+ currentBlock(0) {}
+
+ virtual ~PruneBlocksHandler() {}
+
+ /// Records if a CFGBlock had a potential use of an uninitialized variable.
+ llvm::BitVector hadUse;
+
+ /// Records if any CFGBlock had a potential use of an uninitialized variable.
+ bool hadAnyUse;
+
+ /// The current block to scribble use information.
+ unsigned currentBlock;
+
+ virtual void handleUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) {
+ hadUse[currentBlock] = true;
+ hadAnyUse = true;
+ }
+
+ /// 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) {
+ hadUse[currentBlock] = true;
+ hadAnyUse = true;
+ }
+};
+}
+
void clang::runUninitializedVariablesAnalysis(
const DeclContext &dc,
const CFG &cfg,
@@ -753,27 +815,33 @@ void clang::runUninitializedVariablesAnalysis(
}
// Proceed with the workist.
- DataflowWorklist worklist(cfg);
+ DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
worklist.enqueueSuccessors(&cfg.getEntry());
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
wasAnalyzed[cfg.getEntry().getBlockID()] = true;
+ PruneBlocksHandler PBH(cfg.getNumBlockIDs());
while (const CFGBlock *block = worklist.dequeue()) {
+ PBH.currentBlock = block->getBlockID();
+
// Did the block change?
bool changed = runOnBlock(block, cfg, ac, vals,
- classification, wasAnalyzed);
+ classification, wasAnalyzed, PBH);
++stats.NumBlockVisits;
if (changed || !previouslyVisited[block->getBlockID()])
worklist.enqueueSuccessors(block);
previouslyVisited[block->getBlockID()] = true;
}
-
- // Run through the blocks one more time, and report uninitialized variabes.
+
+ if (!PBH.hadAnyUse)
+ return;
+
+ // Run through the blocks one more time, and report uninitialized variables.
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
const CFGBlock *block = *BI;
- if (wasAnalyzed[block->getBlockID()]) {
- runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, &handler);
+ if (PBH.hadUse[block->getBlockID()]) {
+ runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
++stats.NumBlockVisits;
}
}
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index c78a2921d4e5..242c204d6d80 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -13,8 +13,8 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 73e693befa4f..34111691c82e 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -2,8 +2,7 @@ set(LLVM_LINK_COMPONENTS mc)
add_clang_library(clangBasic
Builtins.cpp
- ConvertUTF.c
- ConvertUTFWrapper.cpp
+ CharInfo.cpp
Diagnostic.cpp
DiagnosticIDs.cpp
FileManager.cpp
@@ -12,6 +11,8 @@ add_clang_library(clangBasic
LangOptions.cpp
Module.cpp
ObjCRuntime.cpp
+ OpenMPKinds.cpp
+ OperatorPrecedence.cpp
SourceLocation.cpp
SourceManager.cpp
TargetInfo.cpp
@@ -28,9 +29,25 @@ if( NOT IS_SYMLINK "${CLANG_SOURCE_DIR}" ) # See PR 8437
find_package(Subversion)
endif()
if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn")
- Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG)
+ # 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)
+
+ # Mark the generated header as being generated.
+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)
+
+ # Tell Version.cpp that it needs to build with -DHAVE_SVN_VERSION_INC.
set_source_files_properties(Version.cpp
- PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"")
+ PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC")
+
endif()
add_dependencies(clangBasic
@@ -49,3 +66,8 @@ add_dependencies(clangBasic
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/CharInfo.cpp b/lib/Basic/CharInfo.cpp
new file mode 100644
index 000000000000..32b3277c927b
--- /dev/null
+++ b/lib/Basic/CharInfo.cpp
@@ -0,0 +1,81 @@
+//===--- CharInfo.cpp - Static Data for Classifying ASCII Characters ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/CharInfo.h"
+
+using namespace clang::charinfo;
+
+// Statically initialize CharInfo table based on ASCII character set
+// Reference: FreeBSD 7.2 /usr/share/misc/ascii
+const uint16_t clang::charinfo::InfoTable[256] = {
+ // 0 NUL 1 SOH 2 STX 3 ETX
+ // 4 EOT 5 ENQ 6 ACK 7 BEL
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+ // 8 BS 9 HT 10 NL 11 VT
+ //12 NP 13 CR 14 SO 15 SI
+ 0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS,
+ CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 ,
+ //16 DLE 17 DC1 18 DC2 19 DC3
+ //20 DC4 21 NAK 22 SYN 23 ETB
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+ //24 CAN 25 EM 26 SUB 27 ESC
+ //28 FS 29 GS 30 RS 31 US
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+ //32 SP 33 ! 34 " 35 #
+ //36 $ 37 % 38 & 39 '
+ CHAR_SPACE , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
+ CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
+ //40 ( 41 ) 42 * 43 +
+ //44 , 45 - 46 . 47 /
+ CHAR_PUNCT , CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL ,
+ //48 0 49 1 50 2 51 3
+ //52 4 53 5 54 6 55 7
+ CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT ,
+ CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT ,
+ //56 8 57 9 58 : 59 ;
+ //60 < 61 = 62 > 63 ?
+ CHAR_DIGIT , CHAR_DIGIT , CHAR_RAWDEL , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
+ //64 @ 65 A 66 B 67 C
+ //68 D 69 E 70 F 71 G
+ CHAR_PUNCT , CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER ,
+ CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER , CHAR_UPPER ,
+ //72 H 73 I 74 J 75 K
+ //76 L 77 M 78 N 79 O
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ //80 P 81 Q 82 R 83 S
+ //84 T 85 U 86 V 87 W
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ //88 X 89 Y 90 Z 91 [
+ //92 \ 93 ] 94 ^ 95 _
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_RAWDEL ,
+ CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER ,
+ //96 ` 97 a 98 b 99 c
+ //100 d 101 e 102 f 103 g
+ CHAR_PUNCT , CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER ,
+ CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER , CHAR_LOWER ,
+ //104 h 105 i 106 j 107 k
+ //108 l 109 m 110 n 111 o
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ //112 p 113 q 114 r 115 s
+ //116 t 117 u 118 v 119 w
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ //120 x 121 y 122 z 123 {
+ //124 | 125 } 126 ~ 127 DEL
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0
+};
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
deleted file mode 100644
index d16965ddd872..000000000000
--- a/lib/Basic/ConvertUTF.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------=*/
-/*
- * Copyright 2001-2004 Unicode, Inc.
- *
- * Disclaimer
- *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
- Conversions between UTF32, UTF-16, and UTF-8. Source code file.
- Author: Mark E. Davis, 1994.
- Rev History: Rick McGowan, fixes & updates May 2001.
- Sept 2001: fixed const & error conditions per
- mods suggested by S. Parent & A. Lillich.
- June 2002: Tim Dodd added detection and handling of incomplete
- source sequences, enhanced error detection, added casts
- to eliminate compiler warnings.
- July 2003: slight mods to back out aggressive FFFE detection.
- Jan 2004: updated switches in from-UTF8 conversions.
- Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
-
- See the header file "ConvertUTF.h" for complete documentation.
-
------------------------------------------------------------------------- */
-
-
-#include "clang/Basic/ConvertUTF.h"
-#ifdef CVTUTF_DEBUG
-#include <stdio.h>
-#endif
-
-static const int halfShift = 10; /* used for shifting by 10 bits */
-
-static const UTF32 halfBase = 0x0010000UL;
-static const UTF32 halfMask = 0x3FFUL;
-
-#define UNI_SUR_HIGH_START (UTF32)0xD800
-#define UNI_SUR_HIGH_END (UTF32)0xDBFF
-#define UNI_SUR_LOW_START (UTF32)0xDC00
-#define UNI_SUR_LOW_END (UTF32)0xDFFF
-#define false 0
-#define true 1
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Index into the table below with the first byte of a UTF-8 sequence to
- * get the number of trailing bytes that are supposed to follow it.
- * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
- * left as-is for anyone who may want to do such conversion, which was
- * allowed in earlier algorithms.
- */
-static const char trailingBytesForUTF8[256] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
-};
-
-/*
- * Magic values subtracted from a buffer value during UTF8 conversion.
- * This table contains as many values as there might be trailing bytes
- * in a UTF-8 sequence.
- */
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
- 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
-
-/*
- * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
- * into the first byte, depending on how many bytes follow. There are
- * as many entries in this table as there are UTF-8 sequence types.
- * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
- * for *legal* UTF-8 will be 4 or fewer bytes total.
- */
-static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-/* --------------------------------------------------------------------- */
-
-/* The interface converts a whole buffer to avoid function-call overhead.
- * Constants have been gathered. Loops & conditionals have been removed as
- * much as possible for efficiency, in favor of drop-through switches.
- * (See "Note A" at the bottom of the file for equivalent code.)
- * If your compiler supports it, the "isLegalUTF8" call can be turned
- * into an inline function.
- */
-
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF32* source = *sourceStart;
- UTF16* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- if (target >= targetEnd) {
- result = targetExhausted; break;
- }
- ch = *source++;
- if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
- /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = (UTF16)ch; /* normal case */
- }
- } else if (ch > UNI_MAX_LEGAL_UTF32) {
- if (flags == strictConversion) {
- result = sourceIllegal;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- /* target is a character in range 0xFFFF - 0x10FFFF. */
- if (target + 1 >= targetEnd) {
- --source; /* Back up source pointer! */
- result = targetExhausted; break;
- }
- ch -= halfBase;
- *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
- *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF16* source = *sourceStart;
- UTF32* target = *targetStart;
- UTF32 ch, ch2;
- while (source < sourceEnd) {
- const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
- ch = *source++;
- /* If we have a surrogate pair, convert to UTF32 first. */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
- /* If the 16 bits following the high surrogate are in the source buffer... */
- if (source < sourceEnd) {
- ch2 = *source;
- /* If it's a low surrogate, convert to UTF32. */
- if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
- ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
- + (ch2 - UNI_SUR_LOW_START) + halfBase;
- ++source;
- } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- } else { /* We don't have the 16 bits following the high surrogate. */
- --source; /* return to the high surrogate */
- result = sourceExhausted;
- break;
- }
- } else if (flags == strictConversion) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- if (target >= targetEnd) {
- source = oldSource; /* Back up source pointer! */
- result = targetExhausted; break;
- }
- *target++ = ch;
- }
- *sourceStart = source;
- *targetStart = target;
-#ifdef CVTUTF_DEBUG
-if (result == sourceIllegal) {
- fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
- fflush(stderr);
-}
-#endif
- return result;
-}
-ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF16* source = *sourceStart;
- UTF8* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- unsigned short bytesToWrite = 0;
- const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
- const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
- ch = *source++;
- /* If we have a surrogate pair, convert to UTF32 first. */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
- /* If the 16 bits following the high surrogate are in the source buffer... */
- if (source < sourceEnd) {
- UTF32 ch2 = *source;
- /* If it's a low surrogate, convert to UTF32. */
- if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
- ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
- + (ch2 - UNI_SUR_LOW_START) + halfBase;
- ++source;
- } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- } else { /* We don't have the 16 bits following the high surrogate. */
- --source; /* return to the high surrogate */
- result = sourceExhausted;
- break;
- }
- } else if (flags == strictConversion) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- /* Figure out how many bytes the result will require */
- if (ch < (UTF32)0x80) { bytesToWrite = 1;
- } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
- } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
- } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
- } else { bytesToWrite = 3;
- ch = UNI_REPLACEMENT_CHAR;
- }
-
- target += bytesToWrite;
- if (target > targetEnd) {
- source = oldSource; /* Back up source pointer! */
- target -= bytesToWrite; result = targetExhausted; break;
- }
- switch (bytesToWrite) { /* note: everything falls through. */
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
- }
- target += bytesToWrite;
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF32* source = *sourceStart;
- UTF8* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- unsigned short bytesToWrite = 0;
- const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
- ch = *source++;
- if (flags == strictConversion ) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- /*
- * Figure out how many bytes the result will require. Turn any
- * illegally large UTF32 things (> Plane 17) into replacement chars.
- */
- if (ch < (UTF32)0x80) { bytesToWrite = 1;
- } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
- } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
- } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
- } else { bytesToWrite = 3;
- ch = UNI_REPLACEMENT_CHAR;
- result = sourceIllegal;
- }
-
- target += bytesToWrite;
- if (target > targetEnd) {
- --source; /* Back up source pointer! */
- target -= bytesToWrite; result = targetExhausted; break;
- }
- switch (bytesToWrite) { /* note: everything falls through. */
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
- }
- target += bytesToWrite;
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Utility routine to tell whether a sequence of bytes is legal UTF-8.
- * This must be called with the length pre-determined by the first byte.
- * If not calling this from ConvertUTF8to*, then the length can be set by:
- * length = trailingBytesForUTF8[*source]+1;
- * and the sequence is illegal right away if there aren't that many bytes
- * available.
- * If presented with a length > 4, this returns false. The Unicode
- * definition of UTF-8 goes up to 4-byte sequences.
- */
-
-static Boolean isLegalUTF8(const UTF8 *source, int length) {
- UTF8 a;
- const UTF8 *srcptr = source+length;
- switch (length) {
- default: return false;
- /* Everything else falls through when "true"... */
- case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
-
- switch (*source) {
- /* no fall-through in this inner switch */
- case 0xE0: if (a < 0xA0) return false; break;
- case 0xED: if (a > 0x9F) return false; break;
- case 0xF0: if (a < 0x90) return false; break;
- case 0xF4: if (a > 0x8F) return false; break;
- default: if (a < 0x80) return false;
- }
-
- case 1: if (*source >= 0x80 && *source < 0xC2) return false;
- }
- if (*source > 0xF4) return false;
- return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 sequence is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
- int length = trailingBytesForUTF8[*source]+1;
- if (length > sourceEnd - source) {
- return false;
- }
- return isLegalUTF8(source, length);
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return the total number of bytes in a codepoint
- * represented in UTF-8, given the value of the first byte.
- */
-unsigned getNumBytesForUTF8(UTF8 first) {
- return trailingBytesForUTF8[first] + 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 string is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) {
- while (*source != sourceEnd) {
- int length = trailingBytesForUTF8[**source] + 1;
- if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
- return false;
- *source += length;
- }
- return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF16* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (extraBytesToRead >= sourceEnd - source) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (!isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
- case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = (UTF16)ch; /* normal case */
- }
- } else if (ch > UNI_MAX_UTF16) {
- if (flags == strictConversion) {
- result = sourceIllegal;
- source -= (extraBytesToRead+1); /* return to the start */
- break; /* Bail out; shouldn't continue */
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- /* target is a character in range 0xFFFF - 0x10FFFF. */
- if (target + 1 >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up source pointer! */
- result = targetExhausted; break;
- }
- ch -= halfBase;
- *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
- *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF32* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (extraBytesToRead >= sourceEnd - source) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (!isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6;
- case 4: ch += *source++; ch <<= 6;
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up the source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_LEGAL_UTF32) {
- /*
- * UTF-16 surrogate values are illegal in UTF-32, and anything
- * over Plane 17 (> 0x10FFFF) is illegal.
- */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = ch;
- }
- } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
- result = sourceIllegal;
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* ---------------------------------------------------------------------
-
- Note A.
- The fall-through switches in UTF-8 reading code save a
- temp variable, some decrements & conditionals. The switches
- are equivalent to the following loop:
- {
- int tmpBytesToRead = extraBytesToRead+1;
- do {
- ch += *source++;
- --tmpBytesToRead;
- if (tmpBytesToRead) ch <<= 6;
- } while (tmpBytesToRead > 0);
- }
- In UTF-8 writing code, the switches on "bytesToWrite" are
- similarly unrolled loops.
-
- --------------------------------------------------------------------- */
diff --git a/lib/Basic/ConvertUTFWrapper.cpp b/lib/Basic/ConvertUTFWrapper.cpp
deleted file mode 100644
index 6be3828d2868..000000000000
--- a/lib/Basic/ConvertUTFWrapper.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Basic/ConvertUTF.h"
-#include "clang/Basic/LLVM.h"
-
-namespace clang {
-
-bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
- char *&ResultPtr, const UTF8 *&ErrorPtr) {
- assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
- ConversionResult result = conversionOK;
- // Copy the character span over.
- if (WideCharWidth == 1) {
- const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.begin());
- if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.end()))) {
- result = sourceIllegal;
- ErrorPtr = Pos;
- } else {
- memcpy(ResultPtr, Source.data(), Source.size());
- ResultPtr += Source.size();
- }
- } else if (WideCharWidth == 2) {
- const UTF8 *sourceStart = (const UTF8*)Source.data();
- // FIXME: Make the type of the result buffer correct instead of
- // using reinterpret_cast.
- UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
- ConversionFlags flags = strictConversion;
- result = ConvertUTF8toUTF16(
- &sourceStart, sourceStart + Source.size(),
- &targetStart, targetStart + 2*Source.size(), flags);
- if (result == conversionOK)
- ResultPtr = reinterpret_cast<char*>(targetStart);
- else
- ErrorPtr = sourceStart;
- } else if (WideCharWidth == 4) {
- const UTF8 *sourceStart = (const UTF8*)Source.data();
- // FIXME: Make the type of the result buffer correct instead of
- // using reinterpret_cast.
- UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
- ConversionFlags flags = strictConversion;
- result = ConvertUTF8toUTF32(
- &sourceStart, sourceStart + Source.size(),
- &targetStart, targetStart + 4*Source.size(), flags);
- if (result == conversionOK)
- ResultPtr = reinterpret_cast<char*>(targetStart);
- else
- ErrorPtr = sourceStart;
- }
- assert((result != targetExhausted)
- && "ConvertUTF8toUTFXX exhausted target buffer");
- return result == conversionOK;
-}
-
-bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
- const UTF32 *SourceStart = &Source;
- const UTF32 *SourceEnd = SourceStart + 1;
- UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
- UTF8 *TargetEnd = TargetStart + 4;
- ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
- &TargetStart, TargetEnd,
- strictConversion);
- if (CR != conversionOK)
- return false;
-
- ResultPtr = reinterpret_cast<char*>(TargetStart);
- return true;
-}
-
-} // end namespace clang
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 854c4c56bb7f..842bacb9a5d0 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CrashRecoveryContext.h"
-#include <cctype>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -97,6 +97,7 @@ bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
void DiagnosticsEngine::Reset() {
ErrorOccurred = false;
+ UncompilableErrorOccurred = false;
FatalErrorOccurred = false;
UnrecoverableErrorOccurred = false;
@@ -107,11 +108,7 @@ void DiagnosticsEngine::Reset() {
TrapNumUnrecoverableErrorsOccurred = 0;
CurDiagID = ~0U;
- // Set LastDiagLevel to an "unset" state. If we set it to 'Ignored', notes
- // using a DiagnosticsEngine associated to a translation unit that follow
- // diagnostics from a DiagnosticsEngine associated to anoter t.u. will not be
- // displayed.
- LastDiagLevel = (DiagnosticIDs::Level)-1;
+ LastDiagLevel = DiagnosticIDs::Ignored;
DelayedDiagID = 0;
// Clear state related to #pragma diagnostic.
@@ -237,7 +234,7 @@ bool DiagnosticsEngine::setDiagnosticGroupMapping(
StringRef Group, diag::Mapping Map, SourceLocation Loc)
{
// Get the diagnostics in this group.
- llvm::SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
return true;
@@ -277,7 +274,7 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
// potentially downgrade anything already mapped to be a warning.
// Get the diagnostics in this group.
- llvm::SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
return true;
@@ -324,7 +321,7 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
// potentially downgrade anything already mapped to be an error.
// Get the diagnostics in this group.
- llvm::SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
return true;
@@ -345,7 +342,7 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
void DiagnosticsEngine::setMappingToAllDiagnostics(diag::Mapping Map,
SourceLocation Loc) {
// Get all the diagnostics.
- llvm::SmallVector<diag::kind, 64> AllDiags;
+ SmallVector<diag::kind, 64> AllDiags;
Diags->getAllDiagnostics(AllDiags);
// Set the mapping.
@@ -460,8 +457,8 @@ static const char *ScanFormat(const char *I, const char *E, char Target) {
// Escaped characters get implicitly skipped here.
// Format specifier.
- if (!isdigit(*I) && !ispunct(*I)) {
- for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ;
+ if (!isDigit(*I) && !isPunctuation(*I)) {
+ for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
if (I == E) break;
if (*I == '{')
Depth++;
@@ -685,7 +682,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
OutStr.append(DiagStr, StrEnd);
DiagStr = StrEnd;
continue;
- } else if (ispunct(DiagStr[1])) {
+ } else if (isPunctuation(DiagStr[1])) {
OutStr.push_back(DiagStr[1]); // %% -> %.
DiagStr += 2;
continue;
@@ -703,7 +700,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
unsigned ModifierLen = 0, ArgumentLen = 0;
// Check to see if we have a modifier. If so eat it.
- if (!isdigit(DiagStr[0])) {
+ if (!isDigit(DiagStr[0])) {
Modifier = DiagStr;
while (DiagStr[0] == '-' ||
(DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
@@ -722,22 +719,40 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
}
- assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
+ assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
unsigned ArgNo = *DiagStr++ - '0';
// Only used for type diffing.
unsigned ArgNo2 = ArgNo;
DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
- if (Kind == DiagnosticsEngine::ak_qualtype &&
- ModifierIs(Modifier, ModifierLen, "diff")) {
- Kind = DiagnosticsEngine::ak_qualtype_pair;
- assert(*DiagStr == ',' && isdigit(*(DiagStr + 1)) &&
+ if (ModifierIs(Modifier, ModifierLen, "diff")) {
+ assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
"Invalid format for diff modifier");
++DiagStr; // Comma.
ArgNo2 = *DiagStr++ - '0';
- assert(getArgKind(ArgNo2) == DiagnosticsEngine::ak_qualtype &&
- "Second value of type diff must be a qualtype");
+ DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
+ if (Kind == DiagnosticsEngine::ak_qualtype &&
+ Kind2 == DiagnosticsEngine::ak_qualtype)
+ Kind = DiagnosticsEngine::ak_qualtype_pair;
+ else {
+ // %diff only supports QualTypes. For other kinds of arguments,
+ // use the default printing. For example, if the modifier is:
+ // "%diff{compare $ to $|other text}1,2"
+ // treat it as:
+ // "compare %1 to %2"
+ const char *Pipe = ScanFormat(Argument, Argument + ArgumentLen, '|');
+ const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
+ const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
+ const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
+ const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
+ FormatDiagnostic(Argument, FirstDollar, OutStr);
+ FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
+ FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
+ FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
+ FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
+ continue;
+ }
}
switch (Kind) {
@@ -940,11 +955,10 @@ StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
StringRef Message, FullSourceLoc Loc,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Fixits)
- : ID(ID), Level(Level), Loc(Loc), Message(Message)
+ ArrayRef<FixItHint> FixIts)
+ : ID(ID), Level(Level), Loc(Loc), Message(Message),
+ Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
{
- this->Ranges.assign(Ranges.begin(), Ranges.end());
- this->FixIts.assign(FixIts.begin(), FixIts.end());
}
StoredDiagnostic::~StoredDiagnostic() { }
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index ed976436e284..353af4bd6df1 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -17,7 +17,6 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
-
#include <map>
using namespace clang;
@@ -108,16 +107,51 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
}
#endif
- // Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { static_cast<unsigned short>(DiagID),
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ // Out of bounds diag. Can't be in the table.
+ using namespace diag;
+ if (DiagID >= DIAG_UPPER_LIMIT)
+ return 0;
- const StaticDiagInfoRec *Found =
- std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
- if (Found == StaticDiagInfo + StaticDiagInfoSize ||
- Found->DiagID != DiagID)
+ // Compute the index of the requested diagnostic in the static table.
+ // 1. Add the number of diagnostics in each category preceeding 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
+ // the offset of the diagnostic in the category.
+ // This is cheaper than a binary search on the table as it doesn't touch
+ // memory at all.
+ unsigned Offset = 0;
+ unsigned ID = DiagID;
+#define DIAG_START_COMMON 0 // Sentinel value.
+#define CATEGORY(NAME, PREV) \
+ if (DiagID > DIAG_START_##NAME) { \
+ Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
+ ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
+ }
+CATEGORY(DRIVER, COMMON)
+CATEGORY(FRONTEND, DRIVER)
+CATEGORY(SERIALIZATION, FRONTEND)
+CATEGORY(LEX, SERIALIZATION)
+CATEGORY(PARSE, LEX)
+CATEGORY(AST, PARSE)
+CATEGORY(COMMENT, AST)
+CATEGORY(SEMA, COMMENT)
+CATEGORY(ANALYSIS, SEMA)
+#undef CATEGORY
+#undef DIAG_START_COMMON
+
+ // Avoid out of bounds reads.
+ if (ID + Offset >= StaticDiagInfoSize)
return 0;
+ assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
+
+ const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
+ // If the diag id doesn't match we found a different diag, abort. This can
+ // 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 Found;
}
@@ -247,14 +281,14 @@ namespace clang {
/// diagnostic.
StringRef getDescription(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
+ "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() &&
- "Invalid diagnosic ID");
+ "Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
@@ -291,7 +325,7 @@ DiagnosticIDs::~DiagnosticIDs() {
}
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
-/// and level. If this is the first request for this diagnosic, it is
+/// 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)
@@ -512,9 +546,8 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
}
void DiagnosticIDs::getDiagnosticsInGroup(
- const WarningOption *Group,
- llvm::SmallVectorImpl<diag::kind> &Diags) const
-{
+ const WarningOption *Group,
+ SmallVectorImpl<diag::kind> &Diags) const {
// Add the members of the option diagnostic set.
if (const short *Member = Group->Members) {
for (; *Member != -1; ++Member)
@@ -529,9 +562,8 @@ void DiagnosticIDs::getDiagnosticsInGroup(
}
bool DiagnosticIDs::getDiagnosticsInGroup(
- StringRef Group,
- llvm::SmallVectorImpl<diag::kind> &Diags) const
-{
+ StringRef Group,
+ SmallVectorImpl<diag::kind> &Diags) const {
WarningOption Key = { Group.size(), Group.data(), 0, 0 };
const WarningOption *Found =
std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
@@ -545,7 +577,7 @@ bool DiagnosticIDs::getDiagnosticsInGroup(
}
void DiagnosticIDs::getAllDiagnostics(
- llvm::SmallVectorImpl<diag::kind> &Diags) const {
+ SmallVectorImpl<diag::kind> &Diags) const {
for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
Diags.push_back(StaticDiagInfo[i].DiagID);
}
@@ -629,6 +661,10 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
if (isUnrecoverable(DiagID))
Diag.UnrecoverableErrorOccurred = true;
+ // Warnings which have been upgraded to errors do not prevent compilation.
+ if (isDefaultMappingAsError(DiagID))
+ Diag.UncompilableErrorOccurred = true;
+
Diag.ErrorOccurred = true;
if (Diag.Client->IncludeInDiagnosticCounts()) {
++Diag.NumErrors;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index a816969b9144..9cc59027ab6e 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -20,12 +20,12 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Config/llvm-config.h"
#include <map>
#include <set>
#include <string>
@@ -40,6 +40,9 @@
#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.
@@ -311,7 +314,7 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// Check to see if the directory exists.
struct stat StatBuf;
- if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
+ if (getStatValue(InterndDirName, StatBuf, false, 0/*directory lookup*/)) {
// There's no real directory at the given path.
if (!CacheFailure)
SeenDirEntries.erase(DirName);
@@ -376,7 +379,8 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// Nope, there isn't. Check to see if the file exists.
int FileDescriptor = -1;
struct stat StatBuf;
- if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
+ if (getStatValue(InterndFileName, StatBuf, true,
+ openFile ? &FileDescriptor : 0)) {
// There's no real file at the given path.
if (!CacheFailure)
SeenFileEntries.erase(Filename);
@@ -444,14 +448,9 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
"The directory of a virtual file should already be in the cache.");
// Check to see if the file exists. If so, drop the virtual file
- int FileDescriptor = -1;
struct stat StatBuf;
const char *InterndFileName = NamedFileEnt.getKeyData();
- if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
- // If the stat process opened the file, close it to avoid a FD leak.
- if (FileDescriptor != -1)
- close(FileDescriptor);
-
+ if (getStatValue(InterndFileName, StatBuf, true, 0) == 0) {
StatBuf.st_size = Size;
StatBuf.st_mtime = ModificationTime;
UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf);
@@ -564,18 +563,18 @@ 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, struct stat &StatBuf,
- int *FileDescriptor) {
+ bool isFile, int *FileDescriptor) {
// FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
// absolute!
if (FileSystemOpts.WorkingDir.empty())
- return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
+ return FileSystemStatCache::get(Path, StatBuf, isFile, FileDescriptor,
StatCache.get());
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
- StatCache.get());
+ return FileSystemStatCache::get(FilePath.c_str(), StatBuf,
+ isFile, FileDescriptor, StatCache.get());
}
bool FileManager::getNoncachedStatValue(StringRef Path,
@@ -624,6 +623,29 @@ void FileManager::modifyFileEntry(FileEntry *File,
File->ModTime = ModificationTime;
}
+StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
+ // FIXME: use llvm::sys::fs::canonical() when it gets implemented
+#ifdef LLVM_ON_UNIX
+ llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
+ = CanonicalDirNames.find(Dir);
+ if (Known != CanonicalDirNames.end())
+ return Known->second;
+
+ StringRef CanonicalName(Dir->getName());
+ char CanonicalNameBuf[PATH_MAX];
+ if (realpath(Dir->getName(), CanonicalNameBuf)) {
+ unsigned Len = strlen(CanonicalNameBuf);
+ char *Mem = static_cast<char *>(CanonicalNameStorage.Allocate(Len, 1));
+ memcpy(Mem, CanonicalNameBuf, Len);
+ CanonicalName = StringRef(Mem, Len);
+ }
+
+ CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
+ return CanonicalName;
+#else
+ return StringRef(Dir->getName());
+#endif
+}
void FileManager::PrintStats() const {
llvm::errs() << "\n*** File Manager Stats:\n";
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
index 875d397a1dae..38c46299018c 100644
--- a/lib/Basic/FileSystemStatCache.cpp
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -34,21 +34,23 @@ void FileSystemStatCache::anchor() { }
/// path, using the cache to accelerate it if possible. This returns true if
/// the path does not exist or false if it exists.
///
-/// If FileDescriptor is non-null, then this lookup should only return success
-/// for files (not directories). If it is null this lookup should only return
+/// If isFile is true, then this lookup should only return success for files
+/// (not directories). If it is false this lookup should only return
/// success for directories (not files). On a successful file lookup, the
/// 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, struct stat &StatBuf,
- int *FileDescriptor, FileSystemStatCache *Cache) {
+ bool isFile, int *FileDescriptor,
+ FileSystemStatCache *Cache) {
LookupResult R;
- bool isForDir = FileDescriptor == 0;
+ bool isForDir = !isFile;
// If we have a cache, use it to resolve the stat query.
if (Cache)
- R = Cache->getStat(Path, StatBuf, FileDescriptor);
- else if (isForDir) {
- // If this is a directory and we have no cache, just go to the file system.
+ R = Cache->getStat(Path, StatBuf, isFile, FileDescriptor);
+ else if (isForDir || !FileDescriptor) {
+ // If this is a directory or a file descriptor is not needed and we have
+ // no cache, just go to the file system.
R = ::stat(Path, &StatBuf) != 0 ? CacheMissing : CacheExists;
} else {
// Otherwise, we have to go to the filesystem. We can always just use
@@ -104,8 +106,8 @@ bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
MemorizeStatCalls::LookupResult
MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
+ bool isFile, int *FileDescriptor) {
+ LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor);
// 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 1965bf99338b..429d9d8cb21e 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -13,13 +13,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
@@ -82,7 +82,7 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
// Add the '_experimental_modules_import' contextual keyword.
- get("__experimental_modules_import").setModulesImport(true);
+ get("import").setModulesImport(true);
}
//===----------------------------------------------------------------------===//
@@ -94,7 +94,7 @@ namespace {
enum {
KEYC99 = 0x1,
KEYCXX = 0x2,
- KEYCXX0X = 0x4,
+ KEYCXX11 = 0x4,
KEYGNU = 0x8,
KEYMS = 0x10,
BOOLSUPPORT = 0x20,
@@ -124,7 +124,7 @@ static void AddKeyword(StringRef Keyword,
unsigned AddResult = 0;
if (Flags == KEYALL) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
- else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
+ else if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1;
else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
@@ -138,7 +138,7 @@ static void AddKeyword(StringRef Keyword,
// We treat bridge casts as objective-C keywords so we can warn on them
// in non-arc mode.
else if (LangOpts.ObjC2 && (Flags & KEYARC)) AddResult = 2;
- else if (LangOpts.CPlusPlus && (Flags & KEYCXX0X)) AddResult = 3;
+ else if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) AddResult = 3;
// Don't add this keyword under MicrosoftMode.
if (LangOpts.MicrosoftMode && (Flags & KEYNOMS))
@@ -404,9 +404,8 @@ std::string Selector::getAsString() const {
/// given "word", which is assumed to end in a lowercase letter.
static bool startsWithWord(StringRef name, StringRef word) {
if (name.size() < word.size()) return false;
- return ((name.size() == word.size() ||
- !islower(name[word.size()]))
- && name.startswith(word));
+ return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
+ name.startswith(word));
}
ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
@@ -472,7 +471,7 @@ SelectorTable::constructSetterName(IdentifierTable &Idents,
SmallString<100> SelectorName;
SelectorName = "set";
SelectorName += Name->getName();
- SelectorName[3] = toupper(SelectorName[3]);
+ SelectorName[3] = toUppercase(SelectorName[3]);
IdentifierInfo *SetterName = &Idents.get(SelectorName);
return SelTable.getUnarySelector(SetterName);
}
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index 991992a477e4..f8714b2389cb 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -14,10 +14,14 @@
using namespace clang;
+const SanitizerOptions SanitizerOptions::Disabled = {};
+
LangOptions::LangOptions() {
#define LANGOPT(Name, Bits, Default, Description) Name = Default;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) set##Name(Default);
#include "clang/Basic/LangOptions.def"
+
+ Sanitize = SanitizerOptions::Disabled;
}
void LangOptions::resetNonModularOptions() {
@@ -26,7 +30,11 @@ void LangOptions::resetNonModularOptions() {
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Name = Default;
#include "clang/Basic/LangOptions.def"
-
+
+ // FIXME: This should not be reset; modules can be different with different
+ // sanitizer options (this affects __has_feature(address_sanitizer) etc).
+ Sanitize = SanitizerOptions::Disabled;
+
CurrentModule.clear();
}
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 76c7f8b364eb..13518cde6642 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -1,4 +1,4 @@
-//===--- Module.h - Describe a module ---------------------------*- C++ -*-===//
+//===--- Module.cpp - Describe a module -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,10 +15,11 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
@@ -27,7 +28,8 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
InferSubmodules(false), InferExplicitSubmodules(false),
- InferExportWildcard(false), NameVisibility(Hidden)
+ InferExportWildcard(false), ConfigMacrosExhaustive(false),
+ NameVisibility(Hidden)
{
if (Parent) {
if (!Parent->isAvailable())
@@ -45,7 +47,6 @@ Module::~Module() {
I != IEnd; ++I) {
delete *I;
}
-
}
/// \brief Determine whether a translation unit built using the current
@@ -56,7 +57,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
.Case("altivec", LangOpts.AltiVec)
.Case("blocks", LangOpts.Blocks)
.Case("cplusplus", LangOpts.CPlusPlus)
- .Case("cplusplus11", LangOpts.CPlusPlus0x)
+ .Case("cplusplus11", LangOpts.CPlusPlus11)
.Case("objc", LangOpts.ObjC1)
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
.Case("opencl", LangOpts.OpenCL)
@@ -103,15 +104,15 @@ const Module *Module::getTopLevelModule() const {
}
std::string Module::getFullModuleName() const {
- llvm::SmallVector<StringRef, 2> Names;
+ SmallVector<StringRef, 2> Names;
// Build up the set of module names (from innermost to outermost).
for (const Module *M = this; M; M = M->Parent)
Names.push_back(M->Name);
std::string Result;
- for (llvm::SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
- IEnd = Names.rend();
+ for (SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
+ IEnd = Names.rend();
I != IEnd; ++I) {
if (!Result.empty())
Result += '.';
@@ -129,6 +130,19 @@ const DirectoryEntry *Module::getUmbrellaDir() const {
return Umbrella.dyn_cast<const DirectoryEntry *>();
}
+ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) {
+ if (!TopHeaderNames.empty()) {
+ for (std::vector<std::string>::iterator
+ I = TopHeaderNames.begin(), E = TopHeaderNames.end(); I != E; ++I) {
+ if (const FileEntry *FE = FileMgr.getFile(*I))
+ TopHeaders.insert(FE);
+ }
+ TopHeaderNames.clear();
+ }
+
+ return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end());
+}
+
void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts,
const TargetInfo &Target) {
Requires.push_back(Feature);
@@ -140,7 +154,7 @@ void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts,
if (!IsAvailable)
return;
- llvm::SmallVector<Module *, 2> Stack;
+ SmallVector<Module *, 2> Stack;
Stack.push_back(this);
while (!Stack.empty()) {
Module *Current = Stack.back();
@@ -167,7 +181,7 @@ Module *Module::findSubmodule(StringRef Name) const {
return SubModules[Pos->getValue()];
}
-static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
+static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
if (I)
OS << ".";
@@ -175,7 +189,60 @@ static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
}
}
-void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
+void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
+ bool AnyWildcard = false;
+ bool UnrestrictedWildcard = false;
+ SmallVector<Module *, 4> WildcardRestrictions;
+ for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
+ Module *Mod = Exports[I].getPointer();
+ if (!Exports[I].getInt()) {
+ // Export a named module directly; no wildcards involved.
+ Exported.push_back(Mod);
+
+ continue;
+ }
+
+ // Wildcard export: export all of the imported modules that match
+ // the given pattern.
+ AnyWildcard = true;
+ if (UnrestrictedWildcard)
+ continue;
+
+ if (Module *Restriction = Exports[I].getPointer())
+ WildcardRestrictions.push_back(Restriction);
+ else {
+ WildcardRestrictions.clear();
+ UnrestrictedWildcard = true;
+ }
+ }
+
+ // If there were any wildcards, push any imported modules that were
+ // re-exported by the wildcard restriction.
+ if (!AnyWildcard)
+ return;
+
+ for (unsigned I = 0, N = Imports.size(); I != N; ++I) {
+ Module *Mod = Imports[I];
+ bool Acceptable = UnrestrictedWildcard;
+ if (!Acceptable) {
+ // Check whether this module meets one of the restrictions.
+ for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
+ Module *Restriction = WildcardRestrictions[R];
+ if (Mod == Restriction || Mod->isSubModuleOf(Restriction)) {
+ Acceptable = true;
+ break;
+ }
+ }
+ }
+
+ if (!Acceptable)
+ continue;
+
+ Exported.push_back(Mod);
+ }
+}
+
+void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.indent(Indent);
if (IsFramework)
OS << "framework ";
@@ -212,7 +279,20 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(UmbrellaDir->getName());
OS << "\"\n";
}
-
+
+ if (!ConfigMacros.empty() || ConfigMacrosExhaustive) {
+ OS.indent(Indent + 2);
+ OS << "config_macros ";
+ if (ConfigMacrosExhaustive)
+ OS << "[exhaustive]";
+ for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << ConfigMacros[I];
+ }
+ OS << "\n";
+ }
+
for (unsigned I = 0, N = Headers.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "header \"";
@@ -257,6 +337,34 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS << "\n";
}
+ for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "link ";
+ if (LinkLibraries[I].IsFramework)
+ OS << "framework ";
+ OS << "\"";
+ OS.write_escaped(LinkLibraries[I].Library);
+ OS << "\"";
+ }
+
+ for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "conflict ";
+ printModuleId(OS, UnresolvedConflicts[I].Id);
+ OS << ", \"";
+ OS.write_escaped(UnresolvedConflicts[I].Message);
+ OS << "\"\n";
+ }
+
+ for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "conflict ";
+ OS << Conflicts[I].Other->getFullModuleName();
+ OS << ", \"";
+ OS.write_escaped(Conflicts[I].Message);
+ OS << "\"\n";
+ }
+
if (InferSubmodules) {
OS.indent(Indent + 2);
if (InferExplicitSubmodules)
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
new file mode 100644
index 000000000000..835908d2a1b5
--- /dev/null
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -0,0 +1,43 @@
+//===--- OpenMPKinds.cpp - Token Kinds Support ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements the OpenMP enum and support functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+
+using namespace clang;
+
+OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) {
+ return llvm::StringSwitch<OpenMPDirectiveKind>(Str)
+#define OPENMP_DIRECTIVE(Name) \
+ .Case(#Name, OMPD_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPD_unknown);
+}
+
+const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
+ assert(Kind < NUM_OPENMP_DIRECTIVES);
+ switch (Kind) {
+ case OMPD_unknown:
+ return ("unknown");
+#define OPENMP_DIRECTIVE(Name) \
+ case OMPD_##Name : return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP directive kind");
+}
diff --git a/lib/Basic/OperatorPrecedence.cpp b/lib/Basic/OperatorPrecedence.cpp
new file mode 100644
index 000000000000..f9de231c5e77
--- /dev/null
+++ b/lib/Basic/OperatorPrecedence.cpp
@@ -0,0 +1,76 @@
+//===--- OperatorPrecedence.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines and computes precedence levels for binary/ternary operators.
+///
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/OperatorPrecedence.h"
+
+namespace clang {
+
+prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
+ bool CPlusPlus11) {
+ switch (Kind) {
+ case tok::greater:
+ // C++ [temp.names]p3:
+ // [...] When parsing a template-argument-list, the first
+ // non-nested > is taken as the ending delimiter rather than a
+ // greater-than operator. [...]
+ if (GreaterThanIsOperator)
+ return prec::Relational;
+ return prec::Unknown;
+
+ case tok::greatergreater:
+ // C++0x [temp.names]p3:
+ //
+ // [...] Similarly, the first non-nested >> is treated as two
+ // consecutive but distinct > tokens, the first of which is
+ // taken as the end of the template-argument-list and completes
+ // the template-id. [...]
+ if (GreaterThanIsOperator || !CPlusPlus11)
+ return prec::Shift;
+ return prec::Unknown;
+
+ default: return prec::Unknown;
+ case tok::comma: return prec::Comma;
+ case tok::equal:
+ case tok::starequal:
+ case tok::slashequal:
+ case tok::percentequal:
+ case tok::plusequal:
+ case tok::minusequal:
+ case tok::lesslessequal:
+ case tok::greatergreaterequal:
+ case tok::ampequal:
+ case tok::caretequal:
+ case tok::pipeequal: return prec::Assignment;
+ case tok::question: return prec::Conditional;
+ case tok::pipepipe: return prec::LogicalOr;
+ case tok::ampamp: return prec::LogicalAnd;
+ case tok::pipe: return prec::InclusiveOr;
+ case tok::caret: return prec::ExclusiveOr;
+ case tok::amp: return prec::And;
+ case tok::exclaimequal:
+ case tok::equalequal: return prec::Equality;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal: return prec::Relational;
+ case tok::lessless: return prec::Shift;
+ case tok::plus:
+ case tok::minus: return prec::Additive;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return prec::Multiplicative;
+ case tok::periodstar:
+ case tok::arrowstar: return prec::PointerToMember;
+ }
+}
+
+} // namespace clang
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 0d62f7bb4b8c..182209117966 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -65,7 +65,7 @@ std::string SourceLocation::printToString(const SourceManager &SM) const {
std::string S;
llvm::raw_string_ostream OS(S);
print(OS, SM);
- return S;
+ return OS.str();
}
void SourceLocation::dump(const SourceManager &SM) const {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index cd0284a18e5d..1b8383bc4261 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -12,20 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Basic/SourceManagerInternals.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Capacity.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/Capacity.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <string>
#include <cstring>
+#include <string>
#include <sys/stat.h>
using namespace clang;
@@ -721,7 +721,7 @@ FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const {
// See if this is near the file point - worst case we start scanning from the
// most newly created FileID.
- std::vector<SrcMgr::SLocEntry>::const_iterator I;
+ const SrcMgr::SLocEntry *I;
if (LastFileIDLookup.ID < 0 ||
LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
@@ -840,10 +840,17 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
++NumProbes;
unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
+ if (E.getOffset() == 0)
+ return FileID(); // invalid entry.
++NumProbes;
if (E.getOffset() > SLocOffset) {
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (GreaterIndex == MiddleIndex) {
+ assert(0 && "binary search missed the entry");
+ return FileID();
+ }
GreaterIndex = MiddleIndex;
continue;
}
@@ -856,6 +863,11 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
return Res;
}
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (LessIndex == MiddleIndex) {
+ assert(0 && "binary search missed the entry");
+ return FileID();
+ }
LessIndex = MiddleIndex;
}
}
@@ -974,11 +986,18 @@ bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const {
if (!Loc.isMacroID()) return false;
FileID FID = getFileID(Loc);
- const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
- const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+ const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion();
return Expansion.isMacroArgExpansion();
}
+bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const {
+ if (!Loc.isMacroID()) return false;
+
+ FileID FID = getFileID(Loc);
+ const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion();
+ return Expansion.isMacroBodyExpansion();
+}
+
//===----------------------------------------------------------------------===//
// Queries about the code at a SourceLocation.
@@ -1032,7 +1051,8 @@ 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 != 0 &&
+ LastLineNoResult < LastLineNoContentCache->NumLines) {
unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
unsigned LineEnd = SourceLineCache[LastLineNoResult];
@@ -1361,7 +1381,8 @@ const char *SourceManager::getBufferName(SourceLocation Loc,
///
/// Note that a presumed location is always given as the expansion point of an
/// expansion location, not at the spelling location.
-PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
+PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc,
+ bool UseLineDirectives) const {
if (Loc.isInvalid()) return PresumedLoc();
// Presumed locations are always for expansion points.
@@ -1395,7 +1416,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// If we have #line directives in this file, update and overwrite the physical
// location info if appropriate.
- if (FI.hasLineDirectives()) {
+ if (UseLineDirectives && FI.hasLineDirectives()) {
assert(LineTable && "Can't have linetable entries without a LineTable!");
// See if there is a #line directive before this. If so, get it.
if (const LineEntry *Entry =
@@ -1451,13 +1472,13 @@ unsigned SourceManager::getFileIDSize(FileID FID) const {
///
/// This routine involves a system call, and therefore should only be used
/// in non-performance-critical code.
-static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) {
+static Optional<ino_t> getActualFileInode(const FileEntry *File) {
if (!File)
- return llvm::Optional<ino_t>();
+ return None;
struct stat StatBuf;
if (::stat(File->getName(), &StatBuf))
- return llvm::Optional<ino_t>();
+ return None;
return StatBuf.st_ino;
}
@@ -1488,8 +1509,8 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
// First, check the main file ID, since it is common to look for a
// location in the main file.
- llvm::Optional<ino_t> SourceFileInode;
- llvm::Optional<StringRef> SourceFileName;
+ Optional<ino_t> SourceFileInode;
+ Optional<StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
bool Invalid = false;
const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
@@ -1511,8 +1532,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
SourceFileInode = getActualFileInode(SourceFile);
if (SourceFileInode) {
- if (llvm::Optional<ino_t> MainFileInode
- = getActualFileInode(MainFile)) {
+ if (Optional<ino_t> MainFileInode = getActualFileInode(MainFile)) {
if (*SourceFileInode == *MainFileInode) {
FirstFID = MainFileID;
SourceFile = MainFile;
@@ -1576,7 +1596,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
- if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
+ if (Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
if (*SourceFileInode == *EntryInode) {
FirstFID = FileID::get(I);
SourceFile = Entry;
@@ -1847,7 +1867,32 @@ static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
Loc = SM.getDecomposedLoc(UpperLoc);
return false;
}
-
+
+/// Return the cache entry for comparing the given file IDs
+/// for isBeforeInTranslationUnit.
+InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID,
+ FileID RFID) const {
+ // This is a magic number for limiting the cache size. It was experimentally
+ // derived from a small Objective-C project (where the cache filled
+ // out to ~250 items). We can make it larger if necessary.
+ enum { MagicCacheSize = 300 };
+ IsBeforeInTUCacheKey Key(LFID, RFID);
+
+ // If the cache size isn't too large, do a lookup and if necessary default
+ // construct an entry. We can then return it to the caller for direct
+ // use. When they update the value, the cache will get automatically
+ // updated as well.
+ if (IBTUCache.size() < MagicCacheSize)
+ return IBTUCache[Key];
+
+ // Otherwise, do a lookup that will not construct a new value.
+ InBeforeInTUCache::iterator I = IBTUCache.find(Key);
+ if (I != IBTUCache.end())
+ return I->second;
+
+ // Fall back to the overflow value.
+ return IBTUCacheOverflow;
+}
/// \brief Determines the order of 2 source locations in the translation unit.
///
@@ -1867,6 +1912,11 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
+ InBeforeInTUCacheEntry &IsBeforeInTUCache =
+ getInBeforeInTUCache(LOffs.first, ROffs.first);
+
+ // If we are comparing a source location with multiple locations in the same
+ // file, we get a big win by caching the result.
if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 83d4e2bf63c9..70ea2351ec35 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
#include <cstdlib>
using namespace clang;
@@ -84,7 +84,7 @@ TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T)
ComplexLongDoubleUsesFP2Ret = false;
// Default to using the Itanium ABI.
- CXXABI = CXXABI_Itanium;
+ TheCXXABI.set(TargetCXXABI::GenericItanium);
// Default to an empty address space map.
AddrSpaceMap = &DefaultAddrSpaceMap;
@@ -223,7 +223,7 @@ bool TargetInfo::isValidGCCRegisterName(StringRef Name) const {
getGCCRegNames(Names, NumNames);
// If we have a number it maps to an entry in the register name array.
- if (isdigit(Name[0])) {
+ if (isDigit(Name[0])) {
int n;
if (!Name.getAsInteger(0, n))
return n >= 0 && (unsigned)n < NumNames;
@@ -279,7 +279,7 @@ TargetInfo::getNormalizedGCCRegisterName(StringRef Name) const {
getGCCRegNames(Names, NumNames);
// First, check if we have a number.
- if (isdigit(Name[0])) {
+ if (isDigit(Name[0])) {
int n;
if (!Name.getAsInteger(0, n)) {
assert(n >= 0 && (unsigned)n < NumNames &&
@@ -496,3 +496,17 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
return true;
}
+
+bool TargetCXXABI::tryParse(llvm::StringRef name) {
+ const Kind unknown = static_cast<Kind>(-1);
+ Kind kind = llvm::StringSwitch<Kind>(name)
+ .Case("arm", GenericARM)
+ .Case("ios", iOS)
+ .Case("itanium", GenericItanium)
+ .Case("microsoft", Microsoft)
+ .Default(unknown);
+ if (kind == unknown) return false;
+
+ set(kind);
+ return true;
+}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f36ef826d0b2..3eda9d8c1841 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -25,9 +25,9 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Type.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Type.h"
#include <algorithm>
using namespace clang;
@@ -94,7 +94,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("OBJC_NEW_PROPERTIES");
// AddressSanitizer doesn't play well with source fortification, which is on
// by default on Darwin.
- if (Opts.SanitizeAddress) Builder.defineMacro("_FORTIFY_SOURCE", "0");
+ if (Opts.Sanitize.Address) Builder.defineMacro("_FORTIFY_SOURCE", "0");
if (!Opts.ObjCAutoRefCount) {
// __weak is always defined, for use in blocks and with objc pointers.
@@ -384,13 +384,13 @@ public:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
case llvm::Triple::arm:
- case llvm::Triple::sparc:
+ case llvm::Triple::sparc:
this->MCountName = "__mcount";
break;
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::ppc:
- case llvm::Triple::sparcv9:
+ case llvm::Triple::sparcv9:
this->MCountName = "_mcount";
break;
}
@@ -575,7 +575,7 @@ protected:
if (Opts.MicrosoftExt) {
Builder.defineMacro("_MSC_EXTENSIONS");
- if (Opts.CPlusPlus0x) {
+ if (Opts.CPlusPlus11) {
Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED");
Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED");
Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED");
@@ -661,9 +661,19 @@ public:
ArchDefine603 = 1 << 4,
ArchDefine604 = 1 << 5,
ArchDefinePwr4 = 1 << 6,
- ArchDefinePwr6 = 1 << 7
+ ArchDefinePwr5 = 1 << 7,
+ ArchDefinePwr5x = 1 << 8,
+ ArchDefinePwr6 = 1 << 9,
+ ArchDefinePwr6x = 1 << 10,
+ ArchDefinePwr7 = 1 << 11,
+ ArchDefineA2 = 1 << 12,
+ ArchDefineA2q = 1 << 13
} 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 CPUKnown = llvm::StringSwitch<bool>(Name)
.Case("generic", true)
@@ -677,6 +687,7 @@ public:
.Case("604", true)
.Case("604e", true)
.Case("620", true)
+ .Case("630", true)
.Case("g3", true)
.Case("7400", true)
.Case("g4", true)
@@ -686,11 +697,26 @@ public:
.Case("970", true)
.Case("g5", true)
.Case("a2", true)
+ .Case("a2q", true)
.Case("e500mc", true)
.Case("e5500", true)
+ .Case("power3", true)
+ .Case("pwr3", true)
+ .Case("power4", true)
+ .Case("pwr4", true)
+ .Case("power5", true)
+ .Case("pwr5", true)
+ .Case("power5x", true)
+ .Case("pwr5x", true)
+ .Case("power6", true)
.Case("pwr6", true)
+ .Case("power6x", true)
+ .Case("pwr6x", true)
+ .Case("power7", true)
.Case("pwr7", true)
+ .Case("powerpc", true)
.Case("ppc", true)
+ .Case("powerpc64", true)
.Case("ppc64", true)
.Default(false);
@@ -711,6 +737,12 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
+
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name,
+ bool Enabled) const;
+
virtual bool hasFeature(StringRef Feature) const;
virtual void getGCCRegNames(const char * const *&Names,
@@ -818,6 +850,11 @@ public:
virtual const char *getClobbers() const {
return "";
}
+ int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 3;
+ if (RegNo == 1) return 4;
+ return -1;
+ }
};
const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
@@ -875,14 +912,42 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
.Case("604", ArchDefineName | ArchDefinePpcgr)
.Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr)
.Case("620", ArchDefineName | ArchDefinePpcgr)
+ .Case("630", ArchDefineName | ArchDefinePpcgr)
.Case("7400", ArchDefineName | ArchDefinePpcgr)
.Case("7450", ArchDefineName | ArchDefinePpcgr)
.Case("750", ArchDefineName | ArchDefinePpcgr)
.Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr
| ArchDefinePpcsq)
- .Case("pwr6", ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr7", ArchDefineName | ArchDefinePwr6 | ArchDefinePpcgr
+ .Case("a2", ArchDefineA2)
+ .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q)
+ .Case("pwr3", ArchDefinePpcgr)
+ .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr
| ArchDefinePpcsq)
+ .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5
+ | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x
+ | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
+ | ArchDefinePpcsq)
+ .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6
+ | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power3", ArchDefinePpcgr)
+ .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
+ | ArchDefinePpcsq)
+ .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
+ | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x
+ | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
+ | ArchDefinePpcsq)
+ .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6
+ | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
.Default(ArchDefineNone);
if (defs & ArchDefineName)
@@ -897,12 +962,80 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_603");
if (defs & ArchDefine604)
Builder.defineMacro("_ARCH_604");
- if (defs & (ArchDefinePwr4 | ArchDefinePwr6))
+ if (defs & ArchDefinePwr4)
Builder.defineMacro("_ARCH_PWR4");
- if (defs & ArchDefinePwr6) {
+ if (defs & ArchDefinePwr5)
Builder.defineMacro("_ARCH_PWR5");
+ if (defs & ArchDefinePwr5x)
+ Builder.defineMacro("_ARCH_PWR5X");
+ if (defs & ArchDefinePwr6)
Builder.defineMacro("_ARCH_PWR6");
+ if (defs & ArchDefinePwr6x)
+ Builder.defineMacro("_ARCH_PWR6X");
+ if (defs & ArchDefinePwr7)
+ Builder.defineMacro("_ARCH_PWR7");
+ if (defs & ArchDefineA2)
+ Builder.defineMacro("_ARCH_A2");
+ if (defs & ArchDefineA2q) {
+ Builder.defineMacro("_ARCH_A2Q");
+ Builder.defineMacro("_ARCH_QP");
+ }
+
+ if (getTriple().getVendor() == llvm::Triple::BGQ) {
+ Builder.defineMacro("__bg__");
+ Builder.defineMacro("__THW_BLUEGENE__");
+ Builder.defineMacro("__bgq__");
+ Builder.defineMacro("__TOS_BGQ__");
+ }
+
+ // FIXME: The following are not yet generated here by Clang, but are
+ // generated by GCC:
+ //
+ // _SOFT_FLOAT_
+ // __RECIP_PRECISION__
+ // __APPLE_ALTIVEC__
+ // __VSX__
+ // __RECIP__
+ // __RECIPF__
+ // __RSQRTE__
+ // __RSQRTEF__
+ // _SOFT_DOUBLE_
+ // __NO_LWSYNC__
+ // __HAVE_BSWAP__
+ // __LONGDOUBLE128
+ // __CMODEL_MEDIUM__
+ // __CMODEL_LARGE__
+ // _CALL_SYSV
+ // _CALL_DARWIN
+ // __NO_FPRS__
+}
+
+void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ Features["altivec"] = llvm::StringSwitch<bool>(CPU)
+ .Case("7400", true)
+ .Case("g4", true)
+ .Case("7450", true)
+ .Case("g4+", true)
+ .Case("970", true)
+ .Case("g5", true)
+ .Case("pwr6", true)
+ .Case("pwr7", true)
+ .Case("ppc64", true)
+ .Default(false);
+
+ Features["qpx"] = (CPU == "a2q");
+}
+
+bool PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name,
+ bool Enabled) const {
+ if (Name == "altivec" || Name == "fprnd" || Name == "mfocrf" ||
+ Name == "popcntd" || Name == "qpx") {
+ Features[Name] = Enabled;
+ return true;
}
+
+ return false;
}
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
@@ -1122,7 +1255,7 @@ namespace {
class NVPTXTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const Builtin::Info BuiltinInfo[];
- std::vector<llvm::StringRef> AvailableFeatures;
+ std::vector<StringRef> AvailableFeatures;
public:
NVPTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
BigEndian = false;
@@ -1169,7 +1302,14 @@ namespace {
return TargetInfo::CharPtrBuiltinVaList;
}
virtual bool setCPU(const std::string &Name) {
- return Name == "sm_10" || Name == "sm_13" || Name == "sm_20";
+ bool Valid = llvm::StringSwitch<bool>(Name)
+ .Case("sm_20", true)
+ .Case("sm_21", true)
+ .Case("sm_30", true)
+ .Case("sm_35", true)
+ .Default(false);
+
+ return Valid;
}
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
StringRef Name,
@@ -1241,16 +1381,50 @@ static const unsigned R600AddrSpaceMap[] = {
3 // cuda_shared
};
+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";
+
+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";
+
+static const char *DescriptionStringSI =
+ "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-v2048:2048:2048"
+ "-n32:64";
+
class R600TargetInfo : public TargetInfo {
+ /// \brief The GPU profiles supported by the R600 target.
+ enum GPUKind {
+ GK_NONE,
+ GK_R600,
+ GK_R600_DOUBLE_OPS,
+ GK_R700,
+ GK_R700_DOUBLE_OPS,
+ GK_EVERGREEN,
+ GK_EVERGREEN_DOUBLE_OPS,
+ GK_NORTHERN_ISLANDS,
+ GK_CAYMAN,
+ GK_SOUTHERN_ISLANDS
+ } GPU;
+
public:
- R600TargetInfo(const std::string& triple) : TargetInfo(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-f80: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"
- "-n8:16:32:64";
+ R600TargetInfo(const std::string& triple)
+ : TargetInfo(triple),
+ GPU(GK_R600) {
+ DescriptionString = DescriptionStringR600;
AddrSpaceMap = &R600AddrSpaceMap;
}
@@ -1291,6 +1465,65 @@ public:
return TargetInfo::CharPtrBuiltinVaList;
}
+ virtual bool setCPU(const std::string &Name) {
+ GPU = llvm::StringSwitch<GPUKind>(Name)
+ .Case("r600" , GK_R600)
+ .Case("rv610", GK_R600)
+ .Case("rv620", GK_R600)
+ .Case("rv630", GK_R600)
+ .Case("rv635", GK_R600)
+ .Case("rs780", GK_R600)
+ .Case("rs880", GK_R600)
+ .Case("rv670", GK_R600_DOUBLE_OPS)
+ .Case("rv710", GK_R700)
+ .Case("rv730", GK_R700)
+ .Case("rv740", GK_R700_DOUBLE_OPS)
+ .Case("rv770", GK_R700_DOUBLE_OPS)
+ .Case("palm", GK_EVERGREEN)
+ .Case("cedar", GK_EVERGREEN)
+ .Case("sumo", GK_EVERGREEN)
+ .Case("sumo2", GK_EVERGREEN)
+ .Case("redwood", GK_EVERGREEN)
+ .Case("juniper", GK_EVERGREEN)
+ .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("cypress", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("barts", GK_NORTHERN_ISLANDS)
+ .Case("turks", GK_NORTHERN_ISLANDS)
+ .Case("caicos", GK_NORTHERN_ISLANDS)
+ .Case("cayman", GK_CAYMAN)
+ .Case("aruba", GK_CAYMAN)
+ .Case("tahiti", GK_SOUTHERN_ISLANDS)
+ .Case("pitcairn", GK_SOUTHERN_ISLANDS)
+ .Case("verde", GK_SOUTHERN_ISLANDS)
+ .Case("oland", GK_SOUTHERN_ISLANDS)
+ .Default(GK_NONE);
+
+ if (GPU == GK_NONE) {
+ return false;
+ }
+
+ // Set the correct data layout
+ switch (GPU) {
+ case GK_NONE:
+ case GK_R600:
+ case GK_R700:
+ case GK_EVERGREEN:
+ case GK_NORTHERN_ISLANDS:
+ DescriptionString = DescriptionStringR600;
+ break;
+ case GK_R600_DOUBLE_OPS:
+ case GK_R700_DOUBLE_OPS:
+ case GK_EVERGREEN_DOUBLE_OPS:
+ case GK_CAYMAN:
+ DescriptionString = DescriptionStringR600DoubleOps;
+ break;
+ case GK_SOUTHERN_ISLANDS:
+ DescriptionString = DescriptionStringSI;
+ break;
+ }
+
+ return true;
+ }
};
} // end anonymous namespace
@@ -1476,6 +1709,8 @@ class X86TargetInfo : public TargetInfo {
bool HasBMI2;
bool HasPOPCNT;
bool HasRTM;
+ bool HasPRFCHW;
+ bool HasRDSEED;
bool HasSSE4a;
bool HasFMA4;
bool HasFMA;
@@ -1627,8 +1862,8 @@ public:
: TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
HasAES(false), HasPCLMUL(false), HasLZCNT(false), HasRDRND(false),
HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false),
- HasSSE4a(false), HasFMA4(false), HasFMA(false), HasXOP(false),
- HasF16C(false), CPU(CK_Generic) {
+ HasPRFCHW(false), HasRDSEED(false), HasSSE4a(false), HasFMA4(false),
+ HasFMA(false), HasXOP(false), HasF16C(false), CPU(CK_Generic) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1652,7 +1887,7 @@ public:
NumAliases = 0;
}
virtual void getGCCAddlRegNames(const AddlRegName *&Names,
- unsigned &NumNames) const {
+ unsigned &NumNames) const {
Names = AddlRegNames;
NumNames = llvm::array_lengthof(AddlRegNames);
}
@@ -1803,11 +2038,12 @@ public:
CC == CC_X86FastCall ||
CC == CC_X86StdCall ||
CC == CC_C ||
- CC == CC_X86Pascal) ? CCCR_OK : CCCR_Warning;
+ CC == CC_X86Pascal ||
+ CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
- virtual CallingConv getDefaultCallingConv() const {
- return CC_C;
+ virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
}
};
@@ -1833,6 +2069,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features["bmi2"] = false;
Features["popcnt"] = false;
Features["rtm"] = false;
+ Features["prfchw"] = false;
+ Features["rdseed"] = false;
Features["fma4"] = false;
Features["fma"] = false;
Features["xop"] = false;
@@ -1842,7 +2080,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
// X86_64 always has SSE2.
if (getTriple().getArch() == llvm::Triple::x86_64)
- Features["sse2"] = Features["sse"] = Features["mmx"] = true;
+ setFeatureEnabled(Features, "sse2", true);
switch (CPU) {
case CK_Generic:
@@ -1859,58 +2097,50 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
break;
case CK_Pentium3:
case CK_Pentium3M:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
break;
case CK_PentiumM:
case CK_Pentium4:
case CK_Pentium4M:
case CK_x86_64:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse2", true);
break;
case CK_Yonah:
case CK_Prescott:
case CK_Nocona:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse3", true);
break;
case CK_Core2:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "ssse3", true);
break;
case CK_Penryn:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4.1", true);
break;
case CK_Atom:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "ssse3", true);
break;
case CK_Corei7:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
break;
case CK_Corei7AVX:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "avx", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
break;
case CK_CoreAVXi:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "avx", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
setFeatureEnabled(Features, "rdrnd", true);
+ setFeatureEnabled(Features, "f16c", true);
break;
case CK_CoreAVX2:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "avx2", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
setFeatureEnabled(Features, "lzcnt", true);
setFeatureEnabled(Features, "rdrnd", true);
+ setFeatureEnabled(Features, "f16c", true);
setFeatureEnabled(Features, "bmi", true);
setFeatureEnabled(Features, "bmi2", true);
setFeatureEnabled(Features, "rtm", true);
@@ -1954,20 +2184,31 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabled(Features, "sse3", true);
setFeatureEnabled(Features, "sse4a", true);
setFeatureEnabled(Features, "3dnowa", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "popcnt", true);
break;
case CK_BTVER1:
setFeatureEnabled(Features, "ssse3", true);
setFeatureEnabled(Features, "sse4a", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "popcnt", true);
break;
case CK_BDVER1:
+ setFeatureEnabled(Features, "xop", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "aes", true);
+ setFeatureEnabled(Features, "pclmul", true);
+ break;
case CK_BDVER2:
- setFeatureEnabled(Features, "avx", true);
setFeatureEnabled(Features, "xop", true);
+ setFeatureEnabled(Features, "lzcnt", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
+ setFeatureEnabled(Features, "bmi", true);
+ setFeatureEnabled(Features, "fma", true);
+ setFeatureEnabled(Features, "f16c", true);
break;
case CK_C3_2:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
break;
}
@@ -2026,12 +2267,12 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
Features["popcnt"] = Features["avx"] = Features["fma"] = true;
else if (Name == "fma4")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
Features["popcnt"] = Features["avx"] = Features["sse4a"] =
Features["fma4"] = true;
else if (Name == "xop")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
Features["popcnt"] = Features["avx"] = Features["sse4a"] =
Features["fma4"] = Features["xop"] = true;
@@ -2052,6 +2293,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["f16c"] = true;
else if (Name == "rtm")
Features["rtm"] = true;
+ else if (Name == "prfchw")
+ Features["prfchw"] = true;
+ else if (Name == "rdseed")
+ Features["rdseed"] = true;
} else {
if (Name == "mmx")
Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
@@ -2116,6 +2361,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["f16c"] = false;
else if (Name == "rtm")
Features["rtm"] = false;
+ else if (Name == "prfchw")
+ Features["prfchw"] = false;
+ else if (Name == "rdseed")
+ Features["rdseed"] = false;
}
return true;
@@ -2172,6 +2421,16 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
+ if (Feature == "prfchw") {
+ HasPRFCHW = true;
+ continue;
+ }
+
+ if (Feature == "rdseed") {
+ HasRDSEED = true;
+ continue;
+ }
+
if (Feature == "sse4a") {
HasSSE4a = true;
continue;
@@ -2396,6 +2655,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasRTM)
Builder.defineMacro("__RTM__");
+ if (HasPRFCHW)
+ Builder.defineMacro("__PRFCHW__");
+
+ if (HasRDSEED)
+ Builder.defineMacro("__RDSEED__");
+
if (HasSSE4a)
Builder.defineMacro("__SSE4A__");
@@ -2465,6 +2730,14 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case NoMMX3DNow:
break;
}
+
+ if (CPU >= CK_i486) {
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ }
+ if (CPU >= CK_i586)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
bool X86TargetInfo::hasFeature(StringRef Feature) const {
@@ -2484,6 +2757,8 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("pclmul", HasPCLMUL)
.Case("popcnt", HasPOPCNT)
.Case("rtm", HasRTM)
+ .Case("prfchw", HasPRFCHW)
+ .Case("rdseed", HasRDSEED)
.Case("sse", SSELevel >= SSE1)
.Case("sse2", SSELevel >= SSE2)
.Case("sse3", SSELevel >= SSE3)
@@ -2600,6 +2875,19 @@ public:
if (RegNo == 1) return 2;
return -1;
}
+ virtual bool validateInputSize(StringRef Constraint,
+ unsigned Size) const {
+ switch (Constraint[0]) {
+ default: break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ return Size <= 32;
+ }
+
+ return true;
+ }
};
} // end anonymous namespace
@@ -2747,6 +3035,7 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_X86_");
Builder.defineMacro("__CYGWIN__");
Builder.defineMacro("__CYGWIN32__");
DefineStd(Builder, "unix", Opts);
@@ -2877,11 +3166,13 @@ public:
}
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
- return TargetInfo::checkCallingConvention(CC);
+ return (CC == CC_Default ||
+ CC == CC_C ||
+ CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
- virtual CallingConv getDefaultCallingConv() const {
- return CC_Default;
+ virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ return CC_C;
}
};
@@ -2995,6 +3286,190 @@ public:
Int64Type = SignedLongLong;
}
};
+}
+
+namespace {
+class AArch64TargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+public:
+ AArch64TargetInfo(const std::string& 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.
+
+ // FIXME: these were written based on an unreleased version of a 32-bit ACLE
+ // which was intended to be compatible with a 64-bit implementation. They
+ // will need updating when a real 64-bit ACLE exists. Particularly pressing
+ // instances are: __AARCH_ISA_A32, __AARCH_ISA_T32, __ARCH_PCS.
+ Builder.defineMacro("__AARCH_ACLE", "101");
+ Builder.defineMacro("__AARCH", "8");
+ Builder.defineMacro("__AARCH_PROFILE", "'A'");
+
+ Builder.defineMacro("__AARCH_FEATURE_UNALIGNED");
+ Builder.defineMacro("__AARCH_FEATURE_CLZ");
+ Builder.defineMacro("__AARCH_FEATURE_FMA");
+
+ // FIXME: ACLE 1.1 reserves bit 4. Will almost certainly come to mean
+ // 128-bit LDXP present, at which point this becomes 0x1f.
+ Builder.defineMacro("__AARCH_FEATURE_LDREX", "0xf");
+
+ // 0xe implies support for half, single and double precision operations.
+ Builder.defineMacro("__AARCH_FP", "0xe");
+
+ // PCS specifies this for SysV variants, which is all we support. Other ABIs
+ // may choose __AARCH_FP16_FORMAT_ALTERNATIVE.
+ Builder.defineMacro("__AARCH_FP16_FORMAT_IEEE");
+
+ if (Opts.FastMath || Opts.FiniteMathOnly)
+ Builder.defineMacro("__AARCH_FP_FAST");
+
+ if ((Opts.C99 || Opts.C11) && !Opts.Freestanding)
+ Builder.defineMacro("__AARCH_FP_FENV_ROUNDING");
+
+ Builder.defineMacro("__AARCH_SIZEOF_WCHAR_T",
+ Opts.ShortWChar ? "2" : "4");
+
+ Builder.defineMacro("__AARCH_SIZEOF_MINIMAL_ENUM",
+ Opts.ShortEnums ? "1" : "4");
+
+ if (BigEndian)
+ Builder.defineMacro("__AARCH_BIG_ENDIAN");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = 0;
+ NumRecords = 0;
+ }
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "aarch64";
+ }
+ 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);
+
+}
} // end anonymous namespace
namespace {
@@ -3056,7 +3531,7 @@ public:
}
// ARM targets default to using the ARM C++ ABI.
- CXXABI = CXXABI_ARM;
+ TheCXXABI.set(TargetCXXABI::GenericARM);
// ARM has atomics up to 8 bytes
// FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
@@ -3078,7 +3553,9 @@ public:
// name.
if (Name == "apcs-gnu") {
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
- SizeType = UnsignedLong;
+ // 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;
@@ -3124,7 +3601,7 @@ public:
else if (CPU == "cortex-a8" || CPU == "cortex-a15" ||
CPU == "cortex-a9" || CPU == "cortex-a9-mp")
Features["neon"] = true;
- else if (CPU == "swift") {
+ else if (CPU == "swift" || CPU == "cortex-a7") {
Features["vfp4"] = true;
Features["neon"] = true;
}
@@ -3197,7 +3674,9 @@ public:
.Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "7A")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
+ .Cases("cortex-a9", "cortex-a15", "7A")
+ .Case("cortex-r5", "7R")
.Case("cortex-a9-mp", "7F")
.Case("swift", "7S")
.Cases("cortex-m3", "cortex-m4", "7M")
@@ -3208,6 +3687,7 @@ public:
return llvm::StringSwitch<const char*>(Name)
.Cases("cortex-a8", "cortex-a9", "A")
.Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
+ .Case("cortex-r5", "R")
.Default("");
}
virtual bool setCPU(const std::string &Name) {
@@ -3318,11 +3798,11 @@ public:
case 'v': // ...VFP load/store (reg+constant offset)
case 'y': // ...iWMMXt load/store
case 't': // address valid for load/store opaque types wider
- // than 128-bits
+ // than 128-bits
case 'n': // valid address for Neon doubleword vector load/store
case 'm': // valid address for Neon element and structure load/store
case 's': // valid address for non-offset loads/stores of quad-word
- // values in four ARM registers
+ // values in four ARM registers
Info.setAllowsMemory();
Name++;
return true;
@@ -3348,6 +3828,9 @@ public:
virtual bool validateConstraintModifier(StringRef Constraint,
const char Modifier,
unsigned Size) const {
+ bool isOutput = (Constraint[0] == '=');
+ bool isInOut = (Constraint[0] == '+');
+
// Strip off constraint modifiers.
while (Constraint[0] == '=' ||
Constraint[0] == '+' ||
@@ -3359,7 +3842,8 @@ public:
case 'r': {
switch (Modifier) {
default:
- return Size == 32;
+ return isInOut || (isOutput && Size >= 32) ||
+ (!isOutput && !isInOut && Size <= 32);
case 'q':
// A register of size 32 cannot fit a vector type.
return false;
@@ -3377,6 +3861,12 @@ public:
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning;
}
+
+ virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 0;
+ if (RegNo == 1) return 1;
+ return -1;
+ }
};
const char * const ARMTargetInfo::GCCRegNames[] = {
@@ -3458,6 +3948,9 @@ public:
// iOS always has 64-bit atomic instructions.
// FIXME: This should be based off of the target features in ARMTargetInfo.
MaxAtomicInlineWidth = 64;
+
+ // Darwin on iOS uses a variant of the ARM C++ ABI.
+ TheCXXABI.set(TargetCXXABI::iOS);
}
};
} // end anonymous namespace.
@@ -3474,7 +3967,7 @@ public:
HexagonTargetInfo(const std::string& triple) : TargetInfo(triple) {
BigEndian = false;
DescriptionString = ("e-p:32:32:32-"
- "i64:64:64-i32:32:32-i16:16:16-i1:32:32"
+ "i64:64:64-i32:32:32-i16:16:16-i1:32:32-"
"f64:64:64-f32:32:32-a0:0-n32");
// {} in inline assembly are packet specifiers, not assembly variant
@@ -3513,8 +4006,6 @@ public:
static const char *getHexagonCPUSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
- .Case("hexagonv2", "2")
- .Case("hexagonv3", "3")
.Case("hexagonv4", "4")
.Case("hexagonv5", "5")
.Default(0);
@@ -4040,6 +4531,9 @@ public:
case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
+ case 'R': // An address that can be used in a non-macro load or store
+ Info.setAllowsMemory();
+ return true;
}
}
@@ -4058,6 +4552,12 @@ public:
Name == "mips16" || Name == "dsp" || Name == "dspr2") {
Features[Name] = Enabled;
return true;
+ } else if (Name == "32") {
+ Features["o32"] = Enabled;
+ return true;
+ } else if (Name == "64") {
+ Features["n64"] = Enabled;
+ return true;
}
return false;
}
@@ -4087,6 +4587,12 @@ public:
if (it != Features.end())
Features.erase(it);
}
+
+ virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 4;
+ if (RegNo == 1) return 5;
+ return -1;
+ }
};
const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = {
@@ -4102,11 +4608,15 @@ public:
MipsTargetInfoBase(triple, "o32", "mips32") {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
virtual bool setABI(const std::string &Name) {
if ((Name == "o32") || (Name == "eabi")) {
ABI = Name;
return true;
+ } else if (Name == "32") {
+ ABI = "o32";
+ return true;
} else
return false;
}
@@ -4168,7 +4678,7 @@ class Mips32EBTargetInfo : public Mips32TargetInfoBase {
public:
Mips32EBTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
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";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4183,7 +4693,7 @@ public:
Mips32ELTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
BigEndian = false;
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";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4202,22 +4712,28 @@ public:
PointerWidth = PointerAlign = 64;
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ }
SuitableAlign = 128;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual bool setABI(const std::string &Name) {
SetDescriptionString(Name);
-
- if (Name != "n32" && Name != "n64")
- return false;
-
- ABI = Name;
-
if (Name == "n32") {
LongWidth = LongAlign = 32;
PointerWidth = PointerAlign = 32;
- }
-
- return true;
+ ABI = Name;
+ return true;
+ } else if (Name == "n64") {
+ ABI = Name;
+ return true;
+ } else if (Name == "64") {
+ ABI = "n64";
+ return true;
+ } else
+ return false;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4285,14 +4801,14 @@ class Mips64EBTargetInfo : public Mips64TargetInfoBase {
if (Name == "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";
+ "v64:64:64-n32:64-S128";
}
public:
Mips64EBTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
// Default ABI is n64.
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";
+ "v64:64:64-n32:64-S128";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4308,7 +4824,7 @@ class Mips64ELTargetInfo : public Mips64TargetInfoBase {
if (Name == "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";
+ "-v64:64:64-n32:64-S128";
}
public:
Mips64ELTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
@@ -4316,7 +4832,7 @@ public:
BigEndian = false;
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";
+ "v64:64:64-n32:64-S128";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4399,6 +4915,97 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
}
} // end anonymous namespace.
+namespace {
+ static const unsigned SPIRAddrSpaceMap[] = {
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // cuda_device
+ 0, // cuda_constant
+ 0 // cuda_shared
+ };
+ class SPIRTargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ static const Builtin::Info BuiltinInfo[];
+ std::vector<StringRef> AvailableFeatures;
+ public:
+ SPIRTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
+ "SPIR target must use unknown OS");
+ assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
+ "SPIR target must use unknown environment type");
+ BigEndian = false;
+ TLSSupported = false;
+ LongWidth = LongAlign = 64;
+ AddrSpaceMap = &SPIRAddrSpaceMap;
+ // Define available target features
+ // These must be defined in sorted order!
+ NoAsmVariants = true;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR", Opts);
+ }
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "spir";
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {}
+ virtual const char *getClobbers() const {
+ return "";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {}
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ return true;
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {}
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+ };
+
+
+ class SPIR32TargetInfo : public SPIRTargetInfo {
+ public:
+ SPIR32TargetInfo(const std::string& triple) : SPIRTargetInfo(triple) {
+ PointerWidth = PointerAlign = 32;
+ 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";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR32", Opts);
+ }
+ };
+
+ class SPIR64TargetInfo : public SPIRTargetInfo {
+ public:
+ SPIR64TargetInfo(const std::string& triple) : SPIRTargetInfo(triple) {
+ 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";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR64", Opts);
+ }
+ };
+}
+
//===----------------------------------------------------------------------===//
// Driver code
@@ -4415,6 +5022,14 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::hexagon:
return new HexagonTargetInfo(T);
+ case llvm::Triple::aarch64:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<AArch64TargetInfo>(T);
+ default:
+ return new AArch64TargetInfo(T);
+ }
+
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Triple.isOSDarwin())
@@ -4433,7 +5048,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new BitrigTargetInfo<ARMTargetInfo>(T);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<ARMTargetInfo>(T);
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<ARMTargetInfo>(T);
default:
return new ARMTargetInfo(T);
@@ -4504,7 +5119,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::le32:
switch (os) {
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<PNaClTargetInfo>(T);
default:
return NULL;
@@ -4573,10 +5188,6 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new SparcV8TargetInfo(T);
}
- // FIXME: Need a real SPU target.
- case llvm::Triple::cellspu:
- return new PS3SPUTargetInfo<PPC64TargetInfo>(T);
-
case llvm::Triple::tce:
return new TCETargetInfo(T);
@@ -4613,7 +5224,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new HaikuX86_32TargetInfo(T);
case llvm::Triple::RTEMS:
return new RTEMSX86_32TargetInfo(T);
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<X86_32TargetInfo>(T);
default:
return new X86_32TargetInfo(T);
@@ -4644,19 +5255,34 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MinGWX86_64TargetInfo(T);
case llvm::Triple::Win32: // This is what Triple.h supports now.
return new VisualStudioWindowsX86_64TargetInfo(T);
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<X86_64TargetInfo>(T);
default:
return new X86_64TargetInfo(T);
}
+
+ case llvm::Triple::spir: {
+ llvm::Triple Triple(T);
+ if (Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
+ return NULL;
+ return new SPIR32TargetInfo(T);
+ }
+ case llvm::Triple::spir64: {
+ llvm::Triple Triple(T);
+ if (Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
+ return NULL;
+ return new SPIR64TargetInfo(T);
+ }
}
}
/// CreateTargetInfo - Return the target info object for the specified target
/// triple.
TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
- TargetOptions &Opts) {
- llvm::Triple Triple(Opts.Triple);
+ TargetOptions *Opts) {
+ llvm::Triple Triple(Opts->Triple);
// Construct the target
OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
@@ -4667,20 +5293,20 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Target->setTargetOpts(Opts);
// Set the target CPU if specified.
- if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) {
- Diags.Report(diag::err_target_unknown_cpu) << Opts.CPU;
+ if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) {
+ Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU;
return 0;
}
// Set the target ABI if specified.
- if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) {
- Diags.Report(diag::err_target_unknown_abi) << Opts.ABI;
+ 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;
+ if (!Opts->CXXABI.empty() && !Target->setCXXABI(Opts->CXXABI)) {
+ Diags.Report(diag::err_target_unknown_cxxabi) << Opts->CXXABI;
return 0;
}
@@ -4692,8 +5318,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Apply the user specified deltas.
// First the enables.
for (std::vector<std::string>::const_iterator
- it = Opts.FeaturesAsWritten.begin(),
- ie = Opts.FeaturesAsWritten.end();
+ it = Opts->FeaturesAsWritten.begin(),
+ ie = Opts->FeaturesAsWritten.end();
it != ie; ++it) {
const char *Name = it->c_str();
@@ -4709,8 +5335,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Then the disables.
for (std::vector<std::string>::const_iterator
- it = Opts.FeaturesAsWritten.begin(),
- ie = Opts.FeaturesAsWritten.end();
+ it = Opts->FeaturesAsWritten.begin(),
+ ie = Opts->FeaturesAsWritten.end();
it != ie; ++it) {
const char *Name = it->c_str();
@@ -4729,11 +5355,11 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
//
// FIXME: If we are completely confident that we have the right set, we only
// need to pass the minuses.
- Opts.Features.clear();
+ Opts->Features.clear();
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
- Opts.Features.push_back((it->second ? "+" : "-") + it->first().str());
- Target->HandleTargetFeatures(Opts.Features);
+ Opts->Features.push_back((it->second ? "+" : "-") + it->first().str());
+ Target->HandleTargetFeatures(Opts->Features);
return Target.take();
}
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index 8cdc1e31950c..6ce076e57a6c 100644
--- a/lib/Basic/TokenKinds.cpp
+++ b/lib/Basic/TokenKinds.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TokenKinds.h"
-
#include <cassert>
using namespace clang;
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index dc7d8d14eefb..7381e7025083 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -13,10 +13,14 @@
#include "clang/Basic/Version.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Config/config.h"
-#include <cstring>
+#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
+#include <cstring>
+
+#ifdef HAVE_SVN_VERSION_INC
+# include "SVNVersion.inc"
+#endif
namespace clang {
@@ -32,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.
- static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_32/final/lib/Basic/Version.cpp $");
+ static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
index 4f479d00d6cc..8b781ab0a304 100644
--- a/lib/Basic/VersionTuple.cpp
+++ b/lib/Basic/VersionTuple.cpp
@@ -28,9 +28,9 @@ std::string VersionTuple::getAsString() const {
raw_ostream& clang::operator<<(raw_ostream &Out,
const VersionTuple &V) {
Out << V.getMajor();
- if (llvm::Optional<unsigned> Minor = V.getMinor())
+ if (Optional<unsigned> Minor = V.getMinor())
Out << '.' << *Minor;
- if (llvm::Optional<unsigned> Subminor = V.getSubminor())
+ if (Optional<unsigned> Subminor = V.getSubminor())
Out << '.' << *Subminor;
return Out;
}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 206c22818b3c..053320ced1d0 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -16,3 +16,4 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Tooling)
add_subdirectory(StaticAnalyzer)
+add_subdirectory(Format)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index da6d035dfaf0..35780f1556dd 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -11,7 +11,8 @@
#define CLANG_CODEGEN_ABIINFO_H
#include "clang/AST/Type.h"
-#include "llvm/Type.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/CallingConv.h"
namespace llvm {
class Value;
@@ -102,8 +103,10 @@ namespace clang {
return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
- , bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0);
+ , bool Realign = false
+ , llvm::Type *Padding = 0) {
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
+ Padding);
}
static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
@@ -182,14 +185,24 @@ namespace clang {
class ABIInfo {
public:
CodeGen::CodeGenTypes &CGT;
+ protected:
+ llvm::CallingConv::ID RuntimeCC;
+ public:
+ ABIInfo(CodeGen::CodeGenTypes &cgt)
+ : CGT(cgt), RuntimeCC(llvm::CallingConv::C) {}
- ABIInfo(CodeGen::CodeGenTypes &cgt) : CGT(cgt) {}
virtual ~ABIInfo();
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
+ /// Return the calling convention to use for system runtime
+ /// functions.
+ llvm::CallingConv::ID getRuntimeCC() const {
+ return RuntimeCC;
+ }
+
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
/// EmitVAArg - Emit the target dependent code to load a value of
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 62f87c983bfa..45079c098984 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -9,31 +9,32 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/Module.h"
-#include "llvm/PassManager.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/DataLayout.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
using namespace clang;
using namespace llvm;
@@ -58,13 +59,8 @@ private:
if (!CodeGenPasses) {
CodeGenPasses = new PassManager();
CodeGenPasses->add(new DataLayout(TheModule));
- // Add TargetTransformInfo.
- if (TM) {
- TargetTransformInfo *TTI =
- new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo());
- CodeGenPasses->add(TTI);
- }
+ if (TM)
+ TM->addAnalysisPasses(*CodeGenPasses);
}
return CodeGenPasses;
}
@@ -73,12 +69,8 @@ private:
if (!PerModulePasses) {
PerModulePasses = new PassManager();
PerModulePasses->add(new DataLayout(TheModule));
- if (TM) {
- TargetTransformInfo *TTI =
- new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo());
- PerModulePasses->add(TTI);
- }
+ if (TM)
+ TM->addAnalysisPasses(*PerModulePasses);
}
return PerModulePasses;
}
@@ -87,12 +79,8 @@ private:
if (!PerFunctionPasses) {
PerFunctionPasses = new FunctionPassManager(TheModule);
PerFunctionPasses->add(new DataLayout(TheModule));
- if (TM) {
- TargetTransformInfo *TTI =
- new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo());
- PerFunctionPasses->add(TTI);
- }
+ if (TM)
+ TM->addAnalysisPasses(*PerFunctionPasses);
}
return PerFunctionPasses;
}
@@ -135,6 +123,20 @@ public:
void EmitAssembly(BackendAction Action, raw_ostream *OS);
};
+// We need this wrapper to access LangOpts and CGOpts from extension functions
+// that we add to the PassManagerBuilder.
+class PassManagerBuilderWrapper : public PassManagerBuilder {
+public:
+ PassManagerBuilderWrapper(const CodeGenOptions &CGOpts,
+ const LangOptions &LangOpts)
+ : PassManagerBuilder(), CGOpts(CGOpts), LangOpts(LangOpts) {}
+ const CodeGenOptions &getCGOpts() const { return CGOpts; }
+ const LangOptions &getLangOpts() const { return LangOpts; }
+private:
+ const CodeGenOptions &CGOpts;
+ const LangOptions &LangOpts;
+};
+
}
static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
@@ -152,20 +154,56 @@ static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase
PM.add(createObjCARCOptPass());
}
-static unsigned BoundsChecking;
static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
- PM.add(createBoundsCheckingPass(BoundsChecking));
+ PM.add(createBoundsCheckingPass());
}
-static void addAddressSanitizerPass(const PassManagerBuilder &Builder,
- PassManagerBase &PM) {
- PM.add(createAddressSanitizerPass());
+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));
+}
+
+static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createMemorySanitizerPass(CGOpts.SanitizeMemoryTrackOrigins,
+ CGOpts.SanitizerBlacklistFile));
+
+ // MemorySanitizer inserts complex instrumentation that mostly follows
+ // the logic of the original code, but operates on "shadow" values.
+ // It can benefit from re-running some general purpose optimization passes.
+ if (Builder.OptLevel > 0) {
+ PM.add(createEarlyCSEPass());
+ PM.add(createReassociatePass());
+ PM.add(createLICMPass());
+ PM.add(createGVNPass());
+ PM.add(createInstructionCombiningPass());
+ PM.add(createDeadStoreEliminationPass());
+ }
}
static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
- PM.add(createThreadSanitizerPass());
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createThreadSanitizerPass(CGOpts.SanitizerBlacklistFile));
}
void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
@@ -178,8 +216,8 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
OptLevel = 0;
Inlining = CodeGenOpts.NoInlining;
}
-
- PassManagerBuilder PMBuilder;
+
+ PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
PMBuilder.OptLevel = OptLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
@@ -197,22 +235,28 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
addObjCARCOptPass);
}
- if (CodeGenOpts.BoundsChecking > 0) {
- BoundsChecking = CodeGenOpts.BoundsChecking;
+ if (LangOpts.Sanitize.Bounds) {
PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
addBoundsCheckingPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addBoundsCheckingPass);
}
- if (LangOpts.SanitizeAddress) {
+ if (LangOpts.Sanitize.Address) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addAddressSanitizerPass);
+ addAddressSanitizerPasses);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addAddressSanitizerPass);
+ addAddressSanitizerPasses);
}
- if (LangOpts.SanitizeThread) {
+ if (LangOpts.Sanitize.Memory) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
+ addMemorySanitizerPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addMemorySanitizerPass);
+ }
+
+ if (LangOpts.Sanitize.Thread) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addThreadSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
@@ -258,11 +302,19 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
// Set up the per-module pass manager.
PassManager *MPM = getPerModulePasses(TM);
- if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
- MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
- CodeGenOpts.EmitGcovArcs,
- TargetTriple.isMacOSX()));
-
+ if (!CodeGenOpts.DisableGCov &&
+ (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) {
+ // Not using 'GCOVOptions::getDefault' allows us to avoid exiting if
+ // LLVM's -default-gcov-version flag is set to something invalid.
+ GCOVOptions Options;
+ Options.EmitNotes = CodeGenOpts.EmitGcovNotes;
+ Options.EmitData = CodeGenOpts.EmitGcovArcs;
+ memcpy(Options.Version, CodeGenOpts.CoverageVersion, 4);
+ Options.UseCfgChecksum = CodeGenOpts.CoverageExtraChecksum;
+ Options.NoRedZone = CodeGenOpts.DisableRedZone;
+ Options.FunctionNamesInData =
+ !CodeGenOpts.CoverageNoFunctionNamesInData;
+ MPM->add(createGCOVProfilerPass(Options));
if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
MPM->add(createStripSymbolsPass(true));
}
@@ -381,14 +433,14 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
}
// Set FP fusion mode.
- switch (LangOpts.getFPContractMode()) {
- case LangOptions::FPC_Off:
+ switch (CodeGenOpts.getFPContractMode()) {
+ case CodeGenOptions::FPC_Off:
Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
break;
- case LangOptions::FPC_On:
+ case CodeGenOptions::FPC_On:
Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
break;
- case LangOptions::FPC_Fast:
+ case CodeGenOptions::FPC_Fast:
Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
break;
}
@@ -405,6 +457,7 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
Options.SSPBufferSize = CodeGenOpts.SSPBufferSize;
+ Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
@@ -438,9 +491,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
TLI->disableAllFunctions();
PM->add(TLI);
- // Add TargetTransformInfo.
- PM->add(new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo()));
+ // Add Target specific analysis passes.
+ TM->addAnalysisPasses(*PM);
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
@@ -476,6 +528,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
Action != Backend_EmitBC &&
Action != Backend_EmitLL);
TargetMachine *TM = CreateTargetMachine(UsesCodeGen);
+ if (UsesCodeGen && !TM) return;
CreatePasses(TM);
switch (Action) {
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
new file mode 100644
index 000000000000..817d5c4cc687
--- /dev/null
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -0,0 +1,942 @@
+//===--- CGAtomic.cpp - Emit LLVM IR for atomic operations ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the code for emitting atomic operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CGCall.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Operator.h"
+
+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;
+ QualType AtomicTy;
+ QualType ValueTy;
+ uint64_t AtomicSizeInBits;
+ uint64_t ValueSizeInBits;
+ CharUnits AtomicAlign;
+ CharUnits ValueAlign;
+ CharUnits LValueAlign;
+ TypeEvaluationKind EvaluationKind;
+ bool UseLibcall;
+ public:
+ AtomicInfo(CodeGenFunction &CGF, LValue &lvalue) : CGF(CGF) {
+ assert(lvalue.isSimple());
+
+ AtomicTy = lvalue.getType();
+ ValueTy = AtomicTy->castAs<AtomicType>()->getValueType();
+ EvaluationKind = CGF.getEvaluationKind(ValueTy);
+
+ ASTContext &C = CGF.getContext();
+
+ uint64_t valueAlignInBits;
+ llvm::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
+
+ uint64_t atomicAlignInBits;
+ llvm::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
+
+ assert(ValueSizeInBits <= AtomicSizeInBits);
+ assert(valueAlignInBits <= atomicAlignInBits);
+
+ AtomicAlign = C.toCharUnitsFromBits(atomicAlignInBits);
+ ValueAlign = C.toCharUnitsFromBits(valueAlignInBits);
+ if (lvalue.getAlignment().isZero())
+ lvalue.setAlignment(AtomicAlign);
+
+ UseLibcall =
+ (AtomicSizeInBits > uint64_t(C.toBits(lvalue.getAlignment())) ||
+ AtomicSizeInBits > C.getTargetInfo().getMaxAtomicInlineWidth());
+ }
+
+ QualType getAtomicType() const { return AtomicTy; }
+ QualType getValueType() const { return ValueTy; }
+ CharUnits getAtomicAlignment() const { return AtomicAlign; }
+ CharUnits getValueAlignment() const { return ValueAlign; }
+ uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
+ uint64_t getValueSizeInBits() const { return AtomicSizeInBits; }
+ TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
+ bool shouldUseLibcall() const { return UseLibcall; }
+
+ /// Is the atomic size larger than the underlying value type?
+ ///
+ /// Note that the absence of padding does not mean that atomic
+ /// objects are completely interchangeable with non-atomic
+ /// objects: we might have promoted the alignment of a type
+ /// without making it bigger.
+ bool hasPadding() const {
+ return (ValueSizeInBits != AtomicSizeInBits);
+ }
+
+ void emitMemSetZeroIfNecessary(LValue dest) const;
+
+ llvm::Value *getAtomicSizeValue() const {
+ CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
+ return CGF.CGM.getSize(size);
+ }
+
+ /// Cast the given pointer to an integer pointer suitable for
+ /// atomic operations.
+ llvm::Value *emitCastToAtomicIntPointer(llvm::Value *addr) const;
+
+ /// Turn an atomic-layout object into an r-value.
+ RValue convertTempToRValue(llvm::Value *addr,
+ AggValueSlot resultSlot) const;
+
+ /// Copy an atomic r-value into atomic-layout memory.
+ void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const;
+
+ /// Project an l-value down to the value field.
+ LValue projectValue(LValue lvalue) const {
+ llvm::Value *addr = lvalue.getAddress();
+ if (hasPadding())
+ addr = CGF.Builder.CreateStructGEP(addr, 0);
+
+ return LValue::MakeAddr(addr, getValueType(), lvalue.getAlignment(),
+ CGF.getContext(), lvalue.getTBAAInfo());
+ }
+
+ /// Materialize an atomic r-value in atomic-layout memory.
+ llvm::Value *materializeRValue(RValue rvalue) const;
+
+ private:
+ bool requiresMemSetZero(llvm::Type *type) const;
+ };
+}
+
+static RValue emitAtomicLibcall(CodeGenFunction &CGF,
+ StringRef fnName,
+ QualType resultType,
+ CallArgList &args) {
+ const CGFunctionInfo &fnInfo =
+ CGF.CGM.getTypes().arrangeFreeFunctionCall(resultType, args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
+ llvm::Constant *fn = CGF.CGM.CreateRuntimeFunction(fnTy, fnName);
+ return CGF.EmitCall(fnInfo, fn, ReturnValueSlot(), args);
+}
+
+/// Does a store of the given IR type modify the full expected width?
+static bool isFullSizeType(CodeGenModule &CGM, llvm::Type *type,
+ uint64_t expectedSize) {
+ return (CGM.getDataLayout().getTypeStoreSize(type) * 8 == expectedSize);
+}
+
+/// Does the atomic type require memsetting to zero before initialization?
+///
+/// The IR type is provided as a way of making certain queries faster.
+bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
+ // If the atomic type has size padding, we definitely need a memset.
+ if (hasPadding()) return true;
+
+ // Otherwise, do some simple heuristics to try to avoid it:
+ switch (getEvaluationKind()) {
+ // For scalars and complexes, check whether the store size of the
+ // type uses the full size.
+ case TEK_Scalar:
+ return !isFullSizeType(CGF.CGM, type, AtomicSizeInBits);
+ case TEK_Complex:
+ return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
+ AtomicSizeInBits / 2);
+
+ // Just be pessimistic about aggregates.
+ case TEK_Aggregate:
+ return true;
+ }
+ llvm_unreachable("bad evaluation kind");
+}
+
+void AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const {
+ llvm::Value *addr = dest.getAddress();
+ if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
+ return;
+
+ CGF.Builder.CreateMemSet(addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
+ AtomicSizeInBits / 8,
+ dest.getAlignment().getQuantity());
+}
+
+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) {
+ llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
+ llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ 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()));
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ case AtomicExpr::AO__atomic_load: {
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
+ Load->setAtomic(Order);
+ Load->setAlignment(Size);
+ Load->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
+ StoreDest->setAlignment(Align);
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n: {
+ assert(!Dest && "Store does not return a value");
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
+ Store->setAtomic(Order);
+ Store->setAlignment(Size);
+ Store->setVolatile(E->isVolatile());
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ Op = llvm::AtomicRMWInst::Xchg;
+ break;
+
+ case AtomicExpr::AO__atomic_add_fetch:
+ PostOp = llvm::Instruction::Add;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ Op = llvm::AtomicRMWInst::Add;
+ break;
+
+ case AtomicExpr::AO__atomic_sub_fetch:
+ PostOp = llvm::Instruction::Sub;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ Op = llvm::AtomicRMWInst::Sub;
+ break;
+
+ case AtomicExpr::AO__atomic_and_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ Op = llvm::AtomicRMWInst::And;
+ break;
+
+ case AtomicExpr::AO__atomic_or_fetch:
+ PostOp = llvm::Instruction::Or;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ Op = llvm::AtomicRMWInst::Or;
+ break;
+
+ case AtomicExpr::AO__atomic_xor_fetch:
+ PostOp = llvm::Instruction::Xor;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ Op = llvm::AtomicRMWInst::Xor;
+ break;
+
+ case AtomicExpr::AO__atomic_nand_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_nand:
+ Op = llvm::AtomicRMWInst::Nand;
+ break;
+ }
+
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::AtomicRMWInst *RMWI =
+ CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
+ RMWI->setVolatile(E->isVolatile());
+
+ // For __atomic_*_fetch operations, perform the operation again to
+ // determine the value which was written.
+ llvm::Value *Result = RMWI;
+ if (PostOp)
+ Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
+ if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
+ Result = CGF.Builder.CreateNot(Result);
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
+ StoreDest->setAlignment(Align);
+}
+
+// This function emits any expression (scalar, complex, or aggregate)
+// into a temporary alloca.
+static llvm::Value *
+EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
+ llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
+ CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
+ /*Init*/ true);
+ return DeclPtr;
+}
+
+RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
+ QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
+ QualType MemTy = AtomicTy;
+ if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
+ MemTy = AT->getValueType();
+ CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidthInBits =
+ getContext().getTargetInfo().getMaxAtomicInlineWidth();
+ bool UseLibcall = (Size != Align ||
+ getContext().toBits(sizeChars) > MaxInlineWidthInBits);
+
+ llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
+ 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);
+ }
+
+ Order = EmitScalarExpr(E->getOrder());
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ break;
+
+ case AtomicExpr::AO__atomic_load:
+ Dest = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_store:
+ Val1 = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ Dest = EmitScalarExpr(E->getVal2());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
+ Val2 = EmitScalarExpr(E->getVal2());
+ else
+ Val2 = EmitValToTemp(*this, E->getVal2());
+ OrderFail = EmitScalarExpr(E->getOrderFail());
+ // Evaluate and discard the 'weak' argument.
+ if (E->getNumSubExprs() == 6)
+ EmitScalarExpr(E->getWeak());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ if (MemTy->isPointerType()) {
+ // For pointer arithmetic, we're required to do a bit of math:
+ // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
+ // ... but only for the C11 builtins. The GNU builtins expect the
+ // user to multiply by sizeof(T).
+ QualType Val1Ty = E->getVal1()->getType();
+ llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
+ CharUnits PointeeIncAmt =
+ getContext().getTypeSizeInChars(MemTy->getPointeeType());
+ Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
+ Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
+ EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
+ break;
+ }
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_add_fetch:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_store_n:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_and_fetch:
+ case AtomicExpr::AO__atomic_or_fetch:
+ case AtomicExpr::AO__atomic_xor_fetch:
+ case AtomicExpr::AO__atomic_nand_fetch:
+ Val1 = EmitValToTemp(*this, E->getVal1());
+ break;
+ }
+
+ if (!E->getType()->isVoidType() && !Dest)
+ Dest = CreateMemTemp(E->getType(), ".atomicdst");
+
+ // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
+ if (UseLibcall) {
+
+ SmallVector<QualType, 5> Params;
+ CallArgList Args;
+ // Size is always the first parameter
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ // Atomic address is always the second parameter
+ Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
+ getContext().VoidPtrTy);
+
+ const char* LibCallName;
+ QualType RetTy = getContext().VoidTy;
+ switch (E->getOp()) {
+ // There is only one libcall for compare an exchange, because there is no
+ // optimisation benefit possible from a libcall version of a weak compare
+ // and exchange.
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure)
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ LibCallName = "__atomic_compare_exchange";
+ RetTy = getContext().BoolTy;
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+ Order = OrderFail;
+ break;
+ // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
+ // int order)
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ LibCallName = "__atomic_exchange";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n:
+ LibCallName = "__atomic_store";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_load(size_t size, void *mem, void *return, int order)
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ LibCallName = "__atomic_load";
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+#if 0
+ // These are only defined for 1-16 byte integers. It is not clear what
+ // their semantics would be on anything else...
+ case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
+ case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
+ case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
+ case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
+ case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
+#endif
+ default: return EmitUnsupportedRValue(E, "atomic library call");
+ }
+ // order is always the last parameter
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
+ RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
+ if (E->isCmpXChg())
+ return Res;
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(Dest, E->getType());
+ }
+
+ bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store_n;
+ bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load_n;
+
+ llvm::Type *IPtrTy =
+ llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
+ llvm::Value *OrigDest = Dest;
+ Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
+ if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
+ if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
+ if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
+
+ 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);
+ break;
+ case AO_ABI_memory_order_consume:
+ case 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);
+ break;
+ case 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);
+ break;
+ case 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);
+ break;
+ case AO_ABI_memory_order_seq_cst:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ break;
+ default: // invalid order
+ // We should not ever get here normally, but it's hard to
+ // enforce that in general.
+ break;
+ }
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(OrigDest, E->getType());
+ }
+
+ // 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;
+ MonotonicBB = createBasicBlock("monotonic", CurFn);
+ if (!IsStore)
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ if (!IsLoad)
+ ReleaseBB = createBasicBlock("release", CurFn);
+ if (!IsLoad && !IsStore)
+ AcqRelBB = createBasicBlock("acqrel", CurFn);
+ SeqCstBB = createBasicBlock("seqcst", CurFn);
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ // Create the switch for the split
+ // 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.
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
+
+ // Emit all the different atomics
+ Builder.SetInsertPoint(MonotonicBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ Builder.CreateBr(ContBB);
+ if (!IsStore) {
+ Builder.SetInsertPoint(AcquireBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(1), AcquireBB);
+ SI->addCase(Builder.getInt32(2), AcquireBB);
+ }
+ if (!IsLoad) {
+ Builder.SetInsertPoint(ReleaseBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+ }
+ if (!IsLoad && !IsStore) {
+ Builder.SetInsertPoint(AcqRelBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(4), AcqRelBB);
+ }
+ Builder.SetInsertPoint(SeqCstBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(5), SeqCstBB);
+
+ // Cleanup and return
+ Builder.SetInsertPoint(ContBB);
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(OrigDest, E->getType());
+}
+
+llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const {
+ unsigned addrspace =
+ cast<llvm::PointerType>(addr->getType())->getAddressSpace();
+ llvm::IntegerType *ty =
+ llvm::IntegerType::get(CGF.getLLVMContext(), AtomicSizeInBits);
+ return CGF.Builder.CreateBitCast(addr, ty->getPointerTo(addrspace));
+}
+
+RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
+ AggValueSlot resultSlot) const {
+ if (EvaluationKind == TEK_Aggregate) {
+ // Nothing to do if the result is ignored.
+ if (resultSlot.isIgnored()) return resultSlot.asRValue();
+
+ assert(resultSlot.getAddr() == addr || hasPadding());
+
+ // In these cases, we should have emitted directly into the result slot.
+ if (!hasPadding() || resultSlot.isValueOfAtomic())
+ return resultSlot.asRValue();
+
+ // Otherwise, fall into the common path.
+ }
+
+ // Drill into the padding structure if we have one.
+ if (hasPadding())
+ addr = CGF.Builder.CreateStructGEP(addr, 0);
+
+ // If we're emitting to an aggregate, copy into the result slot.
+ if (EvaluationKind == TEK_Aggregate) {
+ CGF.EmitAggregateCopy(resultSlot.getAddr(), addr, getValueType(),
+ resultSlot.isVolatile());
+ return resultSlot.asRValue();
+ }
+
+ // Otherwise, just convert the temporary to an r-value using the
+ // normal conversion routine.
+ return CGF.convertTempToRValue(addr, getValueType());
+}
+
+/// Emit a load from an l-value of atomic type. Note that the r-value
+/// we produce is an r-value of the atomic *value* type.
+RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
+ AtomicInfo atomics(*this, src);
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ llvm::Value *tempAddr;
+ if (resultSlot.isValueOfAtomic()) {
+ assert(atomics.getEvaluationKind() == TEK_Aggregate);
+ tempAddr = resultSlot.getPaddedAtomicAddr();
+ } else if (!resultSlot.isIgnored() && !atomics.hasPadding()) {
+ assert(atomics.getEvaluationKind() == TEK_Aggregate);
+ tempAddr = resultSlot.getAddr();
+ } else {
+ tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
+ }
+
+ // void __atomic_load(size_t size, void *mem, void *return, int order);
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(src.getAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(tempAddr)),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(IntTy,
+ AO_ABI_memory_order_seq_cst)),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args);
+
+ // Produce the r-value.
+ return atomics.convertTempToRValue(tempAddr, resultSlot);
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *addr = atomics.emitCastToAtomicIntPointer(src.getAddress());
+ llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load");
+ load->setAtomic(llvm::SequentiallyConsistent);
+
+ // Other decoration.
+ load->setAlignment(src.getAlignment().getQuantity());
+ if (src.isVolatileQualified())
+ load->setVolatile(true);
+ if (src.getTBAAInfo())
+ CGM.DecorateInstruction(load, src.getTBAAInfo());
+
+ // Okay, turn that back into the original value type.
+ QualType valueType = atomics.getValueType();
+ llvm::Value *result = load;
+
+ // If we're ignoring an aggregate return, don't do anything.
+ if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
+ return RValue::getAggregate(0, false);
+
+ // The easiest way to do this this is to go through memory, but we
+ // try not to in some easy cases.
+ if (atomics.getEvaluationKind() == TEK_Scalar && !atomics.hasPadding()) {
+ llvm::Type *resultTy = CGM.getTypes().ConvertTypeForMem(valueType);
+ if (isa<llvm::IntegerType>(resultTy)) {
+ assert(result->getType() == resultTy);
+ result = EmitFromMemory(result, valueType);
+ } else if (isa<llvm::PointerType>(resultTy)) {
+ result = Builder.CreateIntToPtr(result, resultTy);
+ } else {
+ result = Builder.CreateBitCast(result, resultTy);
+ }
+ return RValue::get(result);
+ }
+
+ // Create a temporary. This needs to be big enough to hold the
+ // atomic integer.
+ llvm::Value *temp;
+ bool tempIsVolatile = false;
+ CharUnits tempAlignment;
+ if (atomics.getEvaluationKind() == TEK_Aggregate &&
+ (!atomics.hasPadding() || resultSlot.isValueOfAtomic())) {
+ assert(!resultSlot.isIgnored());
+ if (resultSlot.isValueOfAtomic()) {
+ temp = resultSlot.getPaddedAtomicAddr();
+ tempAlignment = atomics.getAtomicAlignment();
+ } else {
+ temp = resultSlot.getAddr();
+ tempAlignment = atomics.getValueAlignment();
+ }
+ tempIsVolatile = resultSlot.isVolatile();
+ } else {
+ temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
+ tempAlignment = atomics.getAtomicAlignment();
+ }
+
+ // Slam the integer into the temporary.
+ llvm::Value *castTemp = atomics.emitCastToAtomicIntPointer(temp);
+ Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity())
+ ->setVolatile(tempIsVolatile);
+
+ return atomics.convertTempToRValue(temp, resultSlot);
+}
+
+
+
+/// Copy an r-value into memory as part of storing to an atomic type.
+/// This needs to create a bit-pattern suitable for atomic operations.
+void AtomicInfo::emitCopyIntoMemory(RValue rvalue, LValue dest) const {
+ // If we have an r-value, the rvalue should be of the atomic type,
+ // which means that the caller is responsible for having zeroed
+ // any padding. Just do an aggregate copy of that type.
+ if (rvalue.isAggregate()) {
+ CGF.EmitAggregateCopy(dest.getAddress(),
+ rvalue.getAggregateAddr(),
+ getAtomicType(),
+ (rvalue.isVolatileQualified()
+ || dest.isVolatileQualified()),
+ dest.getAlignment());
+ return;
+ }
+
+ // Okay, otherwise we're copying stuff.
+
+ // Zero out the buffer if necessary.
+ emitMemSetZeroIfNecessary(dest);
+
+ // Drill past the padding if present.
+ dest = projectValue(dest);
+
+ // Okay, store the rvalue in.
+ if (rvalue.isScalar()) {
+ CGF.EmitStoreOfScalar(rvalue.getScalarVal(), dest, /*init*/ true);
+ } else {
+ CGF.EmitStoreOfComplex(rvalue.getComplexVal(), dest, /*init*/ true);
+ }
+}
+
+
+/// Materialize an r-value into memory for the purposes of storing it
+/// to an atomic type.
+llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const {
+ // Aggregate r-values are already in memory, and EmitAtomicStore
+ // requires them to be values of the atomic type.
+ if (rvalue.isAggregate())
+ return rvalue.getAggregateAddr();
+
+ // Otherwise, make a temporary and materialize into it.
+ llvm::Value *temp = CGF.CreateMemTemp(getAtomicType(), "atomic-store-temp");
+ LValue tempLV = CGF.MakeAddrLValue(temp, getAtomicType(), getAtomicAlignment());
+ emitCopyIntoMemory(rvalue, tempLV);
+ return temp;
+}
+
+/// Emit a store to an l-value of atomic type.
+///
+/// Note that the r-value is expected to be an r-value *of the atomic
+/// type*; this means that for aggregate r-values, it should include
+/// storage for any padding that was necessary.
+void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
+ bool isInit) {
+ // If this is an aggregate r-value, it should agree in type except
+ // maybe for address-space qualification.
+ assert(!rvalue.isAggregate() ||
+ rvalue.getAggregateAddr()->getType()->getPointerElementType()
+ == dest.getAddress()->getType()->getPointerElementType());
+
+ AtomicInfo atomics(*this, dest);
+
+ // If this is an initialization, just put the value there normally.
+ if (isInit) {
+ atomics.emitCopyIntoMemory(rvalue, dest);
+ return;
+ }
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ // Produce a source address.
+ llvm::Value *srcAddr = atomics.materializeRValue(rvalue);
+
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(dest.getAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(srcAddr)),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(IntTy,
+ AO_ABI_memory_order_seq_cst)),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
+ return;
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *intValue;
+
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ if (rvalue.isScalar() && !atomics.hasPadding()) {
+ llvm::Value *value = rvalue.getScalarVal();
+ if (isa<llvm::IntegerType>(value->getType())) {
+ intValue = value;
+ } else {
+ llvm::IntegerType *inputIntTy =
+ llvm::IntegerType::get(getLLVMContext(), atomics.getValueSizeInBits());
+ if (isa<llvm::PointerType>(value->getType())) {
+ intValue = Builder.CreatePtrToInt(value, inputIntTy);
+ } else {
+ intValue = Builder.CreateBitCast(value, inputIntTy);
+ }
+ }
+
+ // Otherwise, we need to go through memory.
+ } else {
+ // Put the r-value in memory.
+ llvm::Value *addr = atomics.materializeRValue(rvalue);
+
+ // Cast the temporary to the atomic int type and pull a value out.
+ addr = atomics.emitCastToAtomicIntPointer(addr);
+ intValue = Builder.CreateAlignedLoad(addr,
+ atomics.getAtomicAlignment().getQuantity());
+ }
+
+ // Do the atomic store.
+ llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress());
+ llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
+
+ // Initializations don't need to be atomic.
+ if (!isInit) store->setAtomic(llvm::SequentiallyConsistent);
+
+ // Other decoration.
+ store->setAlignment(dest.getAlignment().getQuantity());
+ if (dest.isVolatileQualified())
+ store->setVolatile(true);
+ if (dest.getTBAAInfo())
+ CGM.DecorateInstruction(store, dest.getTBAAInfo());
+}
+
+void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
+ AtomicInfo atomics(*this, dest);
+
+ switch (atomics.getEvaluationKind()) {
+ case TEK_Scalar: {
+ llvm::Value *value = EmitScalarExpr(init);
+ atomics.emitCopyIntoMemory(RValue::get(value), dest);
+ return;
+ }
+
+ case TEK_Complex: {
+ ComplexPairTy value = EmitComplexExpr(init);
+ atomics.emitCopyIntoMemory(RValue::getComplex(value), dest);
+ return;
+ }
+
+ case TEK_Aggregate: {
+ // Memset the buffer first if there's any possibility of
+ // uninitialized internal bits.
+ atomics.emitMemSetZeroIfNecessary(dest);
+
+ // HACK: whether the initializer actually has an atomic type
+ // doesn't really seem reliable right now.
+ if (!init->getType()->isAtomicType()) {
+ dest = atomics.projectValue(dest);
+ }
+
+ // Evaluate the expression directly into the destination.
+ AggValueSlot slot = AggValueSlot::forLValue(dest,
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ EmitAggExpr(init, slot);
+ return;
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
+}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 6742f36cf80f..227ee2d024c6 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -11,16 +11,18 @@
//
//===----------------------------------------------------------------------===//
+#include "CGBlocks.h"
#include "CGDebugInfo.h"
-#include "CodeGenFunction.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "CGBlocks.h"
#include "clang/AST/DeclObjC.h"
-#include "llvm/Module.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CallSite.h"
#include <algorithm>
+#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -181,13 +183,16 @@ namespace {
struct BlockLayoutChunk {
CharUnits Alignment;
CharUnits Size;
+ Qualifiers::ObjCLifetime Lifetime;
const BlockDecl::Capture *Capture; // null for 'this'
llvm::Type *Type;
BlockLayoutChunk(CharUnits align, CharUnits size,
+ Qualifiers::ObjCLifetime lifetime,
const BlockDecl::Capture *capture,
llvm::Type *type)
- : Alignment(align), Size(size), Capture(capture), Type(type) {}
+ : Alignment(align), Size(size), Lifetime(lifetime),
+ Capture(capture), Type(type) {}
/// Tell the block info that this chunk has the given field index.
void setIndex(CGBlockInfo &info, unsigned index) {
@@ -199,9 +204,35 @@ namespace {
}
};
- /// Order by descending alignment.
+ /// Order by 1) all __strong together 2) next, all byfref together 3) next,
+ /// all __weak together. Preserve descending alignment in all situations.
bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) {
- return left.Alignment > right.Alignment;
+ CharUnits LeftValue, RightValue;
+ bool LeftByref = left.Capture ? left.Capture->isByRef() : false;
+ bool RightByref = right.Capture ? right.Capture->isByRef() : false;
+
+ if (left.Lifetime == Qualifiers::OCL_Strong &&
+ left.Alignment >= right.Alignment)
+ LeftValue = CharUnits::fromQuantity(64);
+ else if (LeftByref && left.Alignment >= right.Alignment)
+ LeftValue = CharUnits::fromQuantity(32);
+ else if (left.Lifetime == Qualifiers::OCL_Weak &&
+ left.Alignment >= right.Alignment)
+ LeftValue = CharUnits::fromQuantity(16);
+ else
+ LeftValue = left.Alignment;
+ if (right.Lifetime == Qualifiers::OCL_Strong &&
+ right.Alignment >= left.Alignment)
+ RightValue = CharUnits::fromQuantity(64);
+ else if (RightByref && right.Alignment >= left.Alignment)
+ RightValue = CharUnits::fromQuantity(32);
+ else if (right.Lifetime == Qualifiers::OCL_Weak &&
+ right.Alignment >= left.Alignment)
+ RightValue = CharUnits::fromQuantity(16);
+ else
+ RightValue = right.Alignment;
+
+ return LeftValue > RightValue;
}
}
@@ -217,7 +248,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
// Maintain semantics for classes with non-trivial dtors or copy ctors.
if (!record->hasTrivialDestructor()) return false;
- if (!record->hasTrivialCopyConstructor()) return false;
+ if (record->hasNonTrivialCopyConstructor()) return false;
// Otherwise, we just have to make sure there aren't any mutable
// fields that might have changed since initialization.
@@ -336,7 +367,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
= CGM.getContext().getTypeInfoInChars(thisType);
maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
- layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first, 0, llvmType));
+ layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first,
+ Qualifiers::OCL_None,
+ 0, llvmType));
}
// Next, all the block captures.
@@ -357,6 +390,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));
continue;
}
@@ -370,8 +404,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// If we have a lifetime qualifier, honor it for capture purposes.
// That includes *not* copying it if it's __unsafe_unretained.
- if (Qualifiers::ObjCLifetime lifetime
- = variable->getType().getObjCLifetime()) {
+ Qualifiers::ObjCLifetime lifetime =
+ variable->getType().getObjCLifetime();
+ if (lifetime) {
switch (lifetime) {
case Qualifiers::OCL_None: llvm_unreachable("impossible");
case Qualifiers::OCL_ExplicitNone:
@@ -386,6 +421,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// Block pointers require copy/dispose. So do Objective-C pointers.
} else if (variable->getType()->isObjCRetainableType()) {
info.NeedsCopyDispose = true;
+ // used for mrr below.
+ lifetime = Qualifiers::OCL_Strong;
// So do types that require non-trivial copy construction.
} else if (ci->hasCopyExpr()) {
@@ -412,7 +449,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
llvm::Type *llvmType =
CGM.getTypes().ConvertTypeForMem(VT);
- layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType));
+ layout.push_back(BlockLayoutChunk(align, size, lifetime, &*ci, llvmType));
}
// If that was everything, we're done here.
@@ -427,7 +464,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// to get reproducible results. There should probably be an
// llvm::array_pod_stable_sort.
std::stable_sort(layout.begin(), layout.end());
-
+
+ // Needed for blocks layout info.
+ info.BlockHeaderForcedGapOffset = info.BlockSize;
+ info.BlockHeaderForcedGapSize = CharUnits::Zero();
+
CharUnits &blockSize = info.BlockSize;
info.BlockAlign = std::max(maxFieldAlign, info.BlockAlign);
@@ -468,17 +509,22 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
endAlign = getLowBit(blockSize);
// ...until we get to the alignment of the maximum field.
- if (endAlign >= maxFieldAlign)
+ if (endAlign >= maxFieldAlign) {
+ if (li == first) {
+ // No user field was appended. So, a gap was added.
+ // Save total gap size for use in block layout bit map.
+ info.BlockHeaderForcedGapSize = li->Size;
+ }
break;
+ }
}
-
// Don't re-append everything we just appended.
layout.erase(first, li);
}
}
assert(endAlign == getLowBit(blockSize));
-
+
// At this point, we just have to add padding if the end align still
// isn't aligned right.
if (endAlign < maxFieldAlign) {
@@ -493,7 +539,6 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
assert(endAlign >= maxFieldAlign);
assert(endAlign == getLowBit(blockSize));
-
// Slam everything else on now. This works because they have
// strictly decreasing alignment and we expect that size is always a
// multiple of alignment.
@@ -732,8 +777,16 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// special; we'll simply emit it directly.
src = 0;
} else {
- // This is a [[type]]*.
- src = LocalDeclMap[variable];
+ // 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,
+ VK_LValue, SourceLocation());
+ src = EmitDeclRefLValue(&declRef).getAddress();
+ }
}
// For byrefs, we just write the pointer to the byref struct into
@@ -896,7 +949,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
const FunctionType *FuncTy = FnType->castAs<FunctionType>();
const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeFreeFunctionCall(Args, FuncTy);
+ CGM.getTypes().arrangeBlockFunctionCall(Args, FuncTy);
// Cast the function pointer to the right type.
llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo);
@@ -1085,6 +1138,24 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
BlockPointer = Builder.CreateBitCast(blockAddr,
blockInfo.StructureType->getPointerTo(),
"block");
+ // At -O0 we generate an explicit alloca for the BlockPointer, so the RA
+ // won't delete the dbg.declare intrinsics for captured variables.
+ llvm::Value *BlockPointerDbgLoc = BlockPointer;
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ // Allocate a stack slot for it, so we can point the debugger to it
+ llvm::AllocaInst *Alloca = CreateTempAlloca(BlockPointer->getType(),
+ "block.addr");
+ unsigned Align = getContext().getDeclAlign(&selfDecl).getQuantity();
+ Alloca->setAlignment(Align);
+ // Set the DebugLocation to empty, so the store is recognized as a
+ // frame setup instruction by llvm::DwarfDebug::beginFunction().
+ llvm::DebugLoc Empty;
+ llvm::DebugLoc Loc = Builder.getCurrentDebugLocation();
+ Builder.SetCurrentDebugLocation(Empty);
+ Builder.CreateAlignedStore(BlockPointer, Alloca, Align);
+ Builder.SetCurrentDebugLocation(Loc);
+ BlockPointerDbgLoc = Alloca;
+ }
// If we have a C++ 'this' reference, go ahead and force it into
// existence now.
@@ -1104,6 +1175,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// There might not be a capture for 'self', but if there is...
if (blockInfo.Captures.count(self)) {
const CGBlockInfo::Capture &capture = blockInfo.getCapture(self);
+
llvm::Value *selfAddr = Builder.CreateStructGEP(BlockPointer,
capture.getIndex(),
"block.captured-self");
@@ -1124,7 +1196,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
CreateMemTemp(variable->getType(), "block.captured-const");
alloca->setAlignment(align);
- Builder.CreateStore(capture.getConstant(), alloca, align);
+ Builder.CreateAlignedStore(capture.getConstant(), alloca, align);
LocalDeclMap[variable] = alloca;
}
@@ -1163,10 +1235,13 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
continue;
}
- DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointer,
+ DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointerDbgLoc,
Builder, blockInfo);
}
}
+ // Recover location if it was changed in the above loop.
+ DI->EmitLocation(Builder,
+ cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc());
}
// And resume where we left off.
@@ -1199,7 +1274,14 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
*/
-
+/// Generate the copy-helper function for a block closure object:
+/// static void block_copy_helper(block_t *dst, block_t *src);
+/// The runtime will have previously initialized 'dst' by doing a
+/// bit-copy of 'src'.
+///
+/// Note that this copies an entire block closure object to the heap;
+/// it should not be confused with a 'byref copy helper', which moves
+/// the contents of an individual __block variable to the heap.
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@@ -1234,7 +1316,6 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false,
false);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -1344,8 +1425,24 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
} else {
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
- Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
- llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
+ llvm::Value *args[] = {
+ dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
+ };
+
+ bool copyCanThrow = false;
+ if (ci->isByRef() && variable->getType()->getAsCXXRecordDecl()) {
+ const Expr *copyExpr =
+ CGM.getContext().getBlockVarCopyInits(variable);
+ if (copyExpr) {
+ copyCanThrow = true; // FIXME: reuse the noexcept logic
+ }
+ }
+
+ if (copyCanThrow) {
+ EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
+ } else {
+ EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
+ }
}
}
}
@@ -1355,6 +1452,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
}
+/// Generate the destroy-helper function for a block closure object:
+/// static void block_destroy_helper(block_t *theBlock);
+///
+/// Note that this destroys a heap-allocated block closure object;
+/// it should not be confused with a 'byref destroy helper', which
+/// destroys the heap-allocated contents of an individual __block
+/// variable.
llvm::Constant *
CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@@ -1386,7 +1490,6 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false, false);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -1461,7 +1564,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
// Destroy strong objects with a call if requested.
} else if (useARCStrongDestroy) {
- EmitARCDestroyStrong(srcField, /*precise*/ false);
+ EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
@@ -1501,7 +1604,9 @@ public:
llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
- CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal);
+
+ llvm::Value *args[] = { destField, srcValue, flagsVal };
+ CGF.EmitNounwindRuntimeCall(fn, args);
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
@@ -1553,6 +1658,13 @@ public:
llvm::Value *null =
llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::StoreInst *store = CGF.Builder.CreateStore(null, destField);
+ store->setAlignment(Alignment.getQuantity());
+ CGF.EmitARCStoreStrongCall(destField, value, /*ignored*/ true);
+ CGF.EmitARCStoreStrongCall(srcField, null, /*ignored*/ true);
+ return;
+ }
llvm::StoreInst *store = CGF.Builder.CreateStore(value, destField);
store->setAlignment(Alignment.getQuantity());
@@ -1561,7 +1673,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1591,7 +1703,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1633,6 +1745,7 @@ public:
static llvm::Constant *
generateByrefCopyHelper(CodeGenFunction &CGF,
llvm::StructType &byrefType,
+ unsigned valueFieldIndex,
CodeGenModule::ByrefHelpers &byrefInfo) {
ASTContext &Context = CGF.getContext();
@@ -1667,7 +1780,6 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
- SC_None,
false, false);
// Initialize debug info if necessary.
@@ -1681,13 +1793,13 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
destField = CGF.Builder.CreateLoad(destField);
destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
- destField = CGF.Builder.CreateStructGEP(destField, 6, "x");
+ destField = CGF.Builder.CreateStructGEP(destField, valueFieldIndex, "x");
// src->x
llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src);
srcField = CGF.Builder.CreateLoad(srcField);
srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
- srcField = CGF.Builder.CreateStructGEP(srcField, 6, "x");
+ srcField = CGF.Builder.CreateStructGEP(srcField, valueFieldIndex, "x");
byrefInfo.emitCopy(CGF, destField, srcField);
}
@@ -1700,15 +1812,17 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
/// Build the copy helper for a __block variable.
static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
llvm::StructType &byrefType,
+ unsigned byrefValueIndex,
CodeGenModule::ByrefHelpers &info) {
CodeGenFunction CGF(CGM);
- return generateByrefCopyHelper(CGF, byrefType, info);
+ return generateByrefCopyHelper(CGF, byrefType, byrefValueIndex, info);
}
/// Generate code for a __block variable's dispose helper.
static llvm::Constant *
generateByrefDisposeHelper(CodeGenFunction &CGF,
llvm::StructType &byrefType,
+ unsigned byrefValueIndex,
CodeGenModule::ByrefHelpers &byrefInfo) {
ASTContext &Context = CGF.getContext();
QualType R = Context.VoidTy;
@@ -1740,7 +1854,6 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
- SC_None,
false, false);
// Initialize debug info if necessary.
CGF.maybeInitializeDebugInfo();
@@ -1750,7 +1863,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
V = CGF.Builder.CreateLoad(V);
V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0));
- V = CGF.Builder.CreateStructGEP(V, 6, "x");
+ V = CGF.Builder.CreateStructGEP(V, byrefValueIndex, "x");
byrefInfo.emitDispose(CGF, V);
}
@@ -1763,14 +1876,17 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
/// Build the dispose helper for a __block variable.
static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
llvm::StructType &byrefType,
+ unsigned byrefValueIndex,
CodeGenModule::ByrefHelpers &info) {
CodeGenFunction CGF(CGM);
- return generateByrefDisposeHelper(CGF, byrefType, info);
+ return generateByrefDisposeHelper(CGF, byrefType, byrefValueIndex, info);
}
-///
+/// Lazily build the copy and dispose helpers for a __block variable
+/// with the given information.
template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
llvm::StructType &byrefTy,
+ unsigned byrefValueIndex,
T &byrefInfo) {
// Increase the field's alignment to be at least pointer alignment,
// since the layout of the byref struct will guarantee at least that.
@@ -1785,26 +1901,33 @@ template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
= CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos);
if (node) return static_cast<T*>(node);
- byrefInfo.CopyHelper = buildByrefCopyHelper(CGM, byrefTy, byrefInfo);
- byrefInfo.DisposeHelper = buildByrefDisposeHelper(CGM, byrefTy, byrefInfo);
+ byrefInfo.CopyHelper =
+ buildByrefCopyHelper(CGM, byrefTy, byrefValueIndex, byrefInfo);
+ byrefInfo.DisposeHelper =
+ buildByrefDisposeHelper(CGM, byrefTy, byrefValueIndex,byrefInfo);
T *copy = new (CGM.getContext()) T(byrefInfo);
CGM.ByrefHelpersCache.InsertNode(copy, insertPos);
return copy;
}
+/// Build the copy and dispose helpers for the given __block variable
+/// emission. Places the helpers in the global cache. Returns null
+/// if no helpers are required.
CodeGenModule::ByrefHelpers *
CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
const AutoVarEmission &emission) {
const VarDecl &var = *emission.Variable;
QualType type = var.getType();
+ unsigned byrefValueIndex = getByRefValueLLVMField(&var);
+
if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
if (!copyExpr && record->hasTrivialDestructor()) return 0;
CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
// Otherwise, if we don't have a retainable type, there's nothing to do.
@@ -1829,7 +1952,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// byref routines.
case Qualifiers::OCL_Weak: {
ARCWeakByrefHelpers byrefInfo(emission.Alignment);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
// ARC __strong __block variables need to be retained.
@@ -1838,13 +1961,13 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// transfer possible.
if (type->isBlockPointerType()) {
ARCStrongBlockByrefHelpers byrefInfo(emission.Alignment);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
// Otherwise, we transfer ownership of the retain from the stack
// to the heap.
} else {
ARCStrongByrefHelpers byrefInfo(emission.Alignment);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
}
llvm_unreachable("fell out of lifetime switch!");
@@ -1864,7 +1987,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
flags |= BLOCK_FIELD_IS_WEAK;
ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
@@ -1892,6 +2015,7 @@ llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
/// int32_t __size;
/// void *__copy_helper; // only if needed
/// void *__destroy_helper; // only if needed
+/// void *__byref_variable_layout;// only if needed
/// char padding[X]; // only if needed
/// T x;
/// } x
@@ -1920,9 +2044,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// int32_t __size;
types.push_back(Int32Ty);
-
- bool HasCopyAndDispose =
- (Ty->isObjCRetainableType()) || getContext().getBlockVarCopyInits(D);
+ // Note that this must match *exactly* the logic in buildByrefHelpers.
+ bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty, D);
if (HasCopyAndDispose) {
/// void *__copy_helper;
types.push_back(Int8PtrTy);
@@ -1930,6 +2053,12 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
/// void *__destroy_helper;
types.push_back(Int8PtrTy);
}
+ bool HasByrefExtendedLayout = false;
+ Qualifiers::ObjCLifetime Lifetime;
+ if (getContext().getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout) &&
+ HasByrefExtendedLayout)
+ /// void *__byref_variable_layout;
+ types.push_back(Int8PtrTy);
bool Packed = false;
CharUnits Align = getContext().getDeclAlign(D);
@@ -1939,9 +2068,14 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// The struct above has 2 32-bit integers.
unsigned CurrentOffsetInBytes = 4 * 2;
- // And either 2 or 4 pointers.
- CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
- CGM.getDataLayout().getTypeAllocSize(Int8PtrTy);
+ // And either 2, 3, 4 or 5 pointers.
+ unsigned noPointers = 2;
+ if (HasCopyAndDispose)
+ noPointers += 2;
+ if (HasByrefExtendedLayout)
+ noPointers += 1;
+
+ CurrentOffsetInBytes += noPointers * CGM.getDataLayout().getTypeAllocSize(Int8PtrTy);
// Align the offset.
unsigned AlignedOffsetInBytes =
@@ -1991,6 +2125,11 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
QualType type = D.getType();
+ bool HasByrefExtendedLayout;
+ Qualifiers::ObjCLifetime ByrefLifetime;
+ bool ByRefHasLifetime =
+ getContext().getByrefLifetime(type, ByrefLifetime, HasByrefExtendedLayout);
+
llvm::Value *V;
// Initialize the 'isa', which is just 0 or 1.
@@ -2006,9 +2145,49 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
// Blocks ABI:
// c) the flags field is set to either 0 if no helper functions are
- // needed or BLOCK_HAS_COPY_DISPOSE if they are,
+ // needed or BLOCK_BYREF_HAS_COPY_DISPOSE if they are,
BlockFlags flags;
- if (helpers) flags |= BLOCK_HAS_COPY_DISPOSE;
+ if (helpers) flags |= BLOCK_BYREF_HAS_COPY_DISPOSE;
+ if (ByRefHasLifetime) {
+ if (HasByrefExtendedLayout) flags |= BLOCK_BYREF_LAYOUT_EXTENDED;
+ else switch (ByrefLifetime) {
+ case Qualifiers::OCL_Strong:
+ flags |= BLOCK_BYREF_LAYOUT_STRONG;
+ break;
+ case Qualifiers::OCL_Weak:
+ flags |= BLOCK_BYREF_LAYOUT_WEAK;
+ break;
+ case Qualifiers::OCL_ExplicitNone:
+ flags |= BLOCK_BYREF_LAYOUT_UNRETAINED;
+ break;
+ case Qualifiers::OCL_None:
+ if (!type->isObjCObjectPointerType() && !type->isBlockPointerType())
+ flags |= BLOCK_BYREF_LAYOUT_NON_OBJECT;
+ break;
+ default:
+ break;
+ }
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ printf("\n Inline flag for BYREF variable layout (%d):", flags.getBitMask());
+ if (flags & BLOCK_BYREF_HAS_COPY_DISPOSE)
+ printf(" BLOCK_BYREF_HAS_COPY_DISPOSE");
+ if (flags & BLOCK_BYREF_LAYOUT_MASK) {
+ BlockFlags ThisFlag(flags.getBitMask() & BLOCK_BYREF_LAYOUT_MASK);
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_EXTENDED)
+ printf(" BLOCK_BYREF_LAYOUT_EXTENDED");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_STRONG)
+ printf(" BLOCK_BYREF_LAYOUT_STRONG");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_WEAK)
+ printf(" BLOCK_BYREF_LAYOUT_WEAK");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_UNRETAINED)
+ printf(" BLOCK_BYREF_LAYOUT_UNRETAINED");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_NON_OBJECT)
+ printf(" BLOCK_BYREF_LAYOUT_NON_OBJECT");
+ }
+ printf("\n");
+ }
+ }
+
Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
Builder.CreateStructGEP(addr, 2, "byref.flags"));
@@ -2023,14 +2202,25 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
Builder.CreateStore(helpers->DisposeHelper, destroy_helper);
}
+ if (ByRefHasLifetime && HasByrefExtendedLayout) {
+ llvm::Constant* ByrefLayoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type);
+ llvm::Value *ByrefInfoAddr = Builder.CreateStructGEP(addr, helpers ? 6 : 4,
+ "byref.layout");
+ // cast destination to pointer to source type.
+ llvm::Type *DesTy = ByrefLayoutInfo->getType();
+ DesTy = DesTy->getPointerTo();
+ llvm::Value *BC = Builder.CreatePointerCast(ByrefInfoAddr, DesTy);
+ Builder.CreateStore(ByrefLayoutInfo, BC);
+ }
}
void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
llvm::Value *F = CGM.getBlockObjectDispose();
- llvm::Value *N;
- V = Builder.CreateBitCast(V, Int8PtrTy);
- N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
- Builder.CreateCall2(F, V, N);
+ llvm::Value *args[] = {
+ Builder.CreateBitCast(V, Int8PtrTy),
+ llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
+ };
+ EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors?
}
namespace {
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index f85701af781a..020638a55810 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -14,19 +14,18 @@
#ifndef CLANG_CODEGEN_CGBLOCKS_H
#define CLANG_CODEGEN_CGBLOCKS_H
+#include "CGBuilder.h"
+#include "CGCall.h"
+#include "CGValue.h"
+#include "CodeGenFunction.h"
#include "CodeGenTypes.h"
-#include "clang/AST/Type.h"
-#include "llvm/Module.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-
-#include "CodeGenFunction.h"
-#include "CGBuilder.h"
-#include "CGCall.h"
-#include "CGValue.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/IR/Module.h"
namespace llvm {
class Module;
@@ -69,11 +68,12 @@ enum BlockLiteralFlags {
class BlockFlags {
uint32_t flags;
- BlockFlags(uint32_t flags) : flags(flags) {}
public:
+ BlockFlags(uint32_t flags) : flags(flags) {}
BlockFlags() : flags(0) {}
BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
-
+ BlockFlags(BlockByrefFlags flag) : flags(flag) {}
+
uint32_t getBitMask() const { return flags; }
bool empty() const { return flags == 0; }
@@ -87,6 +87,9 @@ public:
friend bool operator&(BlockFlags l, BlockFlags r) {
return (l.flags & r.flags);
}
+ bool operator==(BlockFlags r) {
+ return (flags == r.flags);
+ }
};
inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
return BlockFlags(l) | BlockFlags(r);
@@ -141,7 +144,7 @@ inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
class CGBlockInfo {
public:
/// Name - The name of the block, kindof.
- llvm::StringRef Name;
+ StringRef Name;
/// The field index of 'this' within the block, if there is one.
unsigned CXXThisIndex;
@@ -208,6 +211,14 @@ public:
const BlockExpr *BlockExpression;
CharUnits BlockSize;
CharUnits BlockAlign;
+
+ // Offset of the gap caused by block header having a smaller
+ // alignment than the alignment of the block descriptor. This
+ // is the gap offset before the first capturued field.
+ CharUnits BlockHeaderForcedGapOffset;
+ // Gap size caused by aligning first field after block header.
+ // This could be zero if no forced alignment is required.
+ CharUnits BlockHeaderForcedGapSize;
/// An instruction which dominates the full-expression that the
/// block is inside.
@@ -236,7 +247,7 @@ public:
return BlockExpression;
}
- CGBlockInfo(const BlockDecl *blockDecl, llvm::StringRef Name);
+ CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h
index a790a742c942..fd21e7e26a3b 100644
--- a/lib/CodeGen/CGBuilder.h
+++ b/lib/CodeGen/CGBuilder.h
@@ -10,7 +10,7 @@
#ifndef CLANG_CODEGEN_CGBUILDER_H
#define CLANG_CODEGEN_CGBUILDER_H
-#include "llvm/IRBuilder.h"
+#include "llvm/IR/IRBuilder.h"
namespace clang {
namespace CodeGen {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index e8c05d3a46d0..3c89652b6dd5 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -11,16 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "TargetInfo.h"
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
-#include "clang/Basic/TargetInfo.h"
+#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetBuiltins.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -160,7 +160,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
- return CGF.Builder.CreateCall(Fn, V, "abs");
+ return CGF.EmitNounwindRuntimeCall(Fn, V, "abs");
}
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
@@ -169,6 +169,30 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn);
}
+/// \brief Emit a call to llvm.{sadd,uadd,ssub,usub,smul,umul}.with.overflow.*
+/// depending on IntrinsicID.
+///
+/// \arg CGF The current codegen function.
+/// \arg IntrinsicID The ID for the Intrinsic we wish to generate.
+/// \arg X The first argument to the llvm.*.with.overflow.*.
+/// \arg Y The second argument to the llvm.*.with.overflow.*.
+/// \arg Carry The carry returned by the llvm.*.with.overflow.*.
+/// \returns The result (i.e. sum/product) returned by the intrinsic.
+static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
+ const llvm::Intrinsic::ID IntrinsicID,
+ llvm::Value *X, llvm::Value *Y,
+ llvm::Value *&Carry) {
+ // Make sure we have integers of the same width.
+ assert(X->getType() == Y->getType() &&
+ "Arguments must be the same type. (Did you forget to make sure both "
+ "arguments have the same integer width?)");
+
+ llvm::Value *Callee = CGF.CGM.getIntrinsic(IntrinsicID, X->getType());
+ llvm::Value *Tmp = CGF.Builder.CreateCall2(Callee, X, Y);
+ Carry = CGF.Builder.CreateExtractValue(Tmp, 1);
+ return CGF.Builder.CreateExtractValue(Tmp, 0);
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E) {
// See if we can constant fold this builtin. If so, don't emit it at all.
@@ -244,14 +268,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin_creal:
case Builtin::BI__builtin_crealf:
- case Builtin::BI__builtin_creall: {
+ case Builtin::BI__builtin_creall:
+ case Builtin::BIcreal:
+ case Builtin::BIcrealf:
+ case Builtin::BIcreall: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.first);
}
case Builtin::BI__builtin_cimag:
case Builtin::BI__builtin_cimagf:
- case Builtin::BI__builtin_cimagl: {
+ case Builtin::BI__builtin_cimagl:
+ case Builtin::BIcimag:
+ case Builtin::BIcimagf:
+ case Builtin::BIcimagl: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.second);
}
@@ -406,10 +436,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
- if (getLangOpts().SanitizeUnreachable)
+ if (SanOpts->Unreachable)
EmitCheck(Builder.getFalse(), "builtin_unreachable",
EmitCheckSourceLocation(E->getExprLoc()),
- llvm::ArrayRef<llvm::Value *>());
+ ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
else
Builder.CreateUnreachable();
@@ -1312,9 +1342,74 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// Get the annotation string, go through casts. Sema requires this to be a
// non-wide string literal, potentially casted, so the cast<> is safe.
const Expr *AnnotationStrExpr = E->getArg(1)->IgnoreParenCasts();
- llvm::StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
+ StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
}
+ case Builtin::BI__builtin_addcs:
+ case Builtin::BI__builtin_addc:
+ case Builtin::BI__builtin_addcl:
+ case Builtin::BI__builtin_addcll:
+ case Builtin::BI__builtin_subcs:
+ case Builtin::BI__builtin_subc:
+ case Builtin::BI__builtin_subcl:
+ case Builtin::BI__builtin_subcll: {
+
+ // We translate all of these builtins from expressions of the form:
+ // int x = ..., y = ..., carryin = ..., carryout, result;
+ // result = __builtin_addc(x, y, carryin, &carryout);
+ //
+ // to LLVM IR of the form:
+ //
+ // %tmp1 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+ // %tmpsum1 = extractvalue {i32, i1} %tmp1, 0
+ // %carry1 = extractvalue {i32, i1} %tmp1, 1
+ // %tmp2 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %tmpsum1,
+ // i32 %carryin)
+ // %result = extractvalue {i32, i1} %tmp2, 0
+ // %carry2 = extractvalue {i32, i1} %tmp2, 1
+ // %tmp3 = or i1 %carry1, %carry2
+ // %tmp4 = zext i1 %tmp3 to i32
+ // store i32 %tmp4, i32* %carryout
+
+ // Scalarize our inputs.
+ llvm::Value *X = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Y = EmitScalarExpr(E->getArg(1));
+ llvm::Value *Carryin = EmitScalarExpr(E->getArg(2));
+ std::pair<llvm::Value*, unsigned> CarryOutPtr =
+ EmitPointerWithAlignment(E->getArg(3));
+
+ // Decide if we are lowering to a uadd.with.overflow or usub.with.overflow.
+ llvm::Intrinsic::ID IntrinsicId;
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unknown multiprecision builtin id.");
+ case Builtin::BI__builtin_addcs:
+ case Builtin::BI__builtin_addc:
+ case Builtin::BI__builtin_addcl:
+ case Builtin::BI__builtin_addcll:
+ IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
+ break;
+ case Builtin::BI__builtin_subcs:
+ case Builtin::BI__builtin_subc:
+ case Builtin::BI__builtin_subcl:
+ case Builtin::BI__builtin_subcll:
+ IntrinsicId = llvm::Intrinsic::usub_with_overflow;
+ break;
+ }
+
+ // Construct our resulting LLVM IR expression.
+ llvm::Value *Carry1;
+ llvm::Value *Sum1 = EmitOverflowIntrinsic(*this, IntrinsicId,
+ X, Y, Carry1);
+ llvm::Value *Carry2;
+ llvm::Value *Sum2 = EmitOverflowIntrinsic(*this, IntrinsicId,
+ Sum1, Carryin, Carry2);
+ llvm::Value *CarryOut = Builder.CreateZExt(Builder.CreateOr(Carry1, Carry2),
+ X->getType());
+ llvm::StoreInst *CarryOutStore = Builder.CreateStore(CarryOut,
+ CarryOutPtr.first);
+ CarryOutStore->setAlignment(CarryOutPtr.second);
+ return RValue::get(Sum2);
+ }
case Builtin::BI__noop:
return RValue::get(0);
}
@@ -1401,9 +1496,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
ErrorUnsupported(E, "builtin function");
// Unknown builtin, for now just dump it out and return undef.
- if (hasAggregateLLVMType(E->getType()))
- return RValue::getAggregate(CreateMemTemp(E->getType()));
- return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
+ return GetUndefRValue(E->getType());
}
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
@@ -1540,7 +1633,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
StringRef Name = FD->getName();
- return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
+ return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
}
if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
@@ -2037,7 +2130,9 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- return Builder.CreateCall3(F, Ops[0], Ops[1], Ops[2]);
+
+ // 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: {
@@ -2614,7 +2709,10 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_rdrand16_step:
case X86::BI__builtin_ia32_rdrand32_step:
- case X86::BI__builtin_ia32_rdrand64_step: {
+ case X86::BI__builtin_ia32_rdrand64_step:
+ case X86::BI__builtin_ia32_rdseed16_step:
+ case X86::BI__builtin_ia32_rdseed32_step:
+ case X86::BI__builtin_ia32_rdseed64_step: {
Intrinsic::ID ID;
switch (BuiltinID) {
default: llvm_unreachable("Unsupported intrinsic!");
@@ -2627,6 +2725,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_rdrand64_step:
ID = Intrinsic::x86_rdrand_64;
break;
+ case X86::BI__builtin_ia32_rdseed16_step:
+ ID = Intrinsic::x86_rdseed_16;
+ break;
+ case X86::BI__builtin_ia32_rdseed32_step:
+ ID = Intrinsic::x86_rdseed_32;
+ break;
+ case X86::BI__builtin_ia32_rdseed64_step:
+ ID = Intrinsic::x86_rdseed_64;
+ break;
}
Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID));
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 88a0bdc821d7..0ebf1aaa44b8 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -16,11 +16,10 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
-#include "llvm/BasicBlock.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/Support/CallSite.h"
-
#include <vector>
using namespace clang;
@@ -79,7 +78,7 @@ llvm::Constant *CGNVCUDARuntime::getLaunchFn() const {
void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
FunctionArgList &Args) {
// Build the argument value list and the argument stack struct type.
- llvm::SmallVector<llvm::Value *, 16> ArgValues;
+ SmallVector<llvm::Value *, 16> ArgValues;
std::vector<llvm::Type *> ArgTypes;
for (FunctionArgList::const_iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
@@ -105,7 +104,7 @@ void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
Args[2] = CGF.Builder.CreateIntCast(
llvm::ConstantExpr::getOffsetOf(ArgStackTy, I),
SizeTy, false);
- llvm::CallSite CS = CGF.EmitCallOrInvoke(cudaSetupArgFn, Args);
+ llvm::CallSite CS = CGF.EmitRuntimeCallOrInvoke(cudaSetupArgFn, Args);
llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0);
llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero);
CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock);
@@ -115,7 +114,7 @@ void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
// Emit the call to cudaLaunch
llvm::Constant *cudaLaunchFn = getLaunchFn();
llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy);
- CGF.EmitCallOrInvoke(cudaLaunchFn, Arg);
+ CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg);
CGF.EmitBranch(EndBlock);
CGF.EmitBlock(EndBlock);
diff --git a/lib/CodeGen/CGCUDARuntime.cpp b/lib/CodeGen/CGCUDARuntime.cpp
index 77dc248d69e6..fc72008af886 100644
--- a/lib/CodeGen/CGCUDARuntime.cpp
+++ b/lib/CodeGen/CGCUDARuntime.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "CGCUDARuntime.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/ExprCXX.h"
#include "CGCall.h"
#include "CodeGenFunction.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace CodeGen;
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 003fef520c90..983cb9224ade 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -13,15 +13,15 @@
// We might split this into multiple files if it gets too unwieldy
+#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
@@ -183,14 +183,16 @@ void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
// The constructor used for constructing this as a base class;
// ignores virtual bases.
- EmitGlobal(GlobalDecl(D, Ctor_Base));
+ if (getTarget().getCXXABI().hasConstructorVariants())
+ EmitGlobal(GlobalDecl(D, Ctor_Base));
}
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 (ctorType == Ctor_Complete &&
+ if (getTarget().getCXXABI().hasConstructorVariants() &&
+ ctorType == Ctor_Complete &&
!ctor->getParent()->getNumVBases() &&
!TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
GlobalDecl(ctor, Ctor_Base)))
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 91795b9ded29..0c0a76f346a5 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -19,8 +19,7 @@ using namespace CodeGen;
CGCXXABI::~CGCXXABI() { }
-static void ErrorUnsupportedABI(CodeGenFunction &CGF,
- StringRef S) {
+void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
DiagnosticsEngine &Diags = CGF.CGM.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot yet compile %0 in this ABI");
@@ -29,8 +28,7 @@ static void ErrorUnsupportedABI(CodeGenFunction &CGF,
<< S;
}
-static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM,
- QualType T) {
+llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
}
@@ -67,12 +65,12 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src) {
ErrorUnsupportedABI(CGF, "member function pointer conversions");
- return GetBogusMemberPointer(CGM, E->getType());
+ return GetBogusMemberPointer(E->getType());
}
llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *Src) {
- return GetBogusMemberPointer(CGM, E->getType());
+ return GetBogusMemberPointer(E->getType());
}
llvm::Value *
@@ -95,22 +93,22 @@ CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
llvm::Constant *
CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- return GetBogusMemberPointer(CGM, QualType(MPT, 0));
+ return GetBogusMemberPointer(QualType(MPT, 0));
}
llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
- return GetBogusMemberPointer(CGM,
+ return GetBogusMemberPointer(
CGM.getContext().getMemberPointerType(MD->getType(),
MD->getParent()->getTypeForDecl()));
}
llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset) {
- return GetBogusMemberPointer(CGM, QualType(MPT, 0));
+ return GetBogusMemberPointer(QualType(MPT, 0));
}
llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
- return GetBogusMemberPointer(CGM, MPT);
+ return GetBogusMemberPointer(MPT);
}
bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
@@ -248,3 +246,12 @@ llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) {
E->path_begin(),
E->path_end());
}
+
+llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler(
+ CodeGenFunction &CGF) {
+ if (CGM.getTarget().getCXXABI().hasConstructorVariants())
+ llvm_unreachable("shouldn't be called in this ABI");
+
+ ErrorUnsupportedABI(CGF, "complete object detection in ctor");
+ return 0;
+}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 570aeb040f55..702e59b71a72 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -15,9 +15,8 @@
#ifndef CLANG_CODEGEN_CXXABI_H
#define CLANG_CODEGEN_CXXABI_H
-#include "clang/Basic/LLVM.h"
-
#include "CodeGenFunction.h"
+#include "clang/Basic/LLVM.h"
namespace llvm {
class Constant;
@@ -55,11 +54,26 @@ protected:
return CGF.CXXABIThisValue;
}
+ /// Issue a diagnostic about unsupported features in the ABI.
+ void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S);
+
+ /// 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.CXXVTTDecl;
+ return CGF.CXXStructorImplicitParamDecl;
}
llvm::Value *&getVTTValue(CodeGenFunction &CGF) {
- return CGF.CXXVTTValue;
+ return CGF.CXXStructorImplicitParamValue;
+ }
+
+ ImplicitParamDecl *&getStructorImplicitParamDecl(CodeGenFunction &CGF) {
+ return CGF.CXXStructorImplicitParamDecl;
+ }
+ llvm::Value *&getStructorImplicitParamValue(CodeGenFunction &CGF) {
+ return CGF.CXXStructorImplicitParamValue;
}
/// Build a parameter variable suitable for 'this'.
@@ -83,6 +97,10 @@ public:
return *MangleCtx;
}
+ /// Returns true if the given instance method is one of the
+ /// kinds that the ABI says returns 'this'.
+ virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
+
/// Find the LLVM type used to represent the given member pointer
/// type.
virtual llvm::Type *
@@ -177,6 +195,8 @@ public:
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+
/// Build the signature of the given destructor variant by adding
/// any required parameters. For convenience, ResTy has been
/// initialized to 'void' and ArgTys has been initialized with the
@@ -199,6 +219,23 @@ 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 llvm::Value *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;
+
+ /// Emit the ABI-specific virtual destructor call.
+ virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This) = 0;
+
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType);
@@ -295,16 +332,14 @@ public:
/// \param addr - a pointer to pass to the destructor function.
virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
llvm::Constant *addr);
-
- /***************************** Virtual Tables *******************************/
-
- /// Generates and emits the virtual tables for a class.
- virtual void EmitVTables(const CXXRecordDecl *Class) = 0;
};
-/// Creates an instance of a C++ ABI class.
-CGCXXABI *CreateARMCXXABI(CodeGenModule &CGM);
+// Create an instance of a C++ ABI class:
+
+/// Creates an Itanium-family ABI.
CGCXXABI *CreateItaniumCXXABI(CodeGenModule &CGM);
+
+/// Creates a Microsoft-family ABI.
CGCXXABI *CreateMicrosoftCXXABI(CodeGenModule &CGM);
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 2d1d152894fd..faf32e300830 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -13,20 +13,22 @@
//===----------------------------------------------------------------------===//
#include "CGCall.h"
-#include "CGCXXABI.h"
#include "ABIInfo.h"
+#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Attributes.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CallSite.h"
-#include "llvm/DataLayout.h"
-#include "llvm/InlineAsm.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
using namespace CodeGen;
@@ -41,6 +43,7 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
+ case CC_IntelOclBicc: return llvm::CallingConv::Intel_OCL_BI;
// TODO: add support for CC_X86Pascal to llvm
}
}
@@ -151,6 +154,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (D->hasAttr<PnaclCallAttr>())
return CC_PnaclCall;
+ if (D->hasAttr<IntelOclBiccAttr>())
+ return CC_IntelOclBicc;
+
return CC_C;
}
@@ -316,6 +322,37 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
return arrangeFunctionDeclaration(FD);
}
+/// Arrange a call as unto a free function, except possibly with an
+/// additional number of formal parameters considered required.
+static const CGFunctionInfo &
+arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
+ const CallArgList &args,
+ const FunctionType *fnType,
+ unsigned numExtraRequiredArgs) {
+ assert(args.size() >= numExtraRequiredArgs);
+
+ // In most cases, there are no optional arguments.
+ RequiredArgs required = RequiredArgs::All;
+
+ // If we have a variadic prototype, the required arguments are the
+ // extra prefix plus the arguments in the prototype.
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
+ if (proto->isVariadic())
+ required = RequiredArgs(proto->getNumArgs() + numExtraRequiredArgs);
+
+ // If we don't have a prototype at all, but we're supposed to
+ // explicitly use the variadic convention for unprototyped calls,
+ // treat all of the arguments as required but preserve the nominal
+ // possibility of variadics.
+ } else if (CGT.CGM.getTargetCodeGenInfo()
+ .isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
+ required = RequiredArgs(args.size());
+ }
+
+ return CGT.arrangeFreeFunctionCall(fnType->getResultType(), args,
+ fnType->getExtInfo(), required);
+}
+
/// Figure out the rules for calling a function with the given formal
/// type using the given arguments. The arguments are necessary
/// because the function might be unprototyped, in which case it's
@@ -323,17 +360,15 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
const FunctionType *fnType) {
- RequiredArgs required = RequiredArgs::All;
- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
- if (proto->isVariadic())
- required = RequiredArgs(proto->getNumArgs());
- } else if (CGM.getTargetCodeGenInfo()
- .isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
- required = RequiredArgs(0);
- }
+ return arrangeFreeFunctionLikeCall(*this, args, fnType, 0);
+}
- return arrangeFreeFunctionCall(fnType->getResultType(), args,
- fnType->getExtInfo(), required);
+/// A block function call is essentially a free-function call with an
+/// extra implicit argument.
+const CGFunctionInfo &
+CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args,
+ const FunctionType *fnType) {
+ return arrangeFreeFunctionLikeCall(*this, args, fnType, 1);
}
const CGFunctionInfo &
@@ -692,12 +727,13 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
// Otherwise do coercion through memory. This is stupid, but
// simple.
llvm::Value *Tmp = CGF.CreateTempAlloca(Ty);
- llvm::Value *Casted =
- CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(SrcTy));
- llvm::StoreInst *Store =
- CGF.Builder.CreateStore(CGF.Builder.CreateLoad(SrcPtr), Casted);
- // FIXME: Use better alignment / avoid requiring aligned store.
- Store->setAlignment(1);
+ llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy();
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy);
+ llvm::Value *SrcCasted = CGF.Builder.CreateBitCast(SrcPtr, I8PtrTy);
+ // FIXME: Use better alignment.
+ CGF.Builder.CreateMemCpy(Casted, SrcCasted,
+ llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize),
+ 1, false);
return CGF.Builder.CreateLoad(Tmp);
}
@@ -779,12 +815,13 @@ static void CreateCoercedStore(llvm::Value *Src,
// to that information.
llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy);
CGF.Builder.CreateStore(Src, Tmp);
- llvm::Value *Casted =
- CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(DstTy));
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted);
- // FIXME: Use better alignment / avoid requiring aligned load.
- Load->setAlignment(1);
- CGF.Builder.CreateStore(Load, DstPtr, DstIsVolatile);
+ llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy();
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy);
+ llvm::Value *DstCasted = CGF.Builder.CreateBitCast(DstPtr, I8PtrTy);
+ // FIXME: Use better alignment.
+ CGF.Builder.CreateMemCpy(DstCasted, Casted,
+ llvm::ConstantInt::get(CGF.IntPtrTy, DstSize),
+ 1, false);
}
}
@@ -863,8 +900,14 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
break;
}
- for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
- ie = FI.arg_end(); it != ie; ++it) {
+ // Add in all of the required arguments.
+ CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie;
+ if (FI.isVariadic()) {
+ ie = it + FI.getRequiredArgs().getNumRequiredArgs();
+ } else {
+ ie = FI.arg_end();
+ }
+ for (; it != ie; ++it) {
const ABIArgInfo &argAI = it->info;
// Insert a padding type to ensure proper alignment.
@@ -927,53 +970,85 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
- unsigned &CallingConv) {
+ unsigned &CallingConv,
+ bool AttrOnCallSite) {
llvm::AttrBuilder FuncAttrs;
llvm::AttrBuilder RetAttrs;
CallingConv = FI.getEffectiveCallingConvention();
if (FI.isNoReturn())
- FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
+ FuncAttrs.addAttribute(llvm::Attribute::ReturnsTwice);
if (TargetDecl->hasAttr<NoThrowAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
- else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+ if (TargetDecl->hasAttr<NoReturnAttr>())
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+
+ if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
if (FPT && FPT->isNothrow(getContext()))
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+ // Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
+ // These attributes are not inherited by overloads.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
+ if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
}
- if (TargetDecl->hasAttr<NoReturnAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
-
- if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
-
// 'const' and 'pure' attribute functions are also nounwind.
if (TargetDecl->hasAttr<ConstAttr>()) {
- FuncAttrs.addAttribute(llvm::Attributes::ReadNone);
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
+ FuncAttrs.addAttribute(llvm::Attribute::ReadNone);
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
} else if (TargetDecl->hasAttr<PureAttr>()) {
- FuncAttrs.addAttribute(llvm::Attributes::ReadOnly);
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
+ FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
if (TargetDecl->hasAttr<MallocAttr>())
- RetAttrs.addAttribute(llvm::Attributes::NoAlias);
+ RetAttrs.addAttribute(llvm::Attribute::NoAlias);
}
if (CodeGenOpts.OptimizeSize)
- FuncAttrs.addAttribute(llvm::Attributes::OptimizeForSize);
+ FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
if (CodeGenOpts.OptimizeSize == 2)
- FuncAttrs.addAttribute(llvm::Attributes::MinSize);
+ FuncAttrs.addAttribute(llvm::Attribute::MinSize);
if (CodeGenOpts.DisableRedZone)
- FuncAttrs.addAttribute(llvm::Attributes::NoRedZone);
+ FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
- FuncAttrs.addAttribute(llvm::Attributes::NoImplicitFloat);
+ FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
+
+ if (AttrOnCallSite) {
+ // Attributes that should go on the call site only.
+ if (!CodeGenOpts.SimplifyLibCalls)
+ FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
+ } else {
+ // Attributes that should go on the function, but not the call site.
+ if (!CodeGenOpts.DisableFPElim) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "false");
+ } else if (CodeGenOpts.OmitLeafFramePointer) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true");
+ } else {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true");
+ }
+
+ FuncAttrs.addAttribute("less-precise-fpmad",
+ CodeGenOpts.LessPreciseFPMAD ? "true" : "false");
+ FuncAttrs.addAttribute("no-infs-fp-math",
+ CodeGenOpts.NoInfsFPMath ? "true" : "false");
+ FuncAttrs.addAttribute("no-nans-fp-math",
+ CodeGenOpts.NoNaNsFPMath ? "true" : "false");
+ FuncAttrs.addAttribute("unsafe-fp-math",
+ CodeGenOpts.UnsafeFPMath ? "true" : "false");
+ FuncAttrs.addAttribute("use-soft-float",
+ CodeGenOpts.SoftFloat ? "true" : "false");
+ }
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
@@ -981,9 +1056,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
if (RetTy->hasSignedIntegerRepresentation())
- RetAttrs.addAttribute(llvm::Attributes::SExt);
+ RetAttrs.addAttribute(llvm::Attribute::SExt);
else if (RetTy->hasUnsignedIntegerRepresentation())
- RetAttrs.addAttribute(llvm::Attributes::ZExt);
+ RetAttrs.addAttribute(llvm::Attribute::ZExt);
break;
case ABIArgInfo::Direct:
case ABIArgInfo::Ignore:
@@ -991,18 +1066,16 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect: {
llvm::AttrBuilder SRETAttrs;
- SRETAttrs.addAttribute(llvm::Attributes::StructRet);
+ SRETAttrs.addAttribute(llvm::Attribute::StructRet);
if (RetAI.getInReg())
- SRETAttrs.addAttribute(llvm::Attributes::InReg);
+ SRETAttrs.addAttribute(llvm::Attribute::InReg);
PAL.push_back(llvm::
- AttributeWithIndex::get(Index,
- llvm::Attributes::get(getLLVMContext(),
- SRETAttrs)));
+ AttributeSet::get(getLLVMContext(), Index, SRETAttrs));
++Index;
// sret disables readnone and readonly
- FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
- .removeAttribute(llvm::Attributes::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
break;
}
@@ -1012,9 +1085,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
if (RetAttrs.hasAttributes())
PAL.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
- llvm::Attributes::get(getLLVMContext(),
- RetAttrs)));
+ AttributeSet::get(getLLVMContext(),
+ llvm::AttributeSet::ReturnIndex,
+ RetAttrs));
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
@@ -1023,13 +1096,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm::AttrBuilder Attrs;
if (AI.getPaddingType()) {
- if (AI.getPaddingInReg()) {
- llvm::AttrBuilder PadAttrs;
- PadAttrs.addAttribute(llvm::Attributes::InReg);
-
- llvm::Attributes A =llvm::Attributes::get(getLLVMContext(), PadAttrs);
- PAL.push_back(llvm::AttributeWithIndex::get(Index, A));
- }
+ if (AI.getPaddingInReg())
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index,
+ llvm::Attribute::InReg));
// Increment Index if there is padding.
++Index;
}
@@ -1040,13 +1109,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (AI.getKind()) {
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerOrEnumerationType())
- Attrs.addAttribute(llvm::Attributes::SExt);
+ Attrs.addAttribute(llvm::Attribute::SExt);
else if (ParamType->isUnsignedIntegerOrEnumerationType())
- Attrs.addAttribute(llvm::Attributes::ZExt);
+ Attrs.addAttribute(llvm::Attribute::ZExt);
// FALL THROUGH
case ABIArgInfo::Direct:
if (AI.getInReg())
- Attrs.addAttribute(llvm::Attributes::InReg);
+ Attrs.addAttribute(llvm::Attribute::InReg);
// FIXME: handle sseregparm someday...
@@ -1055,25 +1124,24 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
if (Attrs.hasAttributes())
for (unsigned I = 0; I < Extra; ++I)
- PAL.push_back(llvm::AttributeWithIndex::get(Index + I,
- llvm::Attributes::get(getLLVMContext(),
- Attrs)));
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index + I,
+ Attrs));
Index += Extra;
}
break;
case ABIArgInfo::Indirect:
if (AI.getInReg())
- Attrs.addAttribute(llvm::Attributes::InReg);
+ Attrs.addAttribute(llvm::Attribute::InReg);
if (AI.getIndirectByVal())
- Attrs.addAttribute(llvm::Attributes::ByVal);
+ Attrs.addAttribute(llvm::Attribute::ByVal);
Attrs.addAlignmentAttr(AI.getIndirectAlign());
// byval disables readnone and readonly.
- FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
- .removeAttribute(llvm::Attributes::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
break;
case ABIArgInfo::Ignore:
@@ -1092,16 +1160,14 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
if (Attrs.hasAttributes())
- PAL.push_back(llvm::AttributeWithIndex::get(Index,
- llvm::Attributes::get(getLLVMContext(),
- Attrs)));
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
++Index;
}
if (FuncAttrs.hasAttributes())
PAL.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
- llvm::Attributes::get(getLLVMContext(),
- FuncAttrs)));
+ AttributeSet::get(getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ FuncAttrs));
}
/// An argument came in as a promoted argument; demote it back to its
@@ -1149,8 +1215,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Name the struct return argument.
if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
- AI->addAttr(llvm::Attributes::get(getLLVMContext(),
- llvm::Attributes::NoAlias));
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NoAlias));
++AI;
}
@@ -1175,7 +1242,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
- if (hasAggregateLLVMType(Ty)) {
+ if (!hasScalarEvaluationKind(Ty)) {
// Aggregates and complex variables are accessed by reference. All we
// need to do is realign the value, if requested
if (ArgI.getIndirectRealign()) {
@@ -1221,8 +1288,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *V = AI;
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::Attributes::get(getLLVMContext(),
- llvm::Attributes::NoAlias));
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NoAlias));
// Ensure the argument is the correct type.
if (V->getType() != ArgI.getCoerceToType())
@@ -1230,7 +1298,15 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
-
+
+ // Because of merging of function types from multiple decls it is
+ // possible for the type of an argument to not match the corresponding
+ // type in the function type. Since we are codegening the callee
+ // in here, add a cast to the argument type.
+ llvm::Type *LTy = ConvertType(Arg->getType());
+ if (V->getType() != LTy)
+ V = Builder.CreateBitCast(V, LTy);
+
EmitParmDecl(*Arg, V, ArgNo);
break;
}
@@ -1299,7 +1375,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Match to what EmitParmDecl is expecting for this type.
- if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ if (CodeGenFunction::hasScalarEvaluationKind(Ty)) {
V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty);
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
@@ -1328,7 +1404,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
- if (hasAggregateLLVMType(Ty))
+ if (!hasScalarEvaluationKind(Ty))
EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo);
else
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())),
@@ -1538,6 +1614,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
return store;
}
+/// Check whether 'this' argument of a callsite matches 'this' of the caller.
+static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
+ if (ThisArg == This)
+ return true;
+ // Check whether ThisArg is a bitcast of This.
+ llvm::BitCastInst *Bitcast;
+ if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&
+ Bitcast->getOperand(0) == This)
+ return true;
+ return false;
+}
+
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// Functions with no result always return void.
if (ReturnValue == 0) {
@@ -1552,15 +1640,23 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
switch (RetAI.getKind()) {
case ABIArgInfo::Indirect: {
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType()) {
- ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false);
- StoreComplexToAddr(RT, CurFn->arg_begin(), false);
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
+ ComplexPairTy RT =
+ EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy));
+ EmitStoreOfComplex(RT,
+ MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ /*isInit*/ true);
+ break;
+ }
+ case TEK_Aggregate:
// Do nothing; aggregrates get evaluated directly into the destination.
- } else {
- EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(),
- false, Alignment, RetTy);
+ break;
+ case TEK_Scalar:
+ EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
+ MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ /*isInit*/ true);
+ break;
}
break;
}
@@ -1621,6 +1717,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
llvm_unreachable("Invalid ABI kind for return argument");
}
+ // If this function returns 'this', the last instruction is a CallInst
+ // that returns 'this', and 'this' argument of the CallInst points to
+ // the same object as CXXThisValue, use the return value from the CallInst.
+ // We will not need to keep 'this' alive through the callsite. It also enables
+ // optimizations in the backend, such as tail call optimization.
+ if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
+ llvm::BasicBlock *IP = Builder.GetInsertBlock();
+ llvm::CallInst *Callsite;
+ if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&
+ Callsite->getCalledFunction() == CalleeWithThisReturn &&
+ checkThisPointer(Callsite->getOperand(0), CXXThisValue))
+ RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
+ }
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
@@ -1637,10 +1746,10 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
// For the most part, we just need to load the alloca, except:
// 1) aggregate r-values are actually pointers to temporaries, and
- // 2) references to aggregates are pointers directly to the aggregate.
- // I don't know why references to non-aggregates are different here.
+ // 2) references to non-scalars are pointers directly to the aggregate.
+ // I don't know why references to scalars are different here.
if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
- if (hasAggregateLLVMType(ref->getPointeeType()))
+ if (!hasScalarEvaluationKind(ref->getPointeeType()))
return args.add(RValue::getAggregate(local), type);
// Locals which are references to scalars are represented
@@ -1648,17 +1757,7 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
- if (type->isAnyComplexType()) {
- ComplexPairTy complex = LoadComplexFromAddr(local, /*volatile*/ false);
- return args.add(RValue::getComplex(complex), type);
- }
-
- if (hasAggregateLLVMType(type))
- return args.add(RValue::getAggregate(local), type);
-
- unsigned alignment = getContext().getDeclAlign(param).getQuantity();
- llvm::Value *value = EmitLoadOfScalar(local, false, alignment, type);
- return args.add(RValue::get(value), type);
+ args.add(convertTempToRValue(local, type), type);
}
static bool isProvablyNull(llvm::Value *addr) {
@@ -1672,7 +1771,8 @@ static bool isProvablyNonNull(llvm::Value *addr) {
/// Emit the actual writing-back of a writeback.
static void emitWriteback(CodeGenFunction &CGF,
const CallArgList::Writeback &writeback) {
- llvm::Value *srcAddr = writeback.Address;
+ const LValue &srcLV = writeback.Source;
+ llvm::Value *srcAddr = srcLV.getAddress();
assert(!isProvablyNull(srcAddr) &&
"shouldn't have writeback for provably null argument");
@@ -1699,9 +1799,35 @@ static void emitWriteback(CodeGenFunction &CGF,
"icr.writeback-cast");
// Perform the writeback.
- QualType srcAddrType = writeback.AddressType;
- CGF.EmitStoreThroughLValue(RValue::get(value),
- CGF.MakeAddrLValue(srcAddr, srcAddrType));
+
+ // If we have a "to use" value, it's something we need to emit a use
+ // of. This has to be carefully threaded in: if it's done after the
+ // release it's potentially undefined behavior (and the optimizer
+ // will ignore it), and if it happens before the retain then the
+ // optimizer could move the release there.
+ if (writeback.ToUse) {
+ assert(srcLV.getObjCLifetime() == Qualifiers::OCL_Strong);
+
+ // Retain the new value. No need to block-copy here: the block's
+ // being passed up the stack.
+ value = CGF.EmitARCRetainNonBlock(value);
+
+ // Emit the intrinsic use here.
+ CGF.EmitARCIntrinsicUse(writeback.ToUse);
+
+ // Load the old value (primitively).
+ llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV);
+
+ // Put the new value in place (primitively).
+ CGF.EmitStoreOfScalar(value, srcLV, /*init*/ false);
+
+ // Release the old value.
+ CGF.EmitARCRelease(oldValue, srcLV.isARCPreciseLifetime());
+
+ // Otherwise, we can just do a normal lvalue store.
+ } else {
+ CGF.EmitStoreThroughLValue(RValue::get(value), srcLV);
+ }
// Jump to the continuation block.
if (!provablyNonNull)
@@ -1715,11 +1841,33 @@ static void emitWritebacks(CodeGenFunction &CGF,
emitWriteback(CGF, *i);
}
+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;
+}
+
/// Emit an argument that's being passed call-by-writeback. That is,
/// we are passing the address of
static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
const ObjCIndirectCopyRestoreExpr *CRE) {
- llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+ LValue srcLV;
+
+ // Make an optimistic effort to emit the address as an l-value.
+ // This can fail if the the argument expression is more complicated.
+ if (const Expr *lvExpr = maybeGetUnaryAddrOfOperand(CRE->getSubExpr())) {
+ srcLV = CGF.EmitLValue(lvExpr);
+
+ // Otherwise, just emit it as a scalar.
+ } else {
+ llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+
+ QualType srcAddrType =
+ CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
+ srcLV = CGF.MakeNaturalAlignAddrLValue(srcAddr, srcAddrType);
+ }
+ llvm::Value *srcAddr = srcLV.getAddress();
// The dest and src types don't necessarily match in LLVM terms
// because of the crazy ObjC compatibility rules.
@@ -1734,13 +1882,15 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
return;
}
- QualType srcAddrType =
- CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
-
// Create the temporary.
llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(),
"icr.temp");
-
+ // Loading an l-value can introduce a cleanup if the l-value is __weak,
+ // and that cleanup will be conditional if we can't prove that the l-value
+ // isn't null, so we need to register a dominating point so that the cleanups
+ // system will make valid IR.
+ CodeGenFunction::ConditionalEvaluation condEval(CGF);
+
// Zero-initialize it if we're not doing a copy-initialization.
bool shouldCopy = CRE->shouldCopy();
if (!shouldCopy) {
@@ -1749,8 +1899,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;
// If the address is *not* known to be non-null, we need to switch.
llvm::Value *finalArgument;
@@ -1768,16 +1919,19 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// If we need to copy, then the load has to be conditional, which
// means we need control flow.
if (shouldCopy) {
+ originBB = CGF.Builder.GetInsertBlock();
contBB = CGF.createBasicBlock("icr.cont");
llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
CGF.EmitBlock(copyBB);
+ condEval.begin(CGF);
}
}
+ llvm::Value *valueToUse = 0;
+
// Perform a copy if necessary.
if (shouldCopy) {
- LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
RValue srcRV = CGF.EmitLoadOfLValue(srcLV);
assert(srcRV.isScalar());
@@ -1787,13 +1941,37 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// Use an ordinary store, not a store-to-lvalue.
CGF.Builder.CreateStore(src, temp);
- }
+ // If optimization is enabled, and the value was held in a
+ // __strong variable, we need to tell the optimizer that this
+ // value has to stay alive until we're doing the store back.
+ // This is because the temporary is effectively unretained,
+ // and so otherwise we can violate the high-level semantics.
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel != 0 &&
+ srcLV.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ valueToUse = src;
+ }
+ }
+
// Finish the control flow if we needed it.
- if (shouldCopy && !provablyNonNull)
+ if (shouldCopy && !provablyNonNull) {
+ llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock();
CGF.EmitBlock(contBB);
- args.addWriteback(srcAddr, srcAddrType, temp);
+ // Make a phi for the value to intrinsically use.
+ if (valueToUse) {
+ llvm::PHINode *phiToUse = CGF.Builder.CreatePHI(valueToUse->getType(), 2,
+ "icr.to-use");
+ phiToUse->addIncoming(valueToUse, copyBB);
+ phiToUse->addIncoming(llvm::UndefValue::get(valueToUse->getType()),
+ originBB);
+ valueToUse = phiToUse;
+ }
+
+ condEval.end(CGF);
+ }
+
+ args.addWriteback(srcLV, temp, valueToUse);
args.add(RValue::get(finalArgument), CRE->getType());
}
@@ -1815,7 +1993,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
type);
}
- if (hasAggregateLLVMType(type) && !E->getType()->isAnyComplexType() &&
+ if (hasAggregateEvaluationKind(type) &&
isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
@@ -1837,6 +2015,85 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
CGM.getNoObjCARCExceptionsMetadata());
}
+/// Emits a call to the given no-arguments nounwind runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
+ const llvm::Twine &name) {
+ return EmitNounwindRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a call to the given nounwind runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const llvm::Twine &name) {
+ llvm::CallInst *call = EmitRuntimeCall(callee, args, name);
+ call->setDoesNotThrow();
+ return call;
+}
+
+/// Emits a simple call (never an invoke) to the given no-arguments
+/// runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
+ const llvm::Twine &name) {
+ return EmitRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a simple call (never an invoke) to the given runtime
+/// function.
+llvm::CallInst *
+CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const llvm::Twine &name) {
+ llvm::CallInst *call = Builder.CreateCall(callee, args, name);
+ call->setCallingConv(getRuntimeCC());
+ return call;
+}
+
+/// Emits a call or invoke to the given noreturn runtime function.
+void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args) {
+ if (getInvokeDest()) {
+ llvm::InvokeInst *invoke =
+ Builder.CreateInvoke(callee,
+ getUnreachableBlock(),
+ getInvokeDest(),
+ args);
+ invoke->setDoesNotReturn();
+ invoke->setCallingConv(getRuntimeCC());
+ } else {
+ llvm::CallInst *call = Builder.CreateCall(callee, args);
+ call->setDoesNotReturn();
+ call->setCallingConv(getRuntimeCC());
+ Builder.CreateUnreachable();
+ }
+}
+
+/// Emits a call or invoke instruction to the given nullary runtime
+/// function.
+llvm::CallSite
+CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ const Twine &name) {
+ return EmitRuntimeCallOrInvoke(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a call or invoke instruction to the given runtime function.
+llvm::CallSite
+CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name) {
+ llvm::CallSite callSite = EmitCallOrInvoke(callee, args, name);
+ callSite.setCallingConv(getRuntimeCC());
+ return callSite;
+}
+
+llvm::CallSite
+CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
+ const Twine &Name) {
+ return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
+}
+
/// Emits a call or invoke instruction to the given function, depending
/// on the current state of the EH stack.
llvm::CallSite
@@ -1862,12 +2119,6 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
return Inst;
}
-llvm::CallSite
-CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- const Twine &Name) {
- return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
-}
-
static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
llvm::FunctionType *FTy) {
if (ArgNo < FTy->getNumParams())
@@ -1886,15 +2137,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
llvm::Value *Addr = RV.getAggregateAddr();
for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
- LValue LV = MakeAddrLValue(EltAddr, EltTy);
- RValue EltRV;
- if (EltTy->isAnyComplexType())
- // FIXME: Volatile?
- EltRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false));
- else if (CodeGenFunction::hasAggregateLLVMType(EltTy))
- EltRV = LV.asAggregateRValue();
- else
- EltRV = EmitLoadOfLValue(LV);
+ RValue EltRV = convertTempToRValue(EltAddr, EltTy);
ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
}
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -1987,8 +2230,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
- unsigned TypeAlign =
- getContext().getTypeAlignInChars(I->Ty).getQuantity();
+ CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
// Insert a padding argument to ensure proper alignment.
if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
@@ -2004,28 +2246,36 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (ArgInfo.getIndirectAlign() > AI->getAlignment())
AI->setAlignment(ArgInfo.getIndirectAlign());
Args.push_back(AI);
+
+ LValue argLV =
+ MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
if (RV.isScalar())
- EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false,
- TypeAlign, I->Ty);
+ EmitStoreOfScalar(RV.getScalarVal(), argLV, /*init*/ true);
else
- StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ EmitStoreOfComplex(RV.getComplexVal(), argLV, /*init*/ true);
// Validate argument match.
checkArgMatches(AI, IRArgNo, IRFuncTy);
} else {
// We want to avoid creating an unnecessary temporary+copy here;
- // however, we need one in two cases:
+ // however, we need one in three cases:
// 1. If the argument is not byval, and we are required to copy the
// source. (This case doesn't occur on any common architecture.)
// 2. If the argument is byval, RV is not sufficiently aligned, and
// we cannot force it to be sufficiently aligned.
+ // 3. If the argument is byval, but RV is located in an address space
+ // different than that of the argument (0).
llvm::Value *Addr = RV.getAggregateAddr();
unsigned Align = ArgInfo.getIndirectAlign();
const llvm::DataLayout *TD = &CGM.getDataLayout();
+ const unsigned RVAddrSpace = Addr->getType()->getPointerAddressSpace();
+ const unsigned ArgAddrSpace = (IRArgNo < IRFuncTy->getNumParams() ?
+ IRFuncTy->getParamType(IRArgNo)->getPointerAddressSpace() : 0);
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
- (ArgInfo.getIndirectByVal() && TypeAlign < Align &&
- llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) {
+ (ArgInfo.getIndirectByVal() && TypeAlign.getQuantity() < Align &&
+ llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align) ||
+ (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
// Create an aligned temporary, and copy to it.
llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
if (Align > AI->getAlignment())
@@ -2073,12 +2323,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
- if (RV.isScalar()) {
- SrcPtr = CreateMemTemp(I->Ty, "coerce");
- EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, TypeAlign, I->Ty);
- } else if (RV.isComplex()) {
+ if (RV.isScalar() || RV.isComplex()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
- StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
+ LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign);
+ if (RV.isScalar()) {
+ EmitStoreOfScalar(RV.getScalarVal(), SrcLV, /*init*/ true);
+ } else {
+ EmitStoreOfComplex(RV.getComplexVal(), SrcLV, /*init*/ true);
+ }
} else
SrcPtr = RV.getAggregateAddr();
@@ -2176,12 +2428,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
- llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(getLLVMContext(),
- AttributeList);
+ CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList,
+ CallingConv, true);
+ llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
+ AttributeList);
llvm::BasicBlock *InvokeDest = 0;
- if (!Attrs.getFnAttributes().hasAttribute(llvm::Attributes::NoUnwind))
+ if (!Attrs.hasAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind))
InvokeDest = getInvokeDest();
llvm::CallSite CS;
@@ -2229,14 +2483,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
emitWritebacks(*this, CallArgs);
switch (RetAI.getKind()) {
- case ABIArgInfo::Indirect: {
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
- if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(Args[0]);
- return RValue::get(EmitLoadOfScalar(Args[0], false, Alignment, RetTy));
- }
+ case ABIArgInfo::Indirect:
+ return convertTempToRValue(Args[0], RetTy);
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
@@ -2247,12 +2495,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
- if (RetTy->isAnyComplexType()) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
- if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ case TEK_Aggregate: {
llvm::Value *DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
@@ -2263,13 +2512,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
return RValue::getAggregate(DestPtr);
}
-
- // If the argument doesn't match, perform a bitcast to coerce it. This
- // can happen due to trivial type mismatches.
- llvm::Value *V = CI;
- if (V->getType() != RetIRTy)
- V = Builder.CreateBitCast(V, RetIRTy);
- return RValue::get(V);
+ case TEK_Scalar: {
+ // If the argument doesn't match, perform a bitcast to coerce it. This
+ // can happen due to trivial type mismatches.
+ llvm::Value *V = CI;
+ if (V->getType() != RetIRTy)
+ V = Builder.CreateBitCast(V, RetIRTy);
+ return RValue::get(V);
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
}
llvm::Value *DestPtr = ReturnValue.getValue();
@@ -2290,12 +2542,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(DestPtr, false));
- if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(DestPtr);
- return RValue::get(EmitLoadOfScalar(DestPtr, false, Alignment, RetTy));
+ return convertTempToRValue(DestPtr, RetTy);
}
case ABIArgInfo::Expand:
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index dead7bd45910..85c3320ec0ee 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -15,23 +15,20 @@
#ifndef CLANG_CODEGEN_CGCALL_H
#define CLANG_CODEGEN_CGCALL_H
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/Value.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/CanonicalType.h"
-
#include "CGValue.h"
+#include "clang/AST/CanonicalType.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/IR/Value.h"
// FIXME: Restructure so we don't have to expose so much stuff.
#include "ABIInfo.h"
namespace llvm {
- struct AttributeWithIndex;
+ class AttributeSet;
class Function;
class Type;
class Value;
-
- template<typename T, unsigned> class SmallVector;
}
namespace clang {
@@ -42,7 +39,7 @@ namespace clang {
class VarDecl;
namespace CodeGen {
- typedef SmallVector<llvm::AttributeWithIndex, 8> AttributeListType;
+ typedef SmallVector<llvm::AttributeSet, 8> AttributeListType;
struct CallArg {
RValue RV;
@@ -59,14 +56,15 @@ namespace CodeGen {
public SmallVector<CallArg, 16> {
public:
struct Writeback {
- /// The original argument.
- llvm::Value *Address;
-
- /// The pointee type of the original argument.
- QualType AddressType;
+ /// The original argument. Note that the argument l-value
+ /// is potentially null.
+ LValue Source;
/// The temporary alloca.
llvm::Value *Temporary;
+
+ /// A value to "use" after the writeback, or null.
+ llvm::Value *ToUse;
};
void add(RValue rvalue, QualType type, bool needscopy = false) {
@@ -79,12 +77,12 @@ namespace CodeGen {
other.Writebacks.begin(), other.Writebacks.end());
}
- void addWriteback(llvm::Value *address, QualType addressType,
- llvm::Value *temporary) {
+ void addWriteback(LValue srcLV, llvm::Value *temporary,
+ llvm::Value *toUse) {
Writeback writeback;
- writeback.Address = address;
- writeback.AddressType = addressType;
+ writeback.Source = srcLV;
writeback.Temporary = temporary;
+ writeback.ToUse = toUse;
Writebacks.push_back(writeback);
}
@@ -135,7 +133,7 @@ namespace CodeGen {
}
bool allowsOptionalArgs() const { return NumRequired != ~0U; }
- bool getNumRequiredArgs() const {
+ unsigned getNumRequiredArgs() const {
assert(allowsOptionalArgs());
return NumRequired;
}
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index b2225e48e361..2ececb03651a 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -13,11 +13,14 @@
#include "CGBlocks.h"
#include "CGDebugInfo.h"
+#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
+#include "CGCXXABI.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "clang/Frontend/CodeGenOptions.h"
using namespace clang;
@@ -232,7 +235,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
QualType DerivedTy =
getContext().getCanonicalType(getContext().getTagDeclType(Derived));
llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
-
+
llvm::Value *NonVirtualOffset =
CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);
@@ -278,50 +281,51 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
return Value;
}
-
-/// GetVTTParameter - Return the VTT parameter that should be passed to a
-/// base constructor/destructor with virtual bases.
-static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
- bool ForVirtualBase) {
+
+llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
+ bool ForVirtualBase,
+ bool Delegating) {
if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
}
- const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent();
const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
llvm::Value *VTT;
uint64_t SubVTTIndex;
- // If the record matches the base, this is the complete ctor/dtor
- // variant calling the base variant in a class with virtual bases.
- if (RD == Base) {
- assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
+ if (Delegating) {
+ // If this is a delegating constructor call, just load the VTT.
+ return LoadCXXVTT();
+ } else if (RD == Base) {
+ // If the record matches the base, this is the complete ctor/dtor
+ // variant calling the base variant in a class with virtual bases.
+ assert(!CodeGenVTables::needsVTTParameter(CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
assert(!ForVirtualBase && "Can't have same class as virtual base!");
SubVTTIndex = 0;
} else {
- const ASTRecordLayout &Layout =
- CGF.getContext().getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
CharUnits BaseOffset = ForVirtualBase ?
Layout.getVBaseClassOffset(Base) :
Layout.getBaseClassOffset(Base);
SubVTTIndex =
- CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
+ CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
- if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) {
+ if (CodeGenVTables::needsVTTParameter(CurGD)) {
// A VTT parameter was passed to the constructor, use it.
- VTT = CGF.LoadCXXVTT();
- VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
+ VTT = LoadCXXVTT();
+ VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
} else {
// We're the complete constructor, so get the VTT by name.
- VTT = CGF.CGM.getVTables().GetAddrOfVTT(RD);
- VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
+ VTT = CGM.getVTables().GetAddrOfVTT(RD);
+ VTT = Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
}
return VTT;
@@ -344,7 +348,8 @@ namespace {
CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThis(),
DerivedClass, BaseClass,
BaseIsVirtual);
- CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual, Addr);
+ CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual,
+ /*Delegating=*/false, Addr);
}
};
@@ -446,12 +451,14 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
LV.setAlignment(std::min(Align, LV.getAlignment()));
}
- if (!CGF.hasAggregateLLVMType(T)) {
+ switch (CGF.getEvaluationKind(T)) {
+ case TEK_Scalar:
CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
- } else if (T->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, LV.getAddress(),
- LV.isVolatileQualified());
- } else {
+ break;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
AggValueSlot Slot =
AggValueSlot::forLValue(LV,
AggValueSlot::IsDestructed,
@@ -459,6 +466,8 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
+ break;
+ }
}
}
@@ -527,21 +536,6 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.EmitBlock(AfterFor, true);
}
-namespace {
- struct CallMemberDtor : EHScopeStack::Cleanup {
- llvm::Value *V;
- CXXDestructorDecl *Dtor;
-
- CallMemberDtor(llvm::Value *V, CXXDestructorDecl *Dtor)
- : V(V), Dtor(Dtor) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- V);
- }
- };
-}
-
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *MemberInit,
@@ -610,16 +604,19 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
LValue LHS, Expr *Init,
ArrayRef<VarDecl *> ArrayIndexes) {
QualType FieldType = Field->getType();
- if (!hasAggregateLLVMType(FieldType)) {
+ switch (getEvaluationKind(FieldType)) {
+ case TEK_Scalar:
if (LHS.isSimple()) {
EmitExprAsInit(Init, Field, LHS, false);
} else {
RValue RHS = RValue::get(EmitScalarExpr(Init));
EmitStoreThroughLValue(RHS, LHS);
}
- } else if (FieldType->isAnyComplexType()) {
- EmitComplexExprIntoAddr(Init, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
+ break;
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
llvm::Value *ArrayIndexVar = 0;
if (ArrayIndexes.size()) {
llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
@@ -647,22 +644,14 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType,
ArrayIndexes, 0);
-
- if (!CGM.getLangOpts().Exceptions)
- return;
-
- // FIXME: If we have an array of classes w/ non-trivial destructors,
- // we need to destroy in reverse order of construction along the exception
- // path.
- const RecordType *RT = FieldType->getAs<RecordType>();
- if (!RT)
- return;
-
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (!RD->hasTrivialDestructor())
- EHStack.pushCleanup<CallMemberDtor>(EHCleanup, LHS.getAddress(),
- RD->getDestructor());
}
+ }
+
+ // Ensure that we destroy this object if an exception is thrown
+ // later in the constructor.
+ QualType::DestructionKind dtorKind = FieldType.isDestructedType();
+ if (needsEHCleanup(dtorKind))
+ pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
}
/// Checks whether the given constructor is a valid subject for the
@@ -721,7 +710,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// Before we go any further, try the complete->base constructor
// delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
- CGM.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ CGM.getContext().getTargetInfo().getCXXABI().hasConstructorVariants()) {
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, Ctor->getLocEnd());
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
@@ -761,6 +750,353 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
}
+namespace {
+ class FieldMemcpyizer {
+ public:
+ FieldMemcpyizer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl,
+ const VarDecl *SrcRec)
+ : CGF(CGF), ClassDecl(ClassDecl), SrcRec(SrcRec),
+ RecLayout(CGF.getContext().getASTRecordLayout(ClassDecl)),
+ FirstField(0), LastField(0), FirstFieldOffset(0), LastFieldOffset(0),
+ LastAddedFieldIndex(0) { }
+
+ static bool isMemcpyableField(FieldDecl *F) {
+ Qualifiers Qual = F->getType().getQualifiers();
+ if (Qual.hasVolatile() || Qual.hasObjCLifetime())
+ return false;
+ return true;
+ }
+
+ void addMemcpyableField(FieldDecl *F) {
+ if (FirstField == 0)
+ addInitialField(F);
+ else
+ addNextField(F);
+ }
+
+ CharUnits getMemcpySize() const {
+ unsigned LastFieldSize =
+ LastField->isBitField() ?
+ LastField->getBitWidthValue(CGF.getContext()) :
+ CGF.getContext().getTypeSize(LastField->getType());
+ uint64_t MemcpySizeBits =
+ LastFieldOffset + LastFieldSize - FirstFieldOffset +
+ CGF.getContext().getCharWidth() - 1;
+ CharUnits MemcpySize =
+ CGF.getContext().toCharUnitsFromBits(MemcpySizeBits);
+ return MemcpySize;
+ }
+
+ 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) {
+ return;
+ }
+
+ CharUnits Alignment;
+
+ if (FirstField->isBitField()) {
+ const CGRecordLayout &RL =
+ CGF.getTypes().getCGRecordLayout(FirstField->getParent());
+ const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
+ Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment);
+ } else {
+ Alignment = CGF.getContext().getDeclAlign(FirstField);
+ }
+
+ assert((CGF.getContext().toCharUnitsFromBits(FirstFieldOffset) %
+ Alignment) == 0 && "Bad field alignment.");
+
+ CharUnits MemcpySize = getMemcpySize();
+ QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue DestLV = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
+ LValue Dest = CGF.EmitLValueForFieldInitialization(DestLV, FirstField);
+ llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(SrcRec));
+ LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
+ LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField);
+
+ emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(),
+ Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(),
+ MemcpySize, Alignment);
+ reset();
+ }
+
+ void reset() {
+ FirstField = 0;
+ }
+
+ protected:
+ CodeGenFunction &CGF;
+ const CXXRecordDecl *ClassDecl;
+
+ private:
+
+ void emitMemcpyIR(llvm::Value *DestPtr, llvm::Value *SrcPtr,
+ CharUnits Size, CharUnits Alignment) {
+ llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType());
+ llvm::Type *DBP =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), DPT->getAddressSpace());
+ DestPtr = CGF.Builder.CreateBitCast(DestPtr, DBP);
+
+ llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType());
+ llvm::Type *SBP =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), SPT->getAddressSpace());
+ SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, SBP);
+
+ CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, Size.getQuantity(),
+ Alignment.getQuantity());
+ }
+
+ void addInitialField(FieldDecl *F) {
+ FirstField = F;
+ LastField = F;
+ FirstFieldOffset = RecLayout.getFieldOffset(F->getFieldIndex());
+ LastFieldOffset = FirstFieldOffset;
+ LastAddedFieldIndex = F->getFieldIndex();
+ return;
+ }
+
+ void addNextField(FieldDecl *F) {
+ assert(F->getFieldIndex() == LastAddedFieldIndex + 1 &&
+ "Cannot aggregate non-contiguous fields.");
+ LastAddedFieldIndex = F->getFieldIndex();
+
+ // The 'first' and 'last' fields are chosen by offset, rather than field
+ // index. This allows the code to support bitfields, as well as regular
+ // fields.
+ uint64_t FOffset = RecLayout.getFieldOffset(F->getFieldIndex());
+ if (FOffset < FirstFieldOffset) {
+ FirstField = F;
+ FirstFieldOffset = FOffset;
+ } else if (FOffset > LastFieldOffset) {
+ LastField = F;
+ LastFieldOffset = FOffset;
+ }
+ }
+
+ const VarDecl *SrcRec;
+ const ASTRecordLayout &RecLayout;
+ FieldDecl *FirstField;
+ FieldDecl *LastField;
+ uint64_t FirstFieldOffset, LastFieldOffset;
+ unsigned LastAddedFieldIndex;
+ };
+
+ class ConstructorMemcpyizer : public FieldMemcpyizer {
+ private:
+
+ /// Get source argument for copy constructor. Returns null if not a copy
+ /// constructor.
+ static const VarDecl* getTrivialCopySource(const CXXConstructorDecl *CD,
+ FunctionArgList &Args) {
+ if (CD->isCopyOrMoveConstructor() && CD->isImplicitlyDefined())
+ return Args[Args.size() - 1];
+ return 0;
+ }
+
+ // Returns true if a CXXCtorInitializer represents a member initialization
+ // that can be rolled into a memcpy.
+ bool isMemberInitMemcpyable(CXXCtorInitializer *MemberInit) const {
+ if (!MemcpyableCtor)
+ return false;
+ FieldDecl *Field = MemberInit->getMember();
+ assert(Field != 0 && "No field for member init.");
+ QualType FieldType = Field->getType();
+ CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
+
+ // Bail out on non-POD, not-trivially-constructable members.
+ if (!(CE && CE->getConstructor()->isTrivial()) &&
+ !(FieldType.isTriviallyCopyableType(CGF.getContext()) ||
+ FieldType->isReferenceType()))
+ return false;
+
+ // Bail out on volatile fields.
+ if (!isMemcpyableField(Field))
+ return false;
+
+ // Otherwise we're good.
+ return true;
+ }
+
+ public:
+ ConstructorMemcpyizer(CodeGenFunction &CGF, const CXXConstructorDecl *CD,
+ FunctionArgList &Args)
+ : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CD, Args)),
+ ConstructorDecl(CD),
+ MemcpyableCtor(CD->isImplicitlyDefined() &&
+ CD->isCopyOrMoveConstructor() &&
+ CGF.getLangOpts().getGC() == LangOptions::NonGC),
+ Args(Args) { }
+
+ void addMemberInitializer(CXXCtorInitializer *MemberInit) {
+ if (isMemberInitMemcpyable(MemberInit)) {
+ AggregatedInits.push_back(MemberInit);
+ addMemcpyableField(MemberInit->getMember());
+ } else {
+ emitAggregatedInits();
+ EmitMemberInitializer(CGF, ConstructorDecl->getParent(), MemberInit,
+ ConstructorDecl, Args);
+ }
+ }
+
+ void emitAggregatedInits() {
+ if (AggregatedInits.size() <= 1) {
+ // This memcpy is too small to be worthwhile. Fall back on default
+ // codegen.
+ for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
+ EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
+ AggregatedInits[i], ConstructorDecl, Args);
+ }
+ reset();
+ return;
+ }
+
+ pushEHDestructors();
+ emitMemcpy();
+ AggregatedInits.clear();
+ }
+
+ void pushEHDestructors() {
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
+ LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
+
+ for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
+ QualType FieldType = AggregatedInits[i]->getMember()->getType();
+ QualType::DestructionKind dtorKind = FieldType.isDestructedType();
+ if (CGF.needsEHCleanup(dtorKind))
+ CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
+ }
+ }
+
+ void finish() {
+ emitAggregatedInits();
+ }
+
+ private:
+ const CXXConstructorDecl *ConstructorDecl;
+ bool MemcpyableCtor;
+ FunctionArgList &Args;
+ SmallVector<CXXCtorInitializer*, 16> AggregatedInits;
+ };
+
+ class AssignmentMemcpyizer : public FieldMemcpyizer {
+ private:
+
+ // Returns the memcpyable field copied by the given statement, if one
+ // exists. Otherwise r
+ FieldDecl* getMemcpyableField(Stmt *S) {
+ if (!AssignmentsMemcpyable)
+ return 0;
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
+ // Recognise trivial assignments.
+ if (BO->getOpcode() != BO_Assign)
+ return 0;
+ MemberExpr *ME = dyn_cast<MemberExpr>(BO->getLHS());
+ if (!ME)
+ return 0;
+ FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!Field || !isMemcpyableField(Field))
+ return 0;
+ Stmt *RHS = BO->getRHS();
+ if (ImplicitCastExpr *EC = dyn_cast<ImplicitCastExpr>(RHS))
+ RHS = EC->getSubExpr();
+ if (!RHS)
+ return 0;
+ MemberExpr *ME2 = dyn_cast<MemberExpr>(RHS);
+ if (dyn_cast<FieldDecl>(ME2->getMemberDecl()) != Field)
+ return 0;
+ 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;
+ MemberExpr *IOA = dyn_cast<MemberExpr>(MCE->getImplicitObjectArgument());
+ if (!IOA)
+ return 0;
+ FieldDecl *Field = dyn_cast<FieldDecl>(IOA->getMemberDecl());
+ if (!Field || !isMemcpyableField(Field))
+ return 0;
+ MemberExpr *Arg0 = dyn_cast<MemberExpr>(MCE->getArg(0));
+ if (!Arg0 || Field != dyn_cast<FieldDecl>(Arg0->getMemberDecl()))
+ return 0;
+ 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;
+ 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;
+ MemberExpr *ME = dyn_cast<MemberExpr>(DUO->getSubExpr());
+ if (!ME)
+ return 0;
+ FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!Field || !isMemcpyableField(Field))
+ return 0;
+ 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;
+ MemberExpr *ME2 = dyn_cast<MemberExpr>(SUO->getSubExpr());
+ if (!ME2 || Field != dyn_cast<FieldDecl>(ME2->getMemberDecl()))
+ return 0;
+ return Field;
+ }
+
+ return 0;
+ }
+
+ bool AssignmentsMemcpyable;
+ SmallVector<Stmt*, 16> AggregatedStmts;
+
+ public:
+
+ AssignmentMemcpyizer(CodeGenFunction &CGF, const CXXMethodDecl *AD,
+ FunctionArgList &Args)
+ : FieldMemcpyizer(CGF, AD->getParent(), Args[Args.size() - 1]),
+ AssignmentsMemcpyable(CGF.getLangOpts().getGC() == LangOptions::NonGC) {
+ assert(Args.size() == 2);
+ }
+
+ void emitAssignment(Stmt *S) {
+ FieldDecl *F = getMemcpyableField(S);
+ if (F) {
+ addMemcpyableField(F);
+ AggregatedStmts.push_back(S);
+ } else {
+ emitAggregatedStmts();
+ CGF.EmitStmt(S);
+ }
+ }
+
+ void emitAggregatedStmts() {
+ if (AggregatedStmts.size() <= 1) {
+ for (unsigned i = 0; i < AggregatedStmts.size(); ++i)
+ CGF.EmitStmt(AggregatedStmts[i]);
+ reset();
+ }
+
+ emitMemcpy();
+ AggregatedStmts.clear();
+ }
+
+ void finish() {
+ emitAggregatedStmts();
+ }
+ };
+
+}
+
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
@@ -771,26 +1107,47 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
const CXXRecordDecl *ClassDecl = CD->getParent();
- SmallVector<CXXCtorInitializer *, 8> MemberInitializers;
-
- for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
- E = CD->init_end();
- B != E; ++B) {
- CXXCtorInitializer *Member = (*B);
-
- if (Member->isBaseInitializer()) {
- EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
- } else {
- assert(Member->isAnyMemberInitializer() &&
- "Delegating initializer on non-delegating constructor");
- MemberInitializers.push_back(Member);
- }
+ CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
+ E = CD->init_end();
+
+ llvm::BasicBlock *BaseCtorContinueBB = 0;
+ if (ClassDecl->getNumVBases() &&
+ !CGM.getTarget().getCXXABI().hasConstructorVariants()) {
+ // The ABIs that don't have constructor variants need to put a branch
+ // before the virtual base initialization code.
+ BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this);
+ assert(BaseCtorContinueBB);
+ }
+
+ // Virtual base initializers first.
+ for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) {
+ EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
+ }
+
+ if (BaseCtorContinueBB) {
+ // Complete object handler should continue to the remaining initializers.
+ Builder.CreateBr(BaseCtorContinueBB);
+ EmitBlock(BaseCtorContinueBB);
+ }
+
+ // Then, non-virtual base initializers.
+ for (; B != E && (*B)->isBaseInitializer(); B++) {
+ assert(!(*B)->isBaseVirtual());
+ EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
}
InitializeVTablePointers(ClassDecl);
- for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I)
- EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
+ // And finally, initialize class members.
+ ConstructorMemcpyizer CM(*this, CD, Args);
+ for (; B != E; B++) {
+ CXXCtorInitializer *Member = (*B);
+ assert(!Member->isBaseInitializer());
+ assert(Member->isAnyMemberInitializer() &&
+ "Delegating initializer on non-delegating constructor");
+ CM.addMemberInitializer(Member);
+ }
+ CM.finish();
}
static bool
@@ -893,7 +1250,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
if (DtorType == Dtor_Deleting) {
EnterDtorCleanups(Dtor, Dtor_Deleting);
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- LoadCXXThis());
+ /*Delegating=*/false, LoadCXXThis());
PopCleanupBlock();
return;
}
@@ -920,9 +1277,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// Enter the cleanup scopes for virtual bases.
EnterDtorCleanups(Dtor, Dtor_Complete);
- if (!isTryBody && CGM.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ if (!isTryBody &&
+ CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) {
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
- LoadCXXThis());
+ /*Delegating=*/false, LoadCXXThis());
break;
}
// Fallthrough: act like we're in the base variant.
@@ -946,7 +1304,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// -fapple-kext must inline any call to this dtor into
// the caller's body.
if (getLangOpts().AppleKext)
- CurFn->addFnAttr(llvm::Attributes::AlwaysInline);
+ CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
break;
}
@@ -958,6 +1316,24 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
}
+void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) {
+ const CXXMethodDecl *AssignOp = cast<CXXMethodDecl>(CurGD.getDecl());
+ const Stmt *RootS = AssignOp->getBody();
+ assert(isa<CompoundStmt>(RootS) &&
+ "Body of an implicit assignment operator should be compound stmt.");
+ const CompoundStmt *RootCS = cast<CompoundStmt>(RootS);
+
+ 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);
+ }
+ AM.finish();
+}
+
namespace {
/// Call the operator delete associated with the current destructor.
struct CallDtorDelete : EHScopeStack::Cleanup {
@@ -971,6 +1347,32 @@ namespace {
}
};
+ struct CallDtorDeleteConditional : EHScopeStack::Cleanup {
+ llvm::Value *ShouldDeleteCondition;
+ public:
+ CallDtorDeleteConditional(llvm::Value *ShouldDeleteCondition)
+ : ShouldDeleteCondition(ShouldDeleteCondition) {
+ assert(ShouldDeleteCondition != NULL);
+ }
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
+ llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
+ llvm::Value *ShouldCallDelete
+ = CGF.Builder.CreateIsNull(ShouldDeleteCondition);
+ CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
+
+ CGF.EmitBlock(callDeleteBB);
+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
+ CGF.getContext().getTagDeclType(ClassDecl));
+ CGF.Builder.CreateBr(continueBB);
+
+ CGF.EmitBlock(continueBB);
+ }
+ };
+
class DestroyField : public EHScopeStack::Cleanup {
const FieldDecl *field;
CodeGenFunction::Destroyer *destroyer;
@@ -1009,7 +1411,14 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
if (DtorType == Dtor_Deleting) {
assert(DD->getOperatorDelete() &&
"operator delete missing - EmitDtorEpilogue");
- EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+ 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.
+ EHStack.pushCleanup<CallDtorDeleteConditional>(
+ NormalAndEHCleanup, CXXStructorImplicitParamValue);
+ } else {
+ EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+ }
return;
}
@@ -1089,8 +1498,6 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
/// constructor for each of several members of an array.
///
/// \param ctor the constructor to call for each element
-/// \param argBegin,argEnd the arguments to evaluate and pass to the
-/// constructor
/// \param arrayType the type of the array to initialize
/// \param arrayBegin an arrayType*
/// \param zeroInitialize true if each element should be
@@ -1116,8 +1523,6 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
/// \param ctor the constructor to call for each element
/// \param numElements the number of elements in the array;
/// may be zero
-/// \param argBegin,argEnd the arguments to evaluate and pass to the
-/// constructor
/// \param arrayBegin a T*, where T is the type constructed by ctor
/// \param zeroInitialize true if each element should be
/// zero-initialized before it is constructed
@@ -1191,7 +1596,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
}
EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/ false,
- cur, argBegin, argEnd);
+ /*Delegating=*/false, cur, argBegin, argEnd);
}
// Go to the next element.
@@ -1219,12 +1624,13 @@ void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
const CXXDestructorDecl *dtor = record->getDestructor();
assert(!dtor->isTrivial());
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
- addr);
+ /*Delegating=*/false, addr);
}
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -1239,6 +1645,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
Parent->getLocation());
}
+ // If this is a trivial constructor, just emit what's needed.
if (D->isTrivial()) {
if (ArgBeg == ArgEnd) {
// Trivial default constructor, no codegen required.
@@ -1258,12 +1665,12 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return;
}
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
-
- // FIXME: Provide a source location here.
- EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, ArgBeg, ArgEnd);
+ // Non-trivial constructors are handled in an ABI-specific manner.
+ llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
+ ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
+ CalleeWithThisReturn = Callee;
}
void
@@ -1333,8 +1740,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
++I;
// vtt
- if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
- /*ForVirtualBase=*/false)) {
+ if (llvm::Value *VTT = GetVTTParameter(GlobalDecl(Ctor, CtorType),
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/true)) {
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.add(RValue::get(VTT), VoidPP);
@@ -1351,9 +1759,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
- CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
- ReturnValueSlot(), DelegateArgs, Ctor);
+ Callee, ReturnValueSlot(), DelegateArgs, Ctor);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
+ CalleeWithThisReturn = Callee;
}
namespace {
@@ -1368,7 +1779,7 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
- Addr);
+ /*Delegating=*/true, Addr);
}
};
}
@@ -1404,9 +1815,10 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
bool ForVirtualBase,
+ bool Delegating,
llvm::Value *This) {
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
- ForVirtualBase);
+ llvm::Value *VTT = GetVTTParameter(GlobalDecl(DD, Type),
+ ForVirtualBase, Delegating);
llvm::Value *Callee = 0;
if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
@@ -1417,7 +1829,11 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
// FIXME: Provide a source location here.
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, 0, 0);
+ VTT, getContext().getPointerType(getContext().VoidPtrTy),
+ 0, 0);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
+ CalleeWithThisReturn = Callee;
}
namespace {
@@ -1430,7 +1846,8 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false, Addr);
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false, Addr);
}
};
}
@@ -1757,7 +2174,7 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
DeclarationName operatorName
= getContext().DeclarationNames.getCXXOperatorName(OO_Call);
CXXMethodDecl *callOperator =
- cast<CXXMethodDecl>(*lambda->lookup(operatorName).first);
+ cast<CXXMethodDecl>(lambda->lookup(operatorName).front());
// Get the address of the call operator.
const CGFunctionInfo &calleeFnInfo =
@@ -1773,7 +2190,7 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
ReturnValueSlot returnSlot;
if (!resultType->isVoidType() &&
calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(calleeFnInfo.getReturnType()))
+ !hasScalarEvaluationKind(calleeFnInfo.getReturnType()))
returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified());
// We don't need to separately arrange the call arguments because
@@ -1787,6 +2204,8 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
// If necessary, copy the returned value into the slot.
if (!resultType->isVoidType() && returnSlot.isNull())
EmitReturnOfRValue(RV, resultType);
+ else
+ EmitBranchThroughCleanup(ReturnBlock);
}
void CodeGenFunction::EmitLambdaBlockInvokeBody() {
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index f9ea7e0a26a7..861d31fb7fc9 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -52,7 +52,8 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) 0);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
- CGF.StoreComplexToAddr(V, addr, /*volatile*/ false);
+ CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0));
+ CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1));
return saved_type(addr, ComplexAddress);
}
@@ -79,8 +80,13 @@ RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
return RValue::getAggregate(Value);
case AggregateAddress:
return RValue::getAggregate(CGF.Builder.CreateLoad(Value));
- case ComplexAddress:
- return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false));
+ case ComplexAddress: {
+ llvm::Value *real =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 0));
+ llvm::Value *imag =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 1));
+ return RValue::getComplex(real, imag);
+ }
}
llvm_unreachable("bad saved r-value kind");
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 80fa09be7473..711d6861507c 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -12,30 +12,30 @@
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGBlocks.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Instructions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -79,7 +79,7 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
llvm::MDNode *N = D;
LexicalBlockStack.pop_back();
LexicalBlockStack.push_back(N);
- } else if (Scope.isLexicalBlock()) {
+ } else if (Scope.isLexicalBlock() || Scope.isSubprogram()) {
llvm::DIDescriptor D
= DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
@@ -126,7 +126,9 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
return FII->getName();
// Otherwise construct human readable name for debug info.
- std::string NS = FD->getNameAsString();
+ SmallString<128> NS;
+ llvm::raw_svector_ostream OS(NS);
+ FD->printName(OS);
// Add any template specialization args.
if (Info) {
@@ -134,15 +136,15 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
const TemplateArgument *Args = TArgs->data();
unsigned NumArgs = TArgs->size();
PrintingPolicy Policy(CGM.getLangOpts());
- NS += TemplateSpecializationType::PrintTemplateArgumentList(Args,
- NumArgs,
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
+ Policy);
}
// Copy this name on the side and use its reference.
- char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
- memcpy(StrPtr, NS.data(), NS.length());
- return StringRef(StrPtr, NS.length());
+ OS.flush();
+ char *StrPtr = DebugInfoNames.Allocate<char>(NS.size());
+ memcpy(StrPtr, NS.data(), NS.size());
+ return StringRef(StrPtr, NS.size());
}
StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
@@ -199,8 +201,12 @@ CGDebugInfo::getClassName(const RecordDecl *RD) {
}
StringRef Name = RD->getIdentifier()->getName();
PrintingPolicy Policy(CGM.getLangOpts());
- std::string TemplateArgList =
- TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy);
+ SmallString<128> TemplateArgList;
+ {
+ llvm::raw_svector_ostream OS(TemplateArgList);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
+ Policy);
+ }
// Copy this name on the side and use its reference.
size_t Length = Name.size() + TemplateArgList.size();
@@ -256,9 +262,9 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
}
/// getColumnNumber - Get column number for the location.
-unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
+unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) {
// We may not want column information at all.
- if (!CGM.getCodeGenOpts().DebugColumnInfo)
+ if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo)
return 0;
// If the location is invalid then use the current column.
@@ -306,6 +312,12 @@ void CGDebugInfo::CreateCompileUnit() {
char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length());
memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length());
StringRef Filename(FilenamePtr, MainFileName.length());
+
+ // Save split dwarf file string.
+ std::string SplitDwarfFile = CGM.getCodeGenOpts().SplitDwarfFile;
+ char *SplitDwarfPtr = DebugInfoNames.Allocate<char>(SplitDwarfFile.length());
+ memcpy(SplitDwarfPtr, SplitDwarfFile.c_str(), SplitDwarfFile.length());
+ StringRef SplitDwarfFilename(SplitDwarfPtr, SplitDwarfFile.length());
unsigned LangTag;
const LangOptions &LO = CGM.getLangOpts();
@@ -330,10 +342,10 @@ void CGDebugInfo::CreateCompileUnit() {
RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
// Create new compile unit.
- DBuilder.createCompileUnit(
- LangTag, Filename, getCurrentDirname(),
- Producer,
- LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
+ DBuilder.createCompileUnit(LangTag, Filename, getCurrentDirname(),
+ Producer, LO.Optimize,
+ CGM.getCodeGenOpts().DwarfDebugFlags,
+ RuntimeVers, SplitDwarfFilename);
// FIXME - Eliminate TheCU.
TheCU = llvm::DICompileUnit(DBuilder.getCU());
}
@@ -380,22 +392,12 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
- llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object",
- getOrCreateMainFile(),
- 0, 0, 0, 0,
- llvm::DIArray());
-
- llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy);
- SmallVector<llvm::Value *, 1> EltTys;
- llvm::DIType FieldTy =
- DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa",
- getOrCreateMainFile(), 0, Size,
- 0, 0, 0, ISATy);
- EltTys.push_back(FieldTy);
- llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
+ ObjTy =
+ DBuilder.createStructType(TheCU, "objc_object", getOrCreateMainFile(),
+ 0, 0, 0, 0, llvm::DIType(), llvm::DIArray());
- ObjNode->replaceOperandWith(10, Elements);
- ObjTy = llvm::DIType(ObjNode);
+ ObjTy.setTypeArray(DBuilder.getOrCreateArray(&*DBuilder.createMemberType(
+ ObjTy, "isa", getOrCreateMainFile(), 0, Size, 0, 0, 0, ISATy)));
return ObjTy;
}
case BuiltinType::ObjCSel: {
@@ -407,6 +409,34 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
0);
return SelTy;
}
+
+ case BuiltinType::OCLImage1d:
+ return getOrCreateStructPtrType("opencl_image1d_t",
+ OCLImage1dDITy);
+ case BuiltinType::OCLImage1dArray:
+ return getOrCreateStructPtrType("opencl_image1d_array_t",
+ OCLImage1dArrayDITy);
+ case BuiltinType::OCLImage1dBuffer:
+ return getOrCreateStructPtrType("opencl_image1d_buffer_t",
+ OCLImage1dBufferDITy);
+ case BuiltinType::OCLImage2d:
+ return getOrCreateStructPtrType("opencl_image2d_t",
+ OCLImage2dDITy);
+ case BuiltinType::OCLImage2dArray:
+ return getOrCreateStructPtrType("opencl_image2d_array_t",
+ OCLImage2dArrayDITy);
+ case BuiltinType::OCLImage3d:
+ return getOrCreateStructPtrType("opencl_image3d_t",
+ OCLImage3dDITy);
+ case BuiltinType::OCLSampler:
+ return DBuilder.createBasicType("opencl_sampler_t",
+ CGM.getContext().getTypeSize(BT),
+ CGM.getContext().getTypeAlign(BT),
+ llvm::dwarf::DW_ATE_unsigned);
+ case BuiltinType::OCLEvent:
+ return getOrCreateStructPtrType("opencl_event_t",
+ OCLEventDITy);
+
case BuiltinType::UChar:
case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
case BuiltinType::Char_S:
@@ -502,6 +532,13 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
llvm::DIFile Unit) {
+
+ // The frontend treats 'id' as a typedef to an ObjCObjectType,
+ // whereas 'id<protocol>' is treated as an ObjCPointerType. For the
+ // debug info, we want to emit 'id' in both cases.
+ if (Ty->isObjCQualifiedIdType())
+ return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
+
llvm::DIType DbgTy =
CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
@@ -556,7 +593,7 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
if (!RD->isDependentType()) {
llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
- getOrCreateMainFile());
+ getOrCreateMainFile());
return llvm::DIDescriptor(Ty);
}
}
@@ -590,7 +627,6 @@ llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
return RetTy;
}
return getOrCreateType(PointeeTy, Unit);
-
}
llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
@@ -601,7 +637,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
return DBuilder.createReferenceType(Tag,
CreatePointeeType(PointeeTy, Unit));
-
+
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
@@ -613,6 +649,18 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
Size, Align);
}
+llvm::DIType CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache) {
+ if (Cache.Verify())
+ return Cache;
+ Cache =
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ Name, TheCU, getOrCreateMainFile(),
+ 0);
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ Cache = DBuilder.createPointerType(Cache, Size);
+ return Cache;
+}
+
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
llvm::DIFile Unit) {
if (BlockLiteralGenericSet)
@@ -639,7 +687,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTy = DBuilder.createStructType(Unit, "__block_descriptor",
Unit, LineNo, FieldOffset, 0,
- Flags, Elements);
+ Flags, llvm::DIType(), Elements);
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -669,7 +717,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
Unit, LineNo, FieldOffset, 0,
- Flags, Elements);
+ Flags, llvm::DIType(), Elements);
BlockLiteralGenericSet = true;
BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
@@ -715,33 +763,6 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
}
-void CGDebugInfo::
-CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) {
-
- for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
- I != E; ++I)
- if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
- if (V->getInit()) {
- const APValue *Value = V->evaluateValue();
- if (Value && Value->isInt()) {
- llvm::ConstantInt *CI
- = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
-
- // Create the descriptor for static variable.
- llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
- StringRef VName = V->getName();
- llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
- // Do not use DIGlobalVariable for enums.
- if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
- DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
- getLineNumber(V->getLocation()),
- VTy, true, CI);
- }
- }
- }
- }
-}
-
llvm::DIType CGDebugInfo::createFieldType(StringRef name,
QualType type,
uint64_t sizeInBitsOverride,
@@ -775,94 +796,159 @@ llvm::DIType CGDebugInfo::createFieldType(StringRef name,
alignInBits, offsetInBits, flags, debugType);
}
+/// CollectRecordLambdaFields - Helper for CollectRecordFields.
+void CGDebugInfo::
+CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
+ // has the name and the location of the variable so we should iterate over
+ // both concurrently.
+ const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl);
+ RecordDecl::field_iterator Field = CXXDecl->field_begin();
+ 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;
+ if (C.capturesVariable()) {
+ VarDecl *V = C.getCapturedVar();
+ llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
+ StringRef VName = V->getName();
+ uint64_t SizeInBitsOverride = 0;
+ if (Field->isBitField()) {
+ SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+ llvm::DIType fieldType
+ = createFieldType(VName, Field->getType(), SizeInBitsOverride,
+ C.getLocation(), Field->getAccess(),
+ layout.getFieldOffset(fieldno), VUnit, RecordTy);
+ elements.push_back(fieldType);
+ } else {
+ // TODO: Need to handle 'this' in some way by probably renaming the
+ // this of the lambda class and having a field member of 'this' or
+ // by using AT_object_pointer for the function and having that be
+ // used as 'this' for semantic references.
+ assert(C.capturesThis() && "Field that isn't captured and isn't this?");
+ FieldDecl *f = *Field;
+ llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
+ QualType type = f->getType();
+ llvm::DIType fieldType
+ = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
+ layout.getFieldOffset(fieldno), VUnit, RecordTy);
+
+ elements.push_back(fieldType);
+ }
+ }
+}
+
+/// CollectRecordStaticField - Helper for CollectRecordFields.
+void CGDebugInfo::
+CollectRecordStaticField(const VarDecl *Var,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ // Create the descriptor for the static variable, with or without
+ // constant initializers.
+ llvm::DIFile VUnit = getOrCreateFile(Var->getLocation());
+ llvm::DIType VTy = getOrCreateType(Var->getType(), VUnit);
+
+ // Do not describe enums as static members.
+ if (VTy.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
+ return;
+
+ unsigned LineNumber = getLineNumber(Var->getLocation());
+ StringRef VName = Var->getName();
+ llvm::Constant *C = NULL;
+ if (Var->getInit()) {
+ const APValue *Value = Var->evaluateValue();
+ if (Value) {
+ if (Value->isInt())
+ C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
+ if (Value->isFloat())
+ C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat());
+ }
+ }
+
+ unsigned Flags = 0;
+ AccessSpecifier Access = Var->getAccess();
+ if (Access == clang::AS_private)
+ Flags |= llvm::DIDescriptor::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ Flags |= llvm::DIDescriptor::FlagProtected;
+
+ llvm::DIType GV = DBuilder.createStaticMemberType(RecordTy, VName, VUnit,
+ LineNumber, VTy, Flags, C);
+ elements.push_back(GV);
+ StaticDataMemberCache[Var->getCanonicalDecl()] = llvm::WeakVH(GV);
+}
+
+/// CollectRecordNormalField - Helper for CollectRecordFields.
+void CGDebugInfo::
+CollectRecordNormalField(const FieldDecl *field, uint64_t OffsetInBits,
+ llvm::DIFile tunit,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ StringRef name = field->getName();
+ QualType type = field->getType();
+
+ // Ignore unnamed fields unless they're anonymous structs/unions.
+ if (name.empty() && !type->isRecordType())
+ return;
+
+ uint64_t SizeInBitsOverride = 0;
+ if (field->isBitField()) {
+ SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+
+ llvm::DIType fieldType
+ = createFieldType(name, type, SizeInBitsOverride,
+ field->getLocation(), field->getAccess(),
+ OffsetInBits, tunit, RecordTy);
+
+ elements.push_back(fieldType);
+}
+
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
SmallVectorImpl<llvm::Value *> &elements,
llvm::DIType RecordTy) {
- unsigned fieldNo = 0;
- const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
- // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
- // has the name and the location of the variable so we should iterate over
- // both concurrently.
- if (CXXDecl && CXXDecl->isLambda()) {
- RecordDecl::field_iterator Field = CXXDecl->field_begin();
- 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;
- if (C.capturesVariable()) {
- VarDecl *V = C.getCapturedVar();
- llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
- StringRef VName = V->getName();
- uint64_t SizeInBitsOverride = 0;
- if (Field->isBitField()) {
- SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
- }
- llvm::DIType fieldType
- = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
- Field->getAccess(), layout.getFieldOffset(fieldno),
- VUnit, RecordTy);
- elements.push_back(fieldType);
- } else {
- // TODO: Need to handle 'this' in some way by probably renaming the
- // this of the lambda class and having a field member of 'this' or
- // by using AT_object_pointer for the function and having that be
- // used as 'this' for semantic references.
- assert(C.capturesThis() && "Field that isn't captured and isn't this?");
- FieldDecl *f = *Field;
- llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
- QualType type = f->getType();
- llvm::DIType fieldType
- = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
- layout.getFieldOffset(fieldNo), VUnit, RecordTy);
-
- elements.push_back(fieldType);
- }
- }
- } else {
+ if (CXXDecl && CXXDecl->isLambda())
+ CollectRecordLambdaFields(CXXDecl, elements, RecordTy);
+ else {
+ const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
+
+ // Field number for non-static fields.
+ unsigned fieldNo = 0;
+
+ // Bookkeeping for an ms struct, which ignores certain fields.
bool IsMsStruct = record->isMsStruct(CGM.getContext());
const FieldDecl *LastFD = 0;
- for (RecordDecl::field_iterator I = record->field_begin(),
- E = record->field_end();
- I != E; ++I, ++fieldNo) {
- FieldDecl *field = *I;
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
- --fieldNo;
- continue;
- }
- LastFD = field;
- }
-
- StringRef name = field->getName();
- QualType type = field->getType();
- // Ignore unnamed fields unless they're anonymous structs/unions.
- if (name.empty() && !type->isRecordType()) {
- LastFD = field;
- continue;
- }
+ // 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))
+ CollectRecordStaticField(V, elements, RecordTy);
+ else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are
+ // completely ignored; we don't even count them.
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD))
+ continue;
+ LastFD = field;
+ }
+ CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),
+ tunit, elements, RecordTy);
- uint64_t SizeInBitsOverride = 0;
- if (field->isBitField()) {
- SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
+ // Bump field number for next field.
+ ++fieldNo;
}
-
- llvm::DIType fieldType
- = createFieldType(name, type, SizeInBitsOverride,
- field->getLocation(), field->getAccess(),
- layout.getFieldOffset(fieldNo), tunit, RecordTy);
-
- elements.push_back(fieldType);
- }
}
}
@@ -872,13 +958,18 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
llvm::DIType
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile Unit) {
- llvm::DIType FnTy
- = getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(),
- 0),
- Unit);
+ const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
+ if (Method->isStatic())
+ return getOrCreateType(QualType(Func, 0), Unit);
+ return getOrCreateInstanceMethodType(Method->getThisType(CGM.getContext()),
+ Func, Unit);
+}
+llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType(
+ QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit) {
// Add "this" pointer.
- llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
+ llvm::DIArray Args = llvm::DICompositeType(
+ getOrCreateType(QualType(Func, 0), Unit)).getTypeArray();
assert (Args.getNumElements() && "Invalid number of arguments!");
SmallVector<llvm::Value *, 16> Elts;
@@ -886,32 +977,28 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(Args.getElement(0));
- if (!Method->isStatic()) {
- // "this" pointer is always first argument.
- QualType ThisPtr = Method->getThisType(CGM.getContext());
-
- const CXXRecordDecl *RD = Method->getParent();
- if (isa<ClassTemplateSpecializationDecl>(RD)) {
- // Create pointer type directly in this case.
- const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
- QualType PointeeTy = ThisPtrTy->getPointeeType();
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
- uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
- llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
- llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- // TODO: This and the artificial type below are misleading, the
- // types aren't artificial the argument is, but the current
- // metadata doesn't represent that.
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- } else {
- llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- }
+ // "this" pointer is always first argument.
+ const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl();
+ if (isa<ClassTemplateSpecializationDecl>(RD)) {
+ // Create pointer type directly in this case.
+ const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
+ QualType PointeeTy = ThisPtrTy->getPointeeType();
+ unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
+ llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
+ llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ // TODO: This and the artificial type below are misleading, the
+ // types aren't artificial the argument is, but the current
+ // metadata doesn't represent that.
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
+ } else {
+ llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
}
// Copy rest of the arguments.
@@ -1199,7 +1286,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
= DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
- 0, Size, 0, 0, 0,
+ 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
}
@@ -1215,10 +1302,10 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
/// getOrCreateInterfaceType - Emit an objective c interface type standalone
/// debug info.
llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
- SourceLocation Loc) {
+ SourceLocation Loc) {
assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
- DBuilder.retainType(T);
+ RetainedTypes.push_back(D.getAsOpaquePtr());
return T;
}
@@ -1236,18 +1323,19 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
+ llvm::DICompositeType FwdDecl(
+ getOrCreateLimitedType(QualType(Ty, 0), DefUnit));
+ assert(FwdDecl.Verify() &&
+ "The debug type of a RecordType should be a DICompositeType");
if (FwdDecl.isForwardDecl())
return FwdDecl;
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl);
-
// Push the struct on region stack.
- LexicalBlockStack.push_back(FwdDeclNode);
+ LexicalBlockStack.push_back(&*FwdDecl);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
- // Add this to the completed types cache since we're completing it.
+ // Add this to the completed-type cache while we're completing it recursively.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Convert all the elements.
@@ -1263,8 +1351,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
CollectVTableInfo(CXXDecl, DefUnit, EltTys);
}
- // Collect static variables with initializers and other fields.
- CollectRecordStaticVars(RD, FwdDecl);
+ // Collect data fields (including static variables and any initializers).
CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
llvm::DIArray TParamsArray;
if (CXXDecl) {
@@ -1279,19 +1366,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RegionMap.erase(Ty->getDecl());
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- // FIXME: Magic numbers ahoy! These should be changed when we
- // get some enums in llvm/Analysis/DebugInfo.h to refer to
- // them.
- if (RD->isUnion())
- FwdDeclNode->replaceOperandWith(10, Elements);
- else if (CXXDecl) {
- FwdDeclNode->replaceOperandWith(10, Elements);
- FwdDeclNode->replaceOperandWith(13, TParamsArray);
- } else
- FwdDeclNode->replaceOperandWith(10, Elements);
+ FwdDecl.setTypeArray(Elements, TParamsArray);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode);
- return llvm::DIType(FwdDeclNode);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+ return FwdDecl;
}
/// CreateType - get objective-c object type.
@@ -1319,8 +1397,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (!Def) {
llvm::DIType FwdDecl =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- ID->getName(), TheCU, DefUnit, Line,
- RuntimeLang);
+ ID->getName(), TheCU, DefUnit, Line,
+ RuntimeLang);
return FwdDecl;
}
@@ -1334,18 +1412,18 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (ID->getImplementation())
Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
- llvm::DIType RealDecl =
+ llvm::DICompositeType RealDecl =
DBuilder.createStructType(Unit, ID->getName(), DefUnit,
Line, Size, Align, Flags,
- llvm::DIArray(), RuntimeLang);
+ 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.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
+ QualType QualTy = QualType(Ty, 0);
+ CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
- LexicalBlockStack.push_back(FwdDeclNode);
+ LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl));
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
// Convert all the elements.
@@ -1373,13 +1451,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
llvm::MDNode *PropertyNode =
DBuilder.createObjCProperty(PD->getName(),
- PUnit, PLine,
+ PUnit, PLine,
(Getter && Getter->isImplicit()) ? "" :
getSelectorName(PD->getGetterName()),
(Setter && Setter->isImplicit()) ? "" :
getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
+ getOrCreateType(PD->getType(), PUnit));
EltTys.push_back(PropertyNode);
}
@@ -1440,9 +1518,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (ObjCPropertyImplDecl *PImpD =
ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
- SourceLocation Loc = PD->getLocation();
- llvm::DIFile PUnit = getOrCreateFile(Loc);
- unsigned PLine = getLineNumber(Loc);
+ SourceLocation Loc = PD->getLocation();
+ llvm::DIFile PUnit = getOrCreateFile(Loc);
+ unsigned PLine = getLineNumber(Loc);
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
PropertyNode =
@@ -1465,31 +1543,33 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
}
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- FwdDeclNode->replaceOperandWith(10, Elements);
+ 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 llvm::DIType(FwdDeclNode);
+ return RealDecl;
}
llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit);
- int64_t NumElems = Ty->getNumElements();
- int64_t LowerBound = 0;
- if (NumElems == 0)
+ int64_t Count = Ty->getNumElements();
+ if (Count == 0)
// If number of elements are not known then this is an unbounded array.
- // Use Low = 1, Hi = 0 to express such arrays.
- LowerBound = 1;
- else
- --NumElems;
+ // Use Count == -1 to express such arrays.
+ Count = -1;
- llvm::Value *Subscript = DBuilder.getOrCreateSubrange(LowerBound, NumElems);
+ llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count);
llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- return
- DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
+ return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
}
llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
@@ -1523,19 +1603,19 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
SmallVector<llvm::Value *, 8> Subscripts;
QualType EltTy(Ty, 0);
while ((Ty = dyn_cast<ArrayType>(EltTy))) {
- int64_t UpperBound = 0;
- int64_t LowerBound = 0;
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) {
- if (CAT->getSize().getZExtValue())
- UpperBound = CAT->getSize().getZExtValue() - 1;
- } else
- // This is an unbounded array. Use Low = 1, Hi = 0 to express such
- // arrays.
- LowerBound = 1;
+ // If the number of elements is known, then count is that number. Otherwise,
+ // it's -1. This allows us to represent a subrange with an array of 0
+ // elements, like this:
+ //
+ // struct foo {
+ // int x[0];
+ // };
+ int64_t Count = -1; // Count == -1 is an unbounded array.
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Count = CAT->getSize().getZExtValue();
// FIXME: Verify this is right for VLAs.
- Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound,
- UpperBound));
+ Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
EltTy = Ty->getElementType();
}
@@ -1561,38 +1641,15 @@ llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
llvm::DIFile U) {
- QualType PointerDiffTy = CGM.getContext().getPointerDiffType();
- llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U);
-
- if (!Ty->getPointeeType()->isFunctionType()) {
- // We have a data member pointer type.
- return PointerDiffDITy;
- }
-
- // We have a member function pointer type. Treat it as a struct with two
- // ptrdiff_t members.
- std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty);
-
- uint64_t FieldOffset = 0;
- llvm::Value *ElementTypes[2];
-
- // FIXME: This should be a DW_TAG_pointer_to_member type.
- ElementTypes[0] =
- DBuilder.createMemberType(U, "ptr", U, 0,
- Info.first, Info.second, FieldOffset, 0,
- PointerDiffDITy);
- FieldOffset += Info.first;
-
- ElementTypes[1] =
- DBuilder.createMemberType(U, "ptr", U, 0,
- Info.first, Info.second, FieldOffset, 0,
- PointerDiffDITy);
-
- llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes);
-
- return DBuilder.createStructType(U, StringRef("test"),
- U, 0, FieldOffset,
- 0, 0, Elements);
+ llvm::DIType ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U);
+ if (!Ty->getPointeeType()->isFunctionType())
+ return DBuilder.createMemberPointerType(
+ CreatePointeeType(Ty->getPointeeType(), U), ClassType);
+ return DBuilder.createMemberPointerType(getOrCreateInstanceMethodType(
+ CGM.getContext().getPointerType(
+ QualType(Ty->getClass(), Ty->getPointeeType().getCVRQualifiers())),
+ Ty->getPointeeType()->getAs<FunctionProtoType>(), U),
+ ClassType);
}
llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
@@ -1651,12 +1708,14 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
return DbgTy;
}
-static QualType UnwrapTypeForDebugInfo(QualType T) {
+static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
+ Qualifiers Quals;
do {
+ Quals += T.getLocalQualifiers();
QualType LastT = T;
switch (T->getTypeClass()) {
default:
- return T;
+ return C.getQualifiedType(T.getTypePtr(), Quals);
case Type::TemplateSpecialization:
T = cast<TemplateSpecializationType>(T)->desugar();
break;
@@ -1681,13 +1740,8 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::Paren:
T = cast<ParenType>(T)->getInnerType();
break;
- case Type::SubstTemplateTypeParm: {
- // We need to keep the qualifiers handy since getReplacementType()
- // will strip them away.
- unsigned Quals = T.getLocalFastQualifiers();
+ case Type::SubstTemplateTypeParm:
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
- T.addFastQualifiers(Quals);
- }
break;
case Type::Auto:
T = cast<AutoType>(T)->getDeducedType();
@@ -1695,8 +1749,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
}
assert(T != LastT && "Type unwrapping failed to unwrap!");
- if (T == LastT)
- return T;
+ (void)LastT;
} while (true);
}
@@ -1704,9 +1757,16 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ 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());
if (it != TypeCache.end()) {
@@ -1723,20 +1783,40 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ 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()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
+ if (it != CompletedTypeCache.end())
+ V = it->second;
+ else {
+ V = getCachedInterfaceTypeOrNull(Ty);
}
+ // Verify that any cached debug info still exists.
+ if (V != 0)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+
return llvm::DIType();
}
+/// 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;
+
+ return 0;
+}
/// getOrCreateType - Get the type from the cache or create a new
/// one if necessary.
@@ -1745,7 +1825,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
return llvm::DIType();
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
llvm::DIType T = getCompletedTypeOrNull(Ty);
@@ -1754,21 +1834,63 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
+ void* TyPtr = Ty.getAsOpaquePtr();
+
+ // And update the type cache.
+ TypeCache[TyPtr] = Res;
llvm::DIType TC = getTypeOrNull(Ty);
if (TC.Verify() && TC.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
- static_cast<llvm::Value*>(TC)));
-
- // And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
+ 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 interace type, we return a forward
+ // declaration that gets RAUW'd in CGDebugInfo::finalize().
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ::iterator it = ObjCInterfaceCache.find(TyPtr);
+ if (it != ObjCInterfaceCache.end())
+ TC = llvm::DIType(cast<llvm::MDNode>(it->second.first));
+ else
+ 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.
+ ObjCInterfaceCache[TyPtr] = std::make_pair(TC, 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[Ty.getAsOpaquePtr()] = Res;
+ CompletedTypeCache[TyPtr] = Res;
return Res;
}
+/// Currently the checksum merely consists of the number of ivars.
+unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl
+ *InterfaceDecl) {
+ unsigned IvarNo = 0;
+ for (const ObjCIvarDecl *Ivar = InterfaceDecl->all_declared_ivar_begin();
+ Ivar != 0; Ivar = Ivar->getNextIvar()) ++IvarNo;
+ return IvarNo;
+}
+
+ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
+ switch (Ty->getTypeClass()) {
+ case Type::ObjCObjectPointer:
+ return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(Ty)->getDecl();
+ default:
+ return 0;
+ }
+}
+
/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
// Handle qualifiers, which recursively handles what they refer to.
@@ -1852,12 +1974,12 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
/// getOrCreateLimitedType - Get the type from the cache or create a new
/// limited type if necessary.
llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
- llvm::DIFile Unit) {
+ llvm::DIFile Unit) {
if (Ty.isNull())
return llvm::DIType();
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
llvm::DIType T = getTypeOrNull(Ty);
@@ -1901,46 +2023,45 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- llvm::TrackingVH<llvm::MDNode> RealDecl;
+ llvm::DICompositeType RealDecl;
if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
+ Size, Align, 0, llvm::DIArray());
else if (RD->isClass()) {
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, 0, llvm::DIType(),
- llvm::DIArray(), llvm::DIType(),
- llvm::DIArray());
+ Size, Align, 0, 0, llvm::DIType(),
+ llvm::DIArray(), llvm::DIType(),
+ llvm::DIArray());
} else
RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
+ Size, Align, 0, llvm::DIType(), llvm::DIArray());
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl);
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
if (CXXDecl) {
// A class's primary base or the class itself contains the vtable.
- llvm::MDNode *ContainingType = NULL;
+ llvm::DICompositeType ContainingType;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non virtual primary base root.
while (1) {
- const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
- const CXXRecordDecl *PBT = BRL.getPrimaryBase();
- if (PBT && !BRL.isPrimaryBaseVirtual())
- PBase = PBT;
- else
- break;
+ const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
+ const CXXRecordDecl *PBT = BRL.getPrimaryBase();
+ if (PBT && !BRL.isPrimaryBaseVirtual())
+ PBase = PBT;
+ else
+ break;
}
- ContainingType =
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
- }
- else if (CXXDecl->isDynamicClass())
+ ContainingType = llvm::DICompositeType(
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit));
+ } else if (CXXDecl->isDynamicClass())
ContainingType = RealDecl;
- RealDecl->replaceOperandWith(12, ContainingType);
+ RealDecl.setContainingType(ContainingType);
}
return llvm::DIType(RealDecl);
}
@@ -2027,8 +2148,9 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
// "self" pointer is always first argument.
- llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F);
- Elts.push_back(DBuilder.createObjectPointerType(SelfTy));
+ QualType SelfDeclTy = OMethod->getSelfDecl()->getType();
+ llvm::DIType SelfTy = getOrCreateType(SelfDeclTy, F);
+ Elts.push_back(CreateSelfType(SelfDeclTy, SelfTy));
// "_cmd" pointer is always second argument.
llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
Elts.push_back(DBuilder.createArtificialType(CmdTy));
@@ -2084,13 +2206,18 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
}
Name = getFunctionName(FD);
- // Use mangled name as linkage name for c/c++ functions.
+ // Use mangled name as linkage name for C/C++ functions.
if (FD->hasPrototype()) {
LinkageName = CGM.getMangledName(GD);
Flags |= llvm::DIDescriptor::FlagPrototyped;
}
+ // No need to replicate the linkage name if it isn't different from the
+ // subprogram name, no need to have it at all unless coverage is enabled or
+ // debug is set to more than just line tables.
if (LinkageName == Name ||
- CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)
+ (!CGM.getCodeGenOpts().EmitGcovArcs &&
+ !CGM.getCodeGenOpts().EmitGcovNotes &&
+ CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly))
LinkageName = StringRef();
if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
@@ -2151,7 +2278,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
/// EmitLocation - Emit metadata to indicate a change in line/column
/// information in the source file.
-void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
+void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
+ bool ForceColumnInfo) {
// Update our current location
setLocation(Loc);
@@ -2163,16 +2291,19 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
if (CurLoc == PrevLoc ||
SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc))
// New Builder may not be in sync with CGDebugInfo.
- if (!Builder.getCurrentDebugLocation().isUnknown())
+ if (!Builder.getCurrentDebugLocation().isUnknown() &&
+ Builder.getCurrentDebugLocation().getScope(CGM.getLLVMContext()) ==
+ LexicalBlockStack.back())
return;
// Update last state.
PrevLoc = CurLoc;
llvm::MDNode *Scope = LexicalBlockStack.back();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc),
- getColumnNumber(CurLoc),
- Scope));
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get
+ (getLineNumber(CurLoc),
+ getColumnNumber(CurLoc, ForceColumnInfo),
+ Scope));
}
/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
@@ -2229,7 +2360,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
-llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *XOffset) {
SmallVector<llvm::Value *, 5> EltTys;
@@ -2248,7 +2379,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
- bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type);
+ bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
@@ -2256,6 +2387,14 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
&FieldOffset));
}
+ bool HasByrefExtendedLayout;
+ Qualifiers::ObjCLifetime Lifetime;
+ if (CGM.getContext().getByrefLifetime(Type,
+ Lifetime, HasByrefExtendedLayout)
+ && HasByrefExtendedLayout)
+ EltTys.push_back(CreateMemberType(Unit, FType,
+ "__byref_variable_layout",
+ &FieldOffset));
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
@@ -2292,7 +2431,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
- Elements);
+ llvm::DIType(), Elements);
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -2324,7 +2463,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// If an aggregate variable has non trivial destructor or non trivial copy
// constructor than it is pass indirectly. Let debug info know about this
// by using reference of the aggregate type as a argument type.
- if (!Record->hasTrivialCopyConstructor() ||
+ if (Record->hasNonTrivialCopyConstructor() ||
!Record->hasTrivialDestructor())
Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
}
@@ -2392,25 +2531,11 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
return;
}
-
- // Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- Name, Unit, Line, Ty,
- CGM.getLangOpts().Optimize, Flags, ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- return;
- }
-
- // If VD is an anonymous union then Storage represents value for
- // all union fields.
- if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
+ } else if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
+ // If VD is an anonymous union then Storage represents value for
+ // all union fields.
const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
- if (RD->isUnion()) {
+ if (RD->isUnion() && RD->isAnonymousStructOrUnion()) {
for (RecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end();
I != E; ++I) {
@@ -2434,8 +2559,20 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
+ return;
}
}
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
+ Name, Unit, Line, Ty,
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
@@ -2445,6 +2582,19 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
}
+/// Look up the completed type for a self pointer in the TypeCache and
+/// create a copy of it with the ObjectPointer and Artificial flags
+/// set. If the type is not cached, a new one is created. This should
+/// never happen though, since creating a type for the implicit self
+/// argument implies that we already parsed the interface definition
+/// and the ivar declarations in the implementation.
+llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType Ty) {
+ llvm::DIType CachedTy = getTypeOrNull(QualTy);
+ if (CachedTy.Verify()) Ty = CachedTy;
+ else DEBUG(llvm::dbgs() << "No cached type for self.");
+ return DBuilder.createObjectPointerType(Ty);
+}
+
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder,
@@ -2468,7 +2618,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
// Self is passed along as an implicit non-arg variable in a
// block. Mark it as the object pointer.
if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
- Ty = DBuilder.createObjectPointerType(Ty);
+ Ty = CreateSelfType(VD->getType(), Ty);
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
@@ -2482,6 +2632,8 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
SmallVector<llvm::Value *, 9> addr;
llvm::Type *Int64Ty = CGM.Int64Ty;
+ if (isa<llvm::AllocaInst>(Storage))
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (isByRef) {
@@ -2503,6 +2655,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
llvm::DIDescriptor(LexicalBlockStack.back()),
VD->getName(), Unit, Line, Ty, addr);
+
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
@@ -2530,7 +2683,8 @@ namespace {
}
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *addr,
+ llvm::Value *Arg,
+ llvm::Value *LocalAddr,
CGBuilderTy &Builder) {
assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
@@ -2651,27 +2805,48 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
DBuilder.createStructType(tunit, typeName.str(), tunit, line,
CGM.getContext().toBits(block.BlockSize),
CGM.getContext().toBits(block.BlockAlign),
- 0, fieldsArray);
+ 0, llvm::DIType(), fieldsArray);
type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
// Get overall information about the block.
unsigned flags = llvm::DIDescriptor::FlagArtificial;
llvm::MDNode *scope = LexicalBlockStack.back();
- StringRef name = ".block_descriptor";
// Create the descriptor for the parameter.
llvm::DIVariable debugVar =
DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
llvm::DIDescriptor(scope),
- name, tunit, line, type,
+ Arg->getName(), tunit, line, type,
CGM.getLangOpts().Optimize, flags,
- cast<llvm::Argument>(addr)->getArgNo() + 1);
-
- // Insert an llvm.dbg.value into the current block.
- llvm::Instruction *declare =
- DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar,
- Builder.GetInsertBlock());
- declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+ cast<llvm::Argument>(Arg)->getArgNo() + 1);
+
+ if (LocalAddr) {
+ // Insert an llvm.dbg.value into the current block.
+ llvm::Instruction *DbgVal =
+ DBuilder.insertDbgValueIntrinsic(LocalAddr, 0, debugVar,
+ Builder.GetInsertBlock());
+ DbgVal->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+ }
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *DbgDecl =
+ DBuilder.insertDeclare(Arg, debugVar, Builder.GetInsertBlock());
+ DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+}
+
+/// getStaticDataMemberDeclaration - If D is an out-of-class definition of
+/// a static data member of a class, find its corresponding in-class
+/// declaration.
+llvm::DIDerivedType CGDebugInfo::getStaticDataMemberDeclaration(const Decl *D) {
+ if (cast<VarDecl>(D)->isStaticDataMember()) {
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ MI = StaticDataMemberCache.find(D->getCanonicalDecl());
+ if (MI != StaticDataMemberCache.end())
+ // Verify the info still exists.
+ if (llvm::Value *V = MI->second)
+ return llvm::DIDerivedType(cast<llvm::MDNode>(V));
+ }
+ return llvm::DIDerivedType();
}
/// EmitGlobalVariable - Emit information about a global variable.
@@ -2705,7 +2880,8 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var);
+ Var->hasInternalLinkage(), Var,
+ getStaticDataMemberDeclaration(D));
}
/// EmitGlobalVariable - Emit information about an objective-c interface.
@@ -2752,7 +2928,8 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
return;
DBuilder.createStaticVariable(Unit, Name, Name, Unit,
getLineNumber(VD->getLocation()),
- Ty, true, Init);
+ Ty, true, Init,
+ getStaticDataMemberDeclaration(VD));
}
/// getOrCreateNamesSpace - Return namespace descriptor for the given
@@ -2774,7 +2951,7 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
return NS;
}
-void CGDebugInfo::finalize(void) {
+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;
@@ -2789,10 +2966,16 @@ void CGDebugInfo::finalize(void) {
if (llvm::Value *V = it->second)
RepTy = llvm::DIType(cast<llvm::MDNode>(V));
}
-
- if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) {
+
+ if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify())
Ty.replaceAllUsesWith(RepTy);
- }
}
+
+ // We keep our own list of retained types, because we need to look
+ // up the final type in the type cache.
+ for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),
+ RE = RetainedTypes.end(); RI != RE; ++RI)
+ DBuilder.retainType(llvm::DIType(cast<llvm::MDNode>(TypeCache[*RI])));
+
DBuilder.finalize();
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 2e88a7376a6c..3a0df999b540 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -14,16 +14,15 @@
#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
#define CLANG_CODEGEN_CGDEBUGINFO_H
-#include "clang/AST/Type.h"
+#include "CGBuilder.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/DebugInfo.h"
-#include "llvm/DIBuilder.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/Support/ValueHandle.h"
+#include "llvm/DIBuilder.h"
+#include "llvm/DebugInfo.h"
#include "llvm/Support/Allocator.h"
-
-#include "CGBuilder.h"
+#include "llvm/Support/ValueHandle.h"
namespace llvm {
class MDNode;
@@ -33,6 +32,7 @@ namespace clang {
class CXXMethodDecl;
class VarDecl;
class ObjCInterfaceDecl;
+ class ObjCIvarDecl;
class ClassTemplateSpecializationDecl;
class GlobalDecl;
@@ -51,12 +51,24 @@ class CGDebugInfo {
SourceLocation CurLoc, PrevLoc;
llvm::DIType VTablePtrType;
llvm::DIType ClassTy;
- llvm::DIType ObjTy;
+ llvm::DICompositeType ObjTy;
llvm::DIType SelTy;
+ llvm::DIType OCLImage1dDITy, OCLImage1dArrayDITy, OCLImage1dBufferDITy;
+ llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy;
+ llvm::DIType OCLImage3dDITy;
+ llvm::DIType OCLEventDITy;
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
+ /// 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;
+
+ /// 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;
@@ -83,8 +95,10 @@ class CGDebugInfo {
llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
+ llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache;
/// Helper functions for getOrCreateType.
+ unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl);
llvm::DIType CreateType(const BuiltinType *Ty);
llvm::DIType CreateType(const ComplexType *Ty);
llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F);
@@ -105,10 +119,13 @@ class CGDebugInfo {
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
llvm::DIType CreateEnumType(const EnumDecl *ED);
+ llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty);
llvm::DIType getTypeOrNull(const QualType);
llvm::DIType getCompletedTypeOrNull(const QualType);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
+ llvm::DIType getOrCreateInstanceMethodType(
+ QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit);
llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
llvm::DIFile F);
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
@@ -117,7 +134,10 @@ class CGDebugInfo {
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DIFile F);
-
+
+ llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty);
+ llvm::DIType getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache);
+
llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
llvm::DIFile F,
llvm::DIType RecordTy);
@@ -152,7 +172,18 @@ class CGDebugInfo {
AccessSpecifier AS, uint64_t offsetInBits,
llvm::DIFile tunit,
llvm::DIDescriptor scope);
- void CollectRecordStaticVars(const RecordDecl *, llvm::DIType);
+
+ // Helpers for collecting fields of a record.
+ void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
+ void CollectRecordStaticField(const VarDecl *Var,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
+ void CollectRecordNormalField(const FieldDecl *Field, uint64_t OffsetInBits,
+ llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &E,
llvm::DIType RecordTy);
@@ -169,7 +200,7 @@ public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
- void finalize(void);
+ void finalize();
/// setLocation - Update the current source location. If \arg loc is
/// invalid it is ignored.
@@ -177,7 +208,9 @@ public:
/// EmitLocation - Emit metadata to indicate a change in line/column
/// information in the source file.
- void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
+ /// \param ForceColumnInfo Assume DebugColumnInfo option is true.
+ void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
+ bool ForceColumnInfo = false);
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
@@ -216,7 +249,8 @@ public:
/// llvm.dbg.declare for the block-literal argument to a block
/// invocation function.
void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *addr,
+ llvm::Value *Arg,
+ llvm::Value *LocalAddr,
CGBuilderTy &Builder);
/// EmitGlobalVariable - Emit information about a global variable.
@@ -243,7 +277,7 @@ private:
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
- llvm::DIType EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+ llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *OffSet);
/// getContextDescriptor - Get context info for the decl.
@@ -280,6 +314,10 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ /// getObjCInterfaceDecl - return the underlying ObjCInterfaceDecl
+ /// if Ty is an ObjCInterface or a pointer to one.
+ ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty);
+
/// CreateLimitedTypeNode - Create type metadata for a source language
/// type, but only partial types for records.
llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
@@ -292,6 +330,11 @@ private:
/// declaration for the given method definition.
llvm::DISubprogram getFunctionDeclaration(const Decl *D);
+ /// getStaticDataMemberDeclaration - Return debug info descriptor to
+ /// describe in-class static data member declaration for the given
+ /// out-of-class definition.
+ llvm::DIDerivedType getStaticDataMemberDeclaration(const Decl *D);
+
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
@@ -317,7 +360,8 @@ private:
/// getColumnNumber - Get column number for the location. If location is
/// invalid then use current location.
- unsigned getColumnNumber(SourceLocation Loc);
+ /// \param Force Assume DebugColumnInfo option is true.
+ unsigned getColumnNumber(SourceLocation Loc, bool Force=false);
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 887058753e14..5375c5e18f2f 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
+#include "CGDebugInfo.h"
#include "CGOpenCLRuntime.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
@@ -22,10 +22,10 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
-#include "llvm/Type.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Type.h"
using namespace clang;
using namespace CodeGen;
@@ -83,6 +83,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
case Decl::Label: // __label__ x;
case Decl::Import:
+ case Decl::OMPThreadPrivate:
+ case Decl::Empty:
// None of these decls require codegen support.
return;
@@ -386,7 +388,9 @@ namespace {
}
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false, Loc);
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false,
+ Loc);
if (NRVO) CGF.EmitBlock(SkipDtorBB);
}
@@ -448,6 +452,22 @@ namespace {
CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args);
}
};
+
+ /// A cleanup to call @llvm.lifetime.end.
+ class CallLifetimeEnd : public EHScopeStack::Cleanup {
+ llvm::Value *Addr;
+ llvm::Value *Size;
+ public:
+ CallLifetimeEnd(llvm::Value *addr, llvm::Value *size)
+ : Addr(addr), Size(size) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr, CGF.Int8PtrTy);
+ CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(),
+ Size, castAddr)
+ ->setDoesNotThrow();
+ }
+ };
}
/// EmitAutoVarWithLifetime - Does the setup required for an automatic
@@ -624,7 +644,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, ARCImpreciseLifetime);
return;
}
@@ -752,7 +772,6 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
// If a global is all zeros, always use a memset.
if (isa<llvm::ConstantAggregateZero>(Init)) return true;
-
// If a non-zero global is <= 32 bytes, always use a memcpy. If it is large,
// do it if it will require 6 or fewer scalar stores.
// TODO: Should budget depends on the size? Avoiding a large global warrants
@@ -764,6 +783,23 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
canEmitInitWithFewStoresAfterMemset(Init, StoreBudget);
}
+/// 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;
+
+ // Limit the size of marked objects to 32 bytes. We don't want to increase
+ // compile time by marking tiny objects.
+ unsigned SizeThreshold = 32;
+
+ return Size > SizeThreshold;
+}
+
/// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a
/// variable declaration with auto, register, or no storage class specifier.
@@ -794,85 +830,91 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
- if (!Target.useGlobalsForAutomaticVariables()) {
- bool NRVO = getLangOpts().ElideConstructors &&
- D.isNRVOVariable();
-
- // If this value is a POD array or struct with a statically
- // determinable constant initializer, there are optimizations we can do.
- //
- // TODO: We should constant-evaluate the initializer of any variable,
- // as long as it is initialized by a constant expression. Currently,
- // isConstantInitializer produces wrong answers for structs with
- // reference or bitfield members, and a few other cases, and checking
- // for POD-ness protects us from some of these.
- if (D.getInit() &&
- (Ty->isArrayType() || Ty->isRecordType()) &&
- (Ty.isPODType(getContext()) ||
- getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
- D.getInit()->isConstantInitializer(getContext(), false)) {
-
- // If the variable's a const type, and it's neither an NRVO
- // candidate nor a __block variable and has no mutable members,
- // emit it as a global instead.
- if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
- CGM.isTypeConstant(Ty, true)) {
- EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
-
- emission.Address = 0; // signal this condition to later callbacks
- assert(emission.wasEmittedAsGlobal());
- return emission;
- }
-
- // Otherwise, tell the initialization code that we're in this case.
- emission.IsConstantAggregate = true;
+ bool NRVO = getLangOpts().ElideConstructors &&
+ D.isNRVOVariable();
+
+ // If this value is a POD array or struct with a statically
+ // determinable constant initializer, there are optimizations we can do.
+ //
+ // TODO: We should constant-evaluate the initializer of any variable,
+ // as long as it is initialized by a constant expression. Currently,
+ // isConstantInitializer produces wrong answers for structs with
+ // reference or bitfield members, and a few other cases, and checking
+ // for POD-ness protects us from some of these.
+ if (D.getInit() &&
+ (Ty->isArrayType() || Ty->isRecordType()) &&
+ (Ty.isPODType(getContext()) ||
+ getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
+ D.getInit()->isConstantInitializer(getContext(), false)) {
+
+ // If the variable's a const type, and it's neither an NRVO
+ // candidate nor a __block variable and has no mutable members,
+ // emit it as a global instead.
+ if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
+ CGM.isTypeConstant(Ty, true)) {
+ EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
+
+ emission.Address = 0; // signal this condition to later callbacks
+ assert(emission.wasEmittedAsGlobal());
+ return emission;
}
- // A normal fixed sized variable becomes an alloca in the entry block,
- // unless it's an NRVO variable.
- llvm::Type *LTy = ConvertTypeForMem(Ty);
+ // Otherwise, tell the initialization code that we're in this case.
+ emission.IsConstantAggregate = true;
+ }
- if (NRVO) {
- // The named return value optimization: allocate this variable in the
- // return slot, so that we can elide the copy when returning this
- // variable (C++0x [class.copy]p34).
- DeclPtr = ReturnValue;
-
- if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
- if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
- // Create a flag that is used to indicate when the NRVO was applied
- // to this variable. Set it to zero to indicate that NRVO was not
- // applied.
- llvm::Value *Zero = Builder.getFalse();
- llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
- EnsureInsertPoint();
- Builder.CreateStore(Zero, NRVOFlag);
-
- // Record the NRVO flag for this variable.
- NRVOFlags[&D] = NRVOFlag;
- emission.NRVOFlag = NRVOFlag;
- }
+ // A normal fixed sized variable becomes an alloca in the entry block,
+ // unless it's an NRVO variable.
+ llvm::Type *LTy = ConvertTypeForMem(Ty);
+
+ if (NRVO) {
+ // The named return value optimization: allocate this variable in the
+ // return slot, so that we can elide the copy when returning this
+ // variable (C++0x [class.copy]p34).
+ DeclPtr = ReturnValue;
+
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+ if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
+ // Create a flag that is used to indicate when the NRVO was applied
+ // to this variable. Set it to zero to indicate that NRVO was not
+ // applied.
+ llvm::Value *Zero = Builder.getFalse();
+ llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
+ EnsureInsertPoint();
+ Builder.CreateStore(Zero, NRVOFlag);
+
+ // Record the NRVO flag for this variable.
+ NRVOFlags[&D] = NRVOFlag;
+ emission.NRVOFlag = NRVOFlag;
}
- } else {
- if (isByRef)
- LTy = BuildByRefType(&D);
-
- llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- Alloc->setName(D.getName());
-
- CharUnits allocaAlignment = alignment;
- if (isByRef)
- allocaAlignment = std::max(allocaAlignment,
- getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
- Alloc->setAlignment(allocaAlignment.getQuantity());
- DeclPtr = Alloc;
}
} else {
- // Targets that don't support recursion emit locals as globals.
- const char *Class =
- D.getStorageClass() == SC_Register ? ".reg." : ".auto.";
- DeclPtr = CreateStaticVarDecl(D, Class,
- llvm::GlobalValue::InternalLinkage);
+ if (isByRef)
+ LTy = BuildByRefType(&D);
+
+ llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
+ Alloc->setName(D.getName());
+
+ CharUnits allocaAlignment = alignment;
+ if (isByRef)
+ allocaAlignment = std::max(allocaAlignment,
+ getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
+ Alloc->setAlignment(allocaAlignment.getQuantity());
+ DeclPtr = Alloc;
+
+ // Emit a lifetime intrinsic if meaningful. There's no point
+ // in doing this if we don't have a valid insertion point (?).
+ uint64_t size = CGM.getDataLayout().getTypeAllocSize(LTy);
+ if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D, size)) {
+ llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size);
+
+ emission.SizeForLifetimeMarkers = sizeV;
+ llvm::Value *castAddr = Builder.CreateBitCast(Alloc, Int8PtrTy);
+ Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV, castAddr)
+ ->setDoesNotThrow();
+ } else {
+ assert(!emission.useLifetimeMarkers());
+ }
}
} else {
EnsureInsertPoint();
@@ -917,11 +959,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
if (CGM.getCodeGenOpts().getDebugInfo()
>= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
- if (Target.useGlobalsForAutomaticVariables()) {
- DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr),
- &D);
- } else
- DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
+ DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
}
}
@@ -1112,21 +1150,33 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue, true);
- } else if (!hasAggregateLLVMType(type)) {
+ return;
+ }
+ switch (getEvaluationKind(type)) {
+ case TEK_Scalar:
EmitScalarInit(init, D, lvalue, capturedByInit);
- } else if (type->isAnyComplexType()) {
+ return;
+ case TEK_Complex: {
ComplexPairTy complex = EmitComplexExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- StoreComplexToAddr(complex, lvalue.getAddress(), lvalue.isVolatile());
- } else {
- // TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
+ EmitStoreOfComplex(complex, lvalue, /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
+ if (type->isAtomicType()) {
+ EmitAtomicInit(const_cast<Expr*>(init), lvalue);
+ } else {
+ // TODO: how can we delay here if D is captured by its initializer?
+ EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ }
MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
/// Enter a destroy cleanup for the given local variable.
@@ -1199,6 +1249,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
+ // Make sure we call @llvm.lifetime.end. This needs to happen
+ // *last*, so the cleanup needs to be pushed *first*.
+ if (emission.useLifetimeMarkers()) {
+ EHStack.pushCleanup<CallLifetimeEnd>(NormalCleanup,
+ emission.getAllocatedAddress(),
+ emission.getSizeForLifetimeMarkers());
+ }
+
// Check the type for a cleanup.
if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
emitAutoVarTypeCleanup(emission, dtorKind);
@@ -1240,7 +1298,18 @@ CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
llvm_unreachable("Unknown DestructionKind");
}
-/// pushDestroy - Push the standard destructor for the given type.
+/// pushEHDestroy - Push the standard destructor for the given type as
+/// an EH-only cleanup.
+void CodeGenFunction::pushEHDestroy(QualType::DestructionKind dtorKind,
+ llvm::Value *addr, QualType type) {
+ assert(dtorKind && "cannot push destructor for trivial type");
+ assert(needsEHCleanup(dtorKind));
+
+ pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind), true);
+}
+
+/// pushDestroy - Push the standard destructor for the given type as
+/// at least a normal cleanup.
void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type) {
assert(dtorKind && "cannot push destructor for trivial type");
@@ -1434,10 +1503,6 @@ namespace {
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
-/// \param array - a value of type elementType*
-/// \param destructionKind - the kind of destruction required
-/// \param initializedElementCount - a value of type size_t* holding
-/// the number of successfully-constructed elements
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
@@ -1453,10 +1518,6 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
-/// \param array - a value of type elementType*
-/// \param destructionKind - the kind of destruction required
-/// \param initializedElementCount - a value of type size_t* holding
-/// the number of successfully-constructed elements
void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd,
QualType elementType,
@@ -1466,18 +1527,37 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
elementType, destroyer);
}
+/// Lazily declare the @llvm.lifetime.start intrinsic.
+llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() {
+ if (LifetimeStartFn) return LifetimeStartFn;
+ LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(),
+ llvm::Intrinsic::lifetime_start);
+ return LifetimeStartFn;
+}
+
+/// Lazily declare the @llvm.lifetime.end intrinsic.
+llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() {
+ if (LifetimeEndFn) return LifetimeEndFn;
+ LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(),
+ llvm::Intrinsic::lifetime_end);
+ return LifetimeEndFn;
+}
+
namespace {
/// A cleanup to perform a release of an object at the end of a
/// function. This is used to balance out the incoming +1 of a
/// ns_consumed argument when we can't reasonably do that just by
/// not doing the initial retain for a __block argument.
struct ConsumeARCParameter : EHScopeStack::Cleanup {
- ConsumeARCParameter(llvm::Value *param) : Param(param) {}
+ ConsumeARCParameter(llvm::Value *param,
+ ARCPreciseLifetime_t precise)
+ : Param(param), Precise(precise) {}
llvm::Value *Param;
+ ARCPreciseLifetime_t Precise;
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitARCRelease(Param, /*precise*/ false);
+ CGF.EmitARCRelease(Param, Precise);
}
};
}
@@ -1492,17 +1572,29 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
Arg->setName(D.getName());
+ QualType Ty = D.getType();
+
// Use better IR generation for certain implicit parameters.
if (isa<ImplicitParamDecl>(D)) {
// The only implicit argument a block has is its literal.
if (BlockInfo) {
LocalDeclMap[&D] = Arg;
+ llvm::Value *LocalAddr = 0;
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ // Allocate a stack slot to let the debug info survive the RA.
+ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
+ D.getName() + ".addr");
+ Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ LValue lv = MakeAddrLValue(Alloc, Ty, getContext().getDeclAlign(&D));
+ EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
+ LocalAddr = Builder.CreateLoad(Alloc);
+ }
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().getDebugInfo()
>= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
- DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder);
+ DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, LocalAddr, Builder);
}
}
@@ -1510,24 +1602,23 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
}
- QualType Ty = D.getType();
-
llvm::Value *DeclPtr;
// If this is an aggregate or variable sized value, reuse the input pointer.
if (!Ty->isConstantSizeType() ||
- CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ !CodeGenFunction::hasScalarEvaluationKind(Ty)) {
DeclPtr = Arg;
} else {
// Otherwise, create a temporary to hold the value.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
D.getName() + ".addr");
- Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ CharUnits Align = getContext().getDeclAlign(&D);
+ Alloc->setAlignment(Align.getQuantity());
DeclPtr = Alloc;
bool doStore = true;
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;
@@ -1548,15 +1639,30 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
if (lt == Qualifiers::OCL_Strong) {
- if (!isConsumed)
+ if (!isConsumed) {
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ // use objc_storeStrong(&dest, value) for retaining the
+ // object. But first, store a null into 'dest' because
+ // objc_storeStrong attempts to release its old value.
+ llvm::Value * Null = CGM.EmitNullConstant(D.getType());
+ EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
+ EmitARCStoreStrongCall(lv.getAddress(), Arg, true);
+ doStore = false;
+ }
+ else
// Don't use objc_retainBlock for block pointers, because we
// don't want to Block_copy something just because we got it
// as a parameter.
- Arg = EmitARCRetainNonBlock(Arg);
+ Arg = EmitARCRetainNonBlock(Arg);
+ }
} else {
// Push the cleanup for a consumed parameter.
- if (isConsumed)
- EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
+ if (isConsumed) {
+ ARCPreciseLifetime_t precise = (D.hasAttr<ObjCPreciseLifetimeAttr>()
+ ? ARCPreciseLifetime : ARCImpreciseLifetime);
+ EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg,
+ precise);
+ }
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
@@ -1569,11 +1675,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
// Store the initial value into the alloca.
- if (doStore) {
- LValue lv = MakeAddrLValue(DeclPtr, Ty,
- getContext().getDeclAlign(&D));
+ if (doStore)
EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
- }
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 65be3c19fb88..0448d31f4073 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CGObjCRuntime.h"
#include "CGCXXABI.h"
+#include "CGObjCRuntime.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Intrinsics.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -34,7 +34,8 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
LValue lv = CGF.MakeAddrLValue(DeclPtr, type, alignment);
const Expr *Init = D.getInit();
- if (!CGF.hasAggregateLLVMType(type)) {
+ switch (CGF.getEvaluationKind(type)) {
+ case TEK_Scalar: {
CodeGenModule &CGM = CGF.CGM;
if (lv.isObjCStrong())
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
@@ -44,13 +45,18 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
DeclPtr);
else
CGF.EmitScalarInit(Init, &D, lv, false);
- } else if (type->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile());
- } else {
+ return;
+ }
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, lv, /*isInit*/ true);
+ return;
+ case TEK_Aggregate:
CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
/// Emit code to cause the destruction of the given variable with
@@ -198,7 +204,7 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtor,
if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
atexitFn->setDoesNotThrow();
- Builder.CreateCall(atexit, dtorStub)->setDoesNotThrow();
+ EmitNounwindRuntimeCall(atexit, dtorStub);
}
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
@@ -229,11 +235,17 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
Fn->setSection(Section);
}
+ Fn->setCallingConv(CGM.getRuntimeCC());
+
if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (CGM.getLangOpts().SanitizeAddress)
- Fn->addFnAttr(llvm::Attributes::AddressSafety);
+ 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);
return Fn;
}
@@ -388,7 +400,7 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
- Builder.CreateCall(Decls[i]);
+ EmitRuntimeCall(Decls[i]);
Scope.ForceCleanup();
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 86dee5a4ab98..36642bcc48ff 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -16,84 +16,85 @@
#include "CGObjCRuntime.h"
#include "TargetInfo.h"
#include "clang/AST/StmtCXX.h"
-#include "llvm/Intrinsics.h"
+#include "clang/AST/StmtObjC.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
-static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
+static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) {
// void *__cxa_allocate_exception(size_t thrown_size);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.SizeTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
-static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
+static llvm::Constant *getFreeExceptionFn(CodeGenModule &CGM) {
// void __cxa_free_exception(void *thrown_exception);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
-static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
+static llvm::Constant *getThrowFn(CodeGenModule &CGM) {
// void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
// void (*dest) (void *));
- llvm::Type *Args[3] = { CGF.Int8PtrTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
+ llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, Args, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
-static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
+static llvm::Constant *getReThrowFn(CodeGenModule &CGM) {
// void __cxa_rethrow();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
}
-static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
+static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
// void *__cxa_get_exception_ptr(void*);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
}
-static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
+static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
// void *__cxa_begin_catch(void*);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
}
-static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
+static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
// void __cxa_end_catch();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
}
-static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
+static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
// void __cxa_call_unexepcted(void *thrown_exception);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
@@ -114,31 +115,31 @@ llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
-static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
+static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {
// void __terminate();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
StringRef name;
// In C++, use std::terminate().
- if (CGF.getLangOpts().CPlusPlus)
+ if (CGM.getLangOpts().CPlusPlus)
name = "_ZSt9terminatev"; // FIXME: mangling!
- else if (CGF.getLangOpts().ObjC1 &&
- CGF.getLangOpts().ObjCRuntime.hasTerminate())
+ else if (CGM.getLangOpts().ObjC1 &&
+ CGM.getLangOpts().ObjCRuntime.hasTerminate())
name = "objc_terminate";
else
name = "abort";
- return CGF.CGM.CreateRuntimeFunction(FTy, name);
+ return CGM.CreateRuntimeFunction(FTy, name);
}
-static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
+static llvm::Constant *getCatchallRethrowFn(CodeGenModule &CGM,
StringRef Name) {
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, Name);
+ return CGM.CreateRuntimeFunction(FTy, Name);
}
namespace {
@@ -155,6 +156,7 @@ namespace {
static const EHPersonality GNU_C;
static const EHPersonality GNU_C_SJLJ;
static const EHPersonality GNU_ObjC;
+ static const EHPersonality GNUstep_ObjC;
static const EHPersonality GNU_ObjCXX;
static const EHPersonality NeXT_ObjC;
static const EHPersonality GNU_CPlusPlus;
@@ -172,6 +174,8 @@ const EHPersonality
EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
const EHPersonality
EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", 0 };
+const EHPersonality
+EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", 0 };
static const EHPersonality &getCPersonality(const LangOptions &L) {
if (L.SjLjExceptions)
@@ -187,6 +191,9 @@ static const EHPersonality &getObjCPersonality(const LangOptions &L) {
case ObjCRuntime::iOS:
return EHPersonality::NeXT_ObjC;
case ObjCRuntime::GNUstep:
+ if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
+ return EHPersonality::GNUstep_ObjC;
+ // fallthrough
case ObjCRuntime::GCC:
case ObjCRuntime::ObjFW:
return EHPersonality::GNU_ObjC;
@@ -357,8 +364,7 @@ namespace {
llvm::Value *exn;
FreeException(llvm::Value *exn) : exn(exn) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn);
}
};
}
@@ -415,15 +421,8 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
- if (getInvokeDest()) {
- Builder.CreateInvoke(getReThrowFn(*this),
- getUnreachableBlock(),
- getInvokeDest())
- ->setDoesNotReturn();
- } else {
- Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
- Builder.CreateUnreachable();
- }
+ EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM),
+ ArrayRef<llvm::Value*>());
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -434,16 +433,26 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
QualType ThrowType = E->getSubExpr()->getType();
+ if (ThrowType->isObjCObjectPointerType()) {
+ const Stmt *ThrowStmt = E->getSubExpr();
+ const ObjCAtThrowStmt S(E->getExprLoc(),
+ const_cast<Stmt *>(ThrowStmt));
+ CGM.getObjCRuntime().EmitThrowStmt(*this, S, false);
+ // This will clear insertion point which was not cleared in
+ // call to EmitThrowStmt.
+ EmitBlock(createBasicBlock("throw.cont"));
+ return;
+ }
+
// Now allocate the exception object.
llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
- llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
+ llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM);
llvm::CallInst *ExceptionPtr =
- Builder.CreateCall(AllocExceptionFn,
- llvm::ConstantInt::get(SizeTy, TypeSize),
- "exception");
- ExceptionPtr->setDoesNotThrow();
+ EmitNounwindRuntimeCall(AllocExceptionFn,
+ llvm::ConstantInt::get(SizeTy, TypeSize),
+ "exception");
EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
@@ -464,18 +473,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
- if (getInvokeDest()) {
- llvm::InvokeInst *ThrowCall =
- Builder.CreateInvoke3(getThrowFn(*this),
- getUnreachableBlock(), getInvokeDest(),
- ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
- } else {
- llvm::CallInst *ThrowCall =
- Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
- Builder.CreateUnreachable();
- }
+ llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
+ EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -545,7 +544,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF,
// according to the last landing pad the exception was thrown
// into. Seriously.
llvm::Value *exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateCall(getUnexpectedFn(CGF), exn)
+ CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -853,7 +852,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Create a filter expression: a constant array indicating which filter
// types there are. The personality routine only lands here if the filter
// doesn't match.
- llvm::SmallVector<llvm::Constant*, 8> Filters;
+ SmallVector<llvm::Constant*, 8> Filters;
llvm::ArrayType *AType =
llvm::ArrayType::get(!filterTypes.empty() ?
filterTypes[0]->getType() : Int8PtrTy,
@@ -907,11 +906,11 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
- CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
return;
}
- CGF.EmitCallOrInvoke(getEndCatchFn(CGF));
+ CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
}
};
}
@@ -923,12 +922,12 @@ namespace {
static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
llvm::Value *Exn,
bool EndMightThrow) {
- llvm::CallInst *Call = CGF.Builder.CreateCall(getBeginCatchFn(CGF), Exn);
- Call->setDoesNotThrow();
+ llvm::CallInst *call =
+ CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
- return Call;
+ return call;
}
/// A "special initializer" callback for initializing a catch
@@ -1003,10 +1002,9 @@ static void InitCatchParam(CodeGenFunction &CGF,
return;
}
- // Non-aggregates (plus complexes).
- bool IsComplex = false;
- if (!CGF.hasAggregateLLVMType(CatchType) ||
- (IsComplex = CatchType->isAnyComplexType())) {
+ // Scalars and complexes.
+ TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
+ if (TEK != TEK_Aggregate) {
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
// If the catch type is a pointer type, __cxa_begin_catch returns
@@ -1038,17 +1036,23 @@ static void InitCatchParam(CodeGenFunction &CGF,
llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
- if (IsComplex) {
- CGF.StoreComplexToAddr(CGF.LoadComplexFromAddr(Cast, /*volatile*/ false),
- ParamAddr, /*volatile*/ false);
- } else {
- unsigned Alignment =
- CGF.getContext().getDeclAlign(&CatchParam).getQuantity();
- llvm::Value *ExnLoad = CGF.Builder.CreateLoad(Cast, "exn.scalar");
- CGF.EmitStoreOfScalar(ExnLoad, ParamAddr, /*volatile*/ false, Alignment,
- CatchType);
+ LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
+ LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
+ CGF.getContext().getDeclAlign(&CatchParam));
+ switch (TEK) {
+ case TEK_Complex:
+ CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV), destLV,
+ /*init*/ true);
+ return;
+ case TEK_Scalar: {
+ llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV);
+ CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
+ return;
}
- return;
+ case TEK_Aggregate:
+ llvm_unreachable("evaluation kind filtered out!");
+ }
+ llvm_unreachable("bad evaluation kind");
}
assert(isa<RecordType>(CatchType) && "unexpected catch type!");
@@ -1068,8 +1072,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
// We have to call __cxa_get_exception_ptr to get the adjusted
// pointer before copying.
llvm::CallInst *rawAdjustedExn =
- CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF), Exn);
- rawAdjustedExn->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
// Cast that to the appropriate type.
llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
@@ -1292,7 +1295,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// constructor function-try-block's catch handler (p14), so this
// really only applies to destructors.
if (doImplicitRethrow && HaveInsertPoint()) {
- EmitCallOrInvoke(getReThrowFn(*this));
+ EmitRuntimeCallOrInvoke(getReThrowFn(CGM));
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
@@ -1324,7 +1327,7 @@ namespace {
CGF.Builder.CreateLoad(ForEHVar, "finally.endcatch");
CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
CGF.EmitBlock(EndCatchBB);
- CGF.EmitCallOrInvoke(EndCatchFn); // catch-all, so might throw
+ CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw
CGF.EmitBlock(CleanupContBB);
}
};
@@ -1369,9 +1372,10 @@ namespace {
CGF.EmitBlock(RethrowBB);
if (SavedExnVar) {
- CGF.EmitCallOrInvoke(RethrowFn, CGF.Builder.CreateLoad(SavedExnVar));
+ CGF.EmitRuntimeCallOrInvoke(RethrowFn,
+ CGF.Builder.CreateLoad(SavedExnVar));
} else {
- CGF.EmitCallOrInvoke(RethrowFn);
+ CGF.EmitRuntimeCallOrInvoke(RethrowFn);
}
CGF.Builder.CreateUnreachable();
@@ -1476,7 +1480,7 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
// If there's a begin-catch function, call it.
if (BeginCatchFn) {
exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(BeginCatchFn, exn);
}
// If we need to remember the exception pointer to rethrow later, do so.
@@ -1498,6 +1502,68 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
CGF.PopCleanupBlock();
}
+/// In a terminate landing pad, should we use __clang__call_terminate
+/// or just a naked call to std::terminate?
+///
+/// __clang_call_terminate calls __cxa_begin_catch, which then allows
+/// std::terminate to usefully report something about the
+/// violating exception.
+static bool useClangCallTerminate(CodeGenModule &CGM) {
+ // Only do this for Itanium-family ABIs in C++ mode.
+ return (CGM.getLangOpts().CPlusPlus &&
+ CGM.getTarget().getCXXABI().isItaniumFamily());
+}
+
+/// Get or define the following function:
+/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
+/// This code is used only in C++.
+static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
+ llvm::FunctionType *fnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::Constant *fnRef =
+ CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");
+
+ llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
+ if (fn && fn->empty()) {
+ fn->setDoesNotThrow();
+ fn->setDoesNotReturn();
+
+ // What we really want is to massively penalize inlining without
+ // forbidding it completely. The difference between that and
+ // 'noinline' is negligible.
+ fn->addFnAttr(llvm::Attribute::NoInline);
+
+ // Allow this function to be shared across translation units, but
+ // we don't want it to turn into an exported symbol.
+ fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
+ fn->setVisibility(llvm::Function::HiddenVisibility);
+
+ // Set up the function.
+ llvm::BasicBlock *entry =
+ llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
+ CGBuilderTy builder(entry);
+
+ // Pull the exception pointer out of the parameter list.
+ llvm::Value *exn = &*fn->arg_begin();
+
+ // Call __cxa_begin_catch(exn).
+ llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);
+ catchCall->setDoesNotThrow();
+ catchCall->setCallingConv(CGM.getRuntimeCC());
+
+ // Call std::terminate().
+ llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM));
+ termCall->setDoesNotThrow();
+ termCall->setDoesNotReturn();
+ termCall->setCallingConv(CGM.getRuntimeCC());
+
+ // std::terminate cannot return.
+ builder.CreateUnreachable();
+ }
+
+ return fnRef;
+}
+
llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
if (TerminateLandingPad)
return TerminateLandingPad;
@@ -1515,9 +1581,15 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
getOpaquePersonalityFn(CGM, Personality), 0);
LPadInst->addClause(getCatchAllValue(*this));
- llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this));
- TerminateCall->setDoesNotReturn();
- TerminateCall->setDoesNotThrow();
+ llvm::CallInst *terminateCall;
+ if (useClangCallTerminate(CGM)) {
+ // Extract out the exception pointer.
+ llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0);
+ terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);
+ } else {
+ terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
+ }
+ terminateCall->setDoesNotReturn();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1536,9 +1608,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
Builder.SetInsertPoint(TerminateHandler);
- llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this));
+ llvm::CallInst *TerminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
TerminateCall->setDoesNotReturn();
- TerminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1562,8 +1633,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// anything on the EH stack which needs our help.
const char *RethrowName = Personality.CatchallRethrowFn;
if (RethrowName != 0 && !isCleanup) {
- Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
- getExceptionFromSlot())
+ EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
+ getExceptionFromSlot())
->setDoesNotReturn();
} else {
switch (CleanupHackLevel) {
@@ -1571,8 +1642,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// In mandatory-catchall mode, we need to use
// _Unwind_Resume_or_Rethrow, or whatever the personality's
// equivalent is.
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- getExceptionFromSlot())
+ EmitRuntimeCall(getUnwindResumeOrRethrowFn(),
+ getExceptionFromSlot())
->setDoesNotReturn();
break;
case CHL_MandatoryCleanup: {
@@ -1596,7 +1667,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// 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).
- Builder.CreateCall(getUnwindResumeFn(), getExceptionFromSlot())
+ EmitRuntimeCall(getUnwindResumeFn(), getExceptionFromSlot())
->setDoesNotReturn();
break;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 63cc5b515da8..2f5186d1f4ff 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -12,22 +12,23 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "CGCall.h"
#include "CGCXXABI.h"
+#include "CGCall.h"
#include "CGDebugInfo.h"
-#include "CGRecordLayout.h"
#include "CGObjCRuntime.h"
+#include "CGRecordLayout.h"
+#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/ConvertUTF.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/MDBuilder.h"
-#include "llvm/DataLayout.h"
#include "llvm/ADT/Hashing.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/Support/ConvertUTF.h"
+
using namespace clang;
using namespace CodeGen;
@@ -113,15 +114,18 @@ void CodeGenFunction::EmitIgnoredExpr(const Expr *E) {
RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
AggValueSlot aggSlot,
bool ignoreResult) {
- if (!hasAggregateLLVMType(E->getType()))
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Scalar:
return RValue::get(EmitScalarExpr(E, ignoreResult));
- else if (E->getType()->isAnyComplexType())
+ case TEK_Complex:
return RValue::getComplex(EmitComplexExpr(E, ignoreResult, ignoreResult));
-
- if (!ignoreResult && aggSlot.isIgnored())
- aggSlot = CreateAggTemp(E->getType(), "agg-temp");
- EmitAggExpr(E, aggSlot);
- return aggSlot.asRValue();
+ case TEK_Aggregate:
+ if (!ignoreResult && aggSlot.isIgnored())
+ aggSlot = CreateAggTemp(E->getType(), "agg-temp");
+ EmitAggExpr(E, aggSlot);
+ return aggSlot.asRValue();
+ }
+ llvm_unreachable("bad evaluation kind");
}
/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
@@ -129,8 +133,7 @@ RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
AggValueSlot AggSlot = AggValueSlot::ignored();
- if (hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType())
+ if (hasAggregateEvaluationKind(E->getType()))
AggSlot = CreateAggTemp(E->getType(), "agg.tmp");
return EmitAnyExpr(E, AggSlot);
}
@@ -142,19 +145,30 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
Qualifiers Quals,
bool IsInit) {
// FIXME: This function should take an LValue as an argument.
- if (E->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
- } else if (hasAggregateLLVMType(E->getType())) {
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(E,
+ MakeNaturalAlignAddrLValue(Location, E->getType()),
+ /*isInit*/ false);
+ return;
+
+ case TEK_Aggregate: {
CharUnits Alignment = getContext().getTypeAlignInChars(E->getType());
EmitAggExpr(E, AggValueSlot::forAddr(Location, Alignment, Quals,
AggValueSlot::IsDestructed_t(IsInit),
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsAliased_t(!IsInit)));
- } else {
+ return;
+ }
+
+ case TEK_Scalar: {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
EmitStoreThroughLValue(RV, LV);
+ return;
+ }
}
+ llvm_unreachable("bad evaluation kind");
}
static llvm::Value *
@@ -287,8 +301,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
// Create a reference temporary if necessary.
AggValueSlot AggSlot = AggValueSlot::ignored();
- if (CGF.hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType()) {
+ if (CGF.hasAggregateEvaluationKind(E->getType())) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
@@ -302,7 +315,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
if (InitializedDecl) {
// Get the destructor for the reference temporary.
- if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
+ if (const RecordType *RT =
+ E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (!ClassDecl->hasTrivialDestructor())
ReferenceTemporaryDtor = ClassDecl->getDestructor();
@@ -368,14 +382,12 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
InitializedDecl);
- unsigned Alignment =
- CGF.getContext().getTypeAlignInChars(E->getType()).getQuantity();
+ LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,
+ E->getType());
if (RV.isScalar())
- CGF.EmitStoreOfScalar(RV.getScalarVal(), ReferenceTemporary,
- /*Volatile=*/false, Alignment, E->getType());
+ CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);
else
- CGF.StoreComplexToAddr(RV.getComplexVal(), ReferenceTemporary,
- /*Volatile=*/false);
+ CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);
return ReferenceTemporary;
}
@@ -405,10 +417,19 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
if (VD && VD->hasGlobalStorage()) {
if (ReferenceTemporaryDtor) {
- llvm::Constant *DtorFn =
- CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
- CGM.getCXXABI().registerGlobalDtor(*this, DtorFn,
- cast<llvm::Constant>(ReferenceTemporary));
+ llvm::Constant *CleanupFn;
+ llvm::Constant *CleanupArg;
+ if (E->getType()->isArrayType()) {
+ CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(
+ cast<llvm::Constant>(ReferenceTemporary), E->getType(),
+ destroyCXXObject, getLangOpts().Exceptions);
+ CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);
+ } else {
+ CleanupFn =
+ CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+ CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
+ }
+ CGM.getCXXABI().registerGlobalDtor(*this, CleanupFn, CleanupArg);
} else {
assert(!ObjCARCReferenceLifetimeType.isNull());
// Note: We intentionally do not register a global "destructor" to
@@ -418,9 +439,13 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
return RValue::get(Value);
}
- if (ReferenceTemporaryDtor)
- PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
- else {
+ if (ReferenceTemporaryDtor) {
+ if (E->getType()->isArrayType())
+ pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
+ destroyCXXObject, getLangOpts().Exceptions);
+ else
+ PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
+ } else {
switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
case Qualifiers::OCL_None:
llvm_unreachable(
@@ -486,14 +511,25 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
return;
llvm::Value *Cond = 0;
+ llvm::BasicBlock *Done = 0;
- if (getLangOpts().SanitizeNull) {
+ if (SanOpts->Null) {
// The glvalue must not be an empty glvalue.
Cond = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType()));
+
+ if (TCK == TCK_DowncastPointer) {
+ // When performing a pointer downcast, it's OK if the value is null.
+ // Skip the remaining checks in that case.
+ Done = createBasicBlock("null");
+ llvm::BasicBlock *Rest = createBasicBlock("not.null");
+ Builder.CreateCondBr(Cond, Rest, Done);
+ EmitBlock(Rest);
+ Cond = 0;
+ }
}
- if (getLangOpts().SanitizeObjectSize && !Ty->isIncompleteType()) {
+ if (SanOpts->ObjectSize && !Ty->isIncompleteType()) {
uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
// The glvalue must refer to a large enough storage region.
@@ -510,7 +546,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
uint64_t AlignVal = 0;
- if (getLangOpts().SanitizeAlignment) {
+ if (SanOpts->Alignment) {
AlignVal = Alignment.getQuantity();
if (!Ty->isIncompleteType() && !AlignVal)
AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
@@ -533,20 +569,28 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::ConstantInt::get(SizeTy, AlignVal),
llvm::ConstantInt::get(Int8Ty, TCK)
};
- EmitCheck(Cond, "type_mismatch", StaticData, Address);
+ EmitCheck(Cond, "type_mismatch", StaticData, Address, CRK_Recoverable);
}
// If possible, check that the vptr indicates that there is a subobject of
// type Ty at offset zero within this object.
+ //
+ // C++11 [basic.life]p5,6:
+ // [For storage which does not refer to an object within its lifetime]
+ // The program has undefined behavior if:
+ // -- the [pointer or glvalue] is used to access a non-static data member
+ // or call a non-static member function
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- if (getLangOpts().SanitizeVptr && TCK != TCK_ConstructorCall &&
+ if (SanOpts->Vptr &&
+ (TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
+ TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference) &&
RD && RD->hasDefinition() && RD->isDynamicClass()) {
// Compute a hash of the mangled name of the type.
//
// FIXME: This is not guaranteed to be deterministic! Move to a
// fingerprinting mechanism once LLVM provides one. For the time
// being the implementation happens to be deterministic.
- llvm::SmallString<64> MangledName;
+ SmallString<64> MangledName;
llvm::raw_svector_ostream Out(MangledName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
Out);
@@ -586,16 +630,100 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
};
llvm::Value *DynamicData[] = { Address, Hash };
EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
- "dynamic_type_cache_miss", StaticData, DynamicData, true);
+ "dynamic_type_cache_miss", StaticData, DynamicData,
+ CRK_AlwaysRecoverable);
+ }
+
+ if (Done) {
+ Builder.CreateBr(Done);
+ EmitBlock(Done);
+ }
+}
+
+/// Determine whether this expression refers to a flexible array member in a
+/// struct. We disable array bounds checks for such members.
+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 (CAT->getSize().ugt(1))
+ return false;
+ } else if (!isa<IncompleteArrayType>(AT))
+ return false;
+
+ E = E->IgnoreParens();
+
+ // A flexible array member must be the last member in the class.
+ if (const MemberExpr *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())) {
+ RecordDecl::field_iterator FI(
+ DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
+ return ++FI == FD->getParent()->field_end();
+ }
+ }
+
+ return false;
+}
+
+/// If Base is known to point to the start of an array, return the length of
+/// that array. Return 0 if the length cannot be determined.
+static llvm::Value *getArrayIndexingBound(
+ CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType) {
+ // For the vector indexing extension, the bound is the number of elements.
+ if (const VectorType *VT = Base->getType()->getAs<VectorType>()) {
+ IndexedType = Base->getType();
+ return CGF.Builder.getInt32(VT->getNumElements());
+ }
+
+ Base = Base->IgnoreParens();
+
+ if (const CastExpr *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))
+ return CGF.Builder.getInt(CAT->getSize());
+ else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT))
+ return CGF.getVLASize(VAT).first;
+ }
}
+
+ return 0;
+}
+
+void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
+ llvm::Value *Index, QualType IndexType,
+ bool Accessed) {
+ assert(SanOpts->Bounds && "should not be called unless adding bounds checks");
+
+ QualType IndexedType;
+ llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
+ if (!Bound)
+ return;
+
+ bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
+ llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
+ llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);
+
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(E->getExprLoc()),
+ EmitCheckTypeDescriptor(IndexedType),
+ EmitCheckTypeDescriptor(IndexType)
+ };
+ llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
+ : Builder.CreateICmpULE(IndexVal, BoundVal);
+ EmitCheck(Check, "out_of_bounds", StaticData, Index, CRK_Recoverable);
}
CodeGenFunction::ComplexPairTy CodeGenFunction::
EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
- ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(),
- LV.isVolatileQualified());
+ ComplexPairTy InVal = EmitLoadOfComplex(LV);
llvm::Value *NextVal;
if (isa<llvm::IntegerType>(InVal.first->getType())) {
@@ -618,7 +746,7 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
ComplexPairTy IncVal(NextVal, InVal.second);
// Store the updated result through the lvalue.
- StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified());
+ EmitStoreOfComplex(IncVal, LV, /*init*/ false);
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
@@ -633,9 +761,11 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
if (Ty->isVoidType())
return RValue::get(0);
-
- if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
- llvm::Type *EltTy = ConvertType(CTy->getElementType());
+
+ switch (getEvaluationKind(Ty)) {
+ case TEK_Complex: {
+ llvm::Type *EltTy =
+ ConvertType(Ty->castAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return RValue::getComplex(std::make_pair(U, U));
}
@@ -643,12 +773,15 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
// If this is a use of an undefined aggregate type, the aggregate must have an
// identifiable address. Just because the contents of the value are undefined
// doesn't mean that the address can't be taken and compared.
- if (hasAggregateLLVMType(Ty)) {
+ case TEK_Aggregate: {
llvm::Value *DestPtr = CreateMemTemp(Ty, "undef.agg.tmp");
return RValue::getAggregate(DestPtr);
}
-
- return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+
+ case TEK_Scalar:
+ return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+ }
+ llvm_unreachable("bad evaluation kind");
}
RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E,
@@ -665,7 +798,11 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
}
LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
- LValue LV = EmitLValue(E);
+ LValue LV;
+ if (SanOpts->Bounds && isa<ArraySubscriptExpr>(E))
+ LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true);
+ else
+ LV = EmitLValue(E);
if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple())
EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(),
E->getType(), LV.getAlignment());
@@ -907,7 +1044,8 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(),
- lvalue.getType(), lvalue.getTBAAInfo());
+ lvalue.getType(), lvalue.getTBAAInfo(),
+ lvalue.getTBAABaseType(), lvalue.getTBAAOffset());
}
static bool hasBooleanRepresentation(QualType Ty) {
@@ -923,23 +1061,22 @@ static bool hasBooleanRepresentation(QualType Ty) {
return false;
}
-llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
+static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
+ llvm::APInt &Min, llvm::APInt &End,
+ bool StrictEnums) {
const EnumType *ET = Ty->getAs<EnumType>();
- bool IsRegularCPlusPlusEnum = (getLangOpts().CPlusPlus && ET &&
- CGM.getCodeGenOpts().StrictEnums &&
- !ET->getDecl()->isFixed());
+ bool IsRegularCPlusPlusEnum = CGF.getLangOpts().CPlusPlus && StrictEnums &&
+ ET && !ET->getDecl()->isFixed();
bool IsBool = hasBooleanRepresentation(Ty);
if (!IsBool && !IsRegularCPlusPlusEnum)
- return NULL;
+ return false;
- llvm::APInt Min;
- llvm::APInt End;
if (IsBool) {
- Min = llvm::APInt(8, 0);
- End = llvm::APInt(8, 2);
+ Min = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
+ End = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
} else {
const EnumDecl *ED = ET->getDecl();
- llvm::Type *LTy = ConvertTypeForMem(ED->getIntegerType());
+ llvm::Type *LTy = CGF.ConvertTypeForMem(ED->getIntegerType());
unsigned Bitwidth = LTy->getScalarSizeInBits();
unsigned NumNegativeBits = ED->getNumNegativeBits();
unsigned NumPositiveBits = ED->getNumPositiveBits();
@@ -955,6 +1092,14 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
Min = llvm::APInt(Bitwidth, 0);
}
}
+ return true;
+}
+
+llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
+ llvm::APInt Min, End;
+ if (!getRangeForType(*this, Ty, Min, End,
+ CGM.getCodeGenOpts().StrictEnums))
+ return 0;
llvm::MDBuilder MDHelper(getLLVMContext());
return MDHelper.createRange(Min, End);
@@ -962,8 +1107,9 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo) {
-
+ llvm::MDNode *TBAAInfo,
+ QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// For better performance, handle vector loads differently.
if (Ty->isVectorType()) {
llvm::Value *V;
@@ -986,19 +1132,14 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
"castToVec4");
// Now load value.
llvm::Value *LoadVal = Builder.CreateLoad(Cast, Volatile, "loadVec4");
-
+
// Shuffle vector to get vec3.
- llvm::SmallVector<llvm::Constant*, 3> Mask;
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(getLLVMContext()),
- 0));
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(getLLVMContext()),
- 1));
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(getLLVMContext()),
- 2));
-
+ llvm::Constant *Mask[] = {
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), 0),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), 1),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), 2)
+ };
+
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
V = Builder.CreateShuffleVector(LoadVal,
llvm::UndefValue::get(vec4Ty),
@@ -1006,19 +1147,47 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
return EmitFromMemory(V, Ty);
}
}
+
+ // Atomic operations have to be done on integral types.
+ if (Ty->isAtomicType()) {
+ LValue lvalue = LValue::MakeAddr(Addr, Ty,
+ CharUnits::fromQuantity(Alignment),
+ getContext(), TBAAInfo);
+ return EmitAtomicLoad(lvalue).getScalarVal();
+ }
llvm::LoadInst *Load = Builder.CreateLoad(Addr);
if (Volatile)
Load->setVolatile(true);
if (Alignment)
Load->setAlignment(Alignment);
- if (TBAAInfo)
- CGM.DecorateInstruction(Load, TBAAInfo);
- // If this is an atomic type, all normal reads must be atomic
- if (Ty->isAtomicType())
- Load->setAtomic(llvm::SequentiallyConsistent);
-
- if (CGM.getCodeGenOpts().OptimizationLevel > 0)
+ if (TBAAInfo) {
+ llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
+ TBAAOffset);
+ CGM.DecorateInstruction(Load, TBAAPath);
+ }
+
+ if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
+ (SanOpts->Enum && Ty->getAs<EnumType>())) {
+ llvm::APInt Min, End;
+ if (getRangeForType(*this, Ty, Min, End, true)) {
+ --End;
+ llvm::Value *Check;
+ if (!Min)
+ Check = Builder.CreateICmpULE(
+ Load, llvm::ConstantInt::get(getLLVMContext(), End));
+ else {
+ llvm::Value *Upper = Builder.CreateICmpSLE(
+ Load, llvm::ConstantInt::get(getLLVMContext(), End));
+ llvm::Value *Lower = Builder.CreateICmpSGE(
+ Load, llvm::ConstantInt::get(getLLVMContext(), Min));
+ Check = Builder.CreateAnd(Upper, Lower);
+ }
+ // FIXME: Provide a SourceLocation.
+ EmitCheck(Check, "load_invalid_value", EmitCheckTypeDescriptor(Ty),
+ EmitCheckValue(Load), CRK_Recoverable);
+ }
+ } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
@@ -1031,8 +1200,9 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
// This should really always be an i1, but sometimes it's already
// an i8, and it's awkward to track those cases down.
if (Value->getType()->isIntegerTy(1))
- return Builder.CreateZExt(Value, Builder.getInt8Ty(), "frombool");
- assert(Value->getType()->isIntegerTy(8) && "value rep of bool not i1/i8");
+ return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "frombool");
+ assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
+ "wrong value rep of bool");
}
return Value;
@@ -1041,7 +1211,8 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
if (hasBooleanRepresentation(Ty)) {
- assert(Value->getType()->isIntegerTy(8) && "memory rep of bool not i8");
+ assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
+ "wrong value rep of bool");
return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool");
}
@@ -1052,7 +1223,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment,
QualType Ty,
llvm::MDNode *TBAAInfo,
- bool isInit) {
+ bool isInit, QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// Handle vectors differently to get better performance.
if (Ty->isVectorType()) {
@@ -1063,7 +1235,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
llvm::LLVMContext &VMContext = getLLVMContext();
// Our source is a vec3, do a shuffle vector to make it a vec4.
- llvm::SmallVector<llvm::Constant*, 4> Mask;
+ SmallVector<llvm::Constant*, 4> Mask;
Mask.push_back(llvm::ConstantInt::get(
llvm::Type::getInt32Ty(VMContext),
0));
@@ -1090,21 +1262,32 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
}
Value = EmitToMemory(Value, Ty);
-
+
+ if (Ty->isAtomicType()) {
+ EmitAtomicStore(RValue::get(Value),
+ LValue::MakeAddr(Addr, Ty,
+ CharUnits::fromQuantity(Alignment),
+ getContext(), TBAAInfo),
+ isInit);
+ return;
+ }
+
llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
if (Alignment)
Store->setAlignment(Alignment);
- if (TBAAInfo)
- CGM.DecorateInstruction(Store, TBAAInfo);
- if (!isInit && Ty->isAtomicType())
- Store->setAtomic(llvm::SequentiallyConsistent);
+ if (TBAAInfo) {
+ llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
+ TBAAOffset);
+ CGM.DecorateInstruction(Store, TBAAPath);
+ }
}
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
- bool isInit) {
+ bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(), lvalue.getType(),
- lvalue.getTBAAInfo(), isInit);
+ lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(),
+ lvalue.getTBAAOffset());
}
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
@@ -1117,8 +1300,11 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
AddrWeakObj));
}
- if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak)
- return RValue::get(EmitARCLoadWeak(LV.getAddress()));
+ if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress());
+ Object = EmitObjCConsumeObject(LV.getType(), Object);
+ return RValue::get(Object);
+ }
if (LV.isSimple()) {
assert(!LV.getType()->isFunctionType());
@@ -1149,72 +1335,30 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// Get the output type.
llvm::Type *ResLTy = ConvertType(LV.getType());
- unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
-
- // Compute the result as an OR of all of the individual component accesses.
- llvm::Value *Res = 0;
- for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
- const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- CharUnits AccessAlignment = AI.AccessAlignment;
- if (!LV.getAlignment().isZero())
- AccessAlignment = std::min(AccessAlignment, LV.getAlignment());
-
- // Get the field pointer.
- llvm::Value *Ptr = LV.getBitFieldBaseAddr();
-
- // Only offset by the field index if used, so that incoming values are not
- // required to be structures.
- if (AI.FieldIndex)
- Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
-
- // Offset by the byte offset, if used.
- if (!AI.FieldByteOffset.isZero()) {
- Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
- "bf.field.offs");
- }
-
- // Cast to the access type.
- llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), AI.AccessWidth,
- CGM.getContext().getTargetAddressSpace(LV.getType()));
- Ptr = Builder.CreateBitCast(Ptr, PTy);
-
- // Perform the load.
- llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified());
- Load->setAlignment(AccessAlignment.getQuantity());
-
- // Shift out unused low bits and mask out unused high bits.
- llvm::Value *Val = Load;
- if (AI.FieldBitStart)
- Val = Builder.CreateLShr(Load, AI.FieldBitStart);
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth,
- AI.TargetBitWidth),
- "bf.clear");
-
- // Extend or truncate to the target size.
- if (AI.AccessWidth < ResSizeInBits)
- Val = Builder.CreateZExt(Val, ResLTy);
- else if (AI.AccessWidth > ResSizeInBits)
- Val = Builder.CreateTrunc(Val, ResLTy);
-
- // Shift into place, and OR into the result.
- if (AI.TargetBitOffset)
- Val = Builder.CreateShl(Val, AI.TargetBitOffset);
- Res = Res ? Builder.CreateOr(Res, Val) : Val;
- }
- // If the bit-field is signed, perform the sign-extension.
- //
- // FIXME: This can easily be folded into the load of the high bits, which
- // could also eliminate the mask of high bits in some situations.
- if (Info.isSigned()) {
- unsigned ExtraBits = ResSizeInBits - Info.getSize();
- if (ExtraBits)
- Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits),
- ExtraBits, "bf.val.sext");
+ llvm::Value *Ptr = LV.getBitFieldAddr();
+ llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(),
+ "bf.load");
+ cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
+
+ if (Info.IsSigned) {
+ assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize);
+ unsigned HighBits = Info.StorageSize - Info.Offset - Info.Size;
+ if (HighBits)
+ Val = Builder.CreateShl(Val, HighBits, "bf.shl");
+ if (Info.Offset + HighBits)
+ Val = Builder.CreateAShr(Val, Info.Offset + HighBits, "bf.ashr");
+ } else {
+ if (Info.Offset)
+ Val = Builder.CreateLShr(Val, Info.Offset, "bf.lshr");
+ if (static_cast<unsigned>(Info.Offset) + Info.Size < Info.StorageSize)
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(Info.StorageSize,
+ Info.Size),
+ "bf.clear");
}
+ Val = Builder.CreateIntCast(Val, ResLTy, Info.IsSigned, "bf.cast");
- return RValue::get(Res);
+ return RValue::get(Val);
}
// If this is a reference to a subset of the elements of a vector, create an
@@ -1344,106 +1488,71 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
-
- // Get the output type.
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
- unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
+ llvm::Value *Ptr = Dst.getBitFieldAddr();
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- if (hasBooleanRepresentation(Dst.getType()))
- SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
-
- SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
- Info.getSize()),
- "bf.value");
-
- // Return the new value of the bit-field, if requested.
- if (Result) {
- // Cast back to the proper type for result.
- llvm::Type *SrcTy = Src.getScalarVal()->getType();
- llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false,
- "bf.reload.val");
-
- // Sign extend if necessary.
- if (Info.isSigned()) {
- unsigned ExtraBits = ResSizeInBits - Info.getSize();
- if (ExtraBits)
- ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits),
- ExtraBits, "bf.reload.sext");
- }
+ // Cast the source to the storage type and shift it into place.
+ SrcVal = Builder.CreateIntCast(SrcVal,
+ Ptr->getType()->getPointerElementType(),
+ /*IsSigned=*/false);
+ llvm::Value *MaskedVal = SrcVal;
+
+ // See if there are other bits in the bitfield's storage we'll need to load
+ // and mask together with source before storing.
+ if (Info.StorageSize != Info.Size) {
+ assert(Info.StorageSize > Info.Size && "Invalid bitfield size.");
+ llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
+ "bf.load");
+ cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
+
+ // Mask the source value as needed.
+ if (!hasBooleanRepresentation(Dst.getType()))
+ SrcVal = Builder.CreateAnd(SrcVal,
+ llvm::APInt::getLowBitsSet(Info.StorageSize,
+ Info.Size),
+ "bf.value");
+ MaskedVal = SrcVal;
+ if (Info.Offset)
+ SrcVal = Builder.CreateShl(SrcVal, Info.Offset, "bf.shl");
+
+ // Mask out the original value.
+ Val = Builder.CreateAnd(Val,
+ ~llvm::APInt::getBitsSet(Info.StorageSize,
+ Info.Offset,
+ Info.Offset + Info.Size),
+ "bf.clear");
- *Result = ReloadVal;
+ // Or together the unchanged values and the source value.
+ SrcVal = Builder.CreateOr(Val, SrcVal, "bf.set");
+ } else {
+ assert(Info.Offset == 0);
}
- // Iterate over the components, writing each piece to memory.
- for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
- const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- CharUnits AccessAlignment = AI.AccessAlignment;
- if (!Dst.getAlignment().isZero())
- AccessAlignment = std::min(AccessAlignment, Dst.getAlignment());
-
- // Get the field pointer.
- llvm::Value *Ptr = Dst.getBitFieldBaseAddr();
- unsigned addressSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
-
- // Only offset by the field index if used, so that incoming values are not
- // required to be structures.
- if (AI.FieldIndex)
- Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
-
- // Offset by the byte offset, if used.
- if (!AI.FieldByteOffset.isZero()) {
- Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
- "bf.field.offs");
- }
+ // Write the new value back out.
+ llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr,
+ Dst.isVolatileQualified());
+ Store->setAlignment(Info.StorageAlignment);
- // Cast to the access type.
- llvm::Type *AccessLTy =
- llvm::Type::getIntNTy(getLLVMContext(), AI.AccessWidth);
-
- llvm::Type *PTy = AccessLTy->getPointerTo(addressSpace);
- Ptr = Builder.CreateBitCast(Ptr, PTy);
-
- // Extract the piece of the bit-field value to write in this access, limited
- // to the values that are part of this access.
- llvm::Value *Val = SrcVal;
- if (AI.TargetBitOffset)
- Val = Builder.CreateLShr(Val, AI.TargetBitOffset);
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits,
- AI.TargetBitWidth));
-
- // Extend or truncate to the access size.
- if (ResSizeInBits < AI.AccessWidth)
- Val = Builder.CreateZExt(Val, AccessLTy);
- else if (ResSizeInBits > AI.AccessWidth)
- Val = Builder.CreateTrunc(Val, AccessLTy);
-
- // Shift into the position in memory.
- if (AI.FieldBitStart)
- Val = Builder.CreateShl(Val, AI.FieldBitStart);
-
- // If necessary, load and OR in bits that are outside of the bit-field.
- if (AI.TargetBitWidth != AI.AccessWidth) {
- llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified());
- Load->setAlignment(AccessAlignment.getQuantity());
-
- // Compute the mask for zeroing the bits that are part of the bit-field.
- llvm::APInt InvMask =
- ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart,
- AI.FieldBitStart + AI.TargetBitWidth);
-
- // Apply the mask and OR in to the value to write.
- Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val);
+ // Return the new value of the bit-field, if requested.
+ if (Result) {
+ llvm::Value *ResultVal = MaskedVal;
+
+ // Sign extend the value if needed.
+ if (Info.IsSigned) {
+ assert(Info.Size <= Info.StorageSize);
+ unsigned HighBits = Info.StorageSize - Info.Size;
+ if (HighBits) {
+ ResultVal = Builder.CreateShl(ResultVal, HighBits, "bf.result.shl");
+ ResultVal = Builder.CreateAShr(ResultVal, HighBits, "bf.result.ashr");
+ }
}
- // Write the value.
- llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr,
- Dst.isVolatileQualified());
- Store->setAlignment(AccessAlignment.getQuantity());
+ ResultVal = Builder.CreateIntCast(ResultVal, ResLTy, Info.IsSigned,
+ "bf.result.cast");
+ *Result = EmitFromMemory(ResultVal, Dst.getType());
}
}
@@ -1625,9 +1734,6 @@ EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
const Expr *E, const VarDecl *VD) {
- assert((VD->hasExternalStorage() || VD->isFileVarDecl()) &&
- "Var decl must have external storage or be a file var decl!");
-
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
@@ -1700,16 +1806,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// Check if this is a global variable.
- if (VD->hasExternalStorage() || VD->isFileVarDecl())
+ if (VD->hasLinkage() || VD->isStaticDataMember())
return EmitGlobalVarDeclLValue(*this, E, VD);
bool isBlockVariable = VD->hasAttr<BlocksAttr>();
- bool NonGCable = VD->hasLocalStorage() &&
- !VD->getType()->isReferenceType() &&
- !isBlockVariable;
-
- llvm::Value *V = LocalDeclMap[VD];
+ llvm::Value *V = LocalDeclMap.lookup(VD);
if (!V && VD->isStaticLocal())
V = CGM.getStaticLocalDeclAddress(VD);
@@ -1742,10 +1844,20 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
LV = MakeAddrLValue(V, T, Alignment);
}
+ bool isLocalStorage = VD->hasLocalStorage();
+
+ bool NonGCable = isLocalStorage &&
+ !VD->getType()->isReferenceType() &&
+ !isBlockVariable;
if (NonGCable) {
LV.getQuals().removeObjCGCAttr();
LV.setNonGC(true);
}
+
+ bool isImpreciseLifetime =
+ (isLocalStorage && !VD->hasAttr<ObjCPreciseLifetimeAttr>());
+ if (isImpreciseLifetime)
+ LV.setARCPreciseLifetime(ARCImpreciseLifetime);
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
@@ -1945,7 +2057,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
if (T->isIntegerType()) {
TypeKind = 0;
TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
- T->isSignedIntegerType();
+ (T->isSignedIntegerType() ? 1 : 0);
} else if (T->isFloatingType()) {
TypeKind = 1;
TypeInfo = getContext().getTypeSize(T);
@@ -1953,7 +2065,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
// Format the type name as if for a diagnostic, including quotes and
// optionally an 'aka'.
- llvm::SmallString<32> Buffer;
+ SmallString<32> Buffer;
CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
(intptr_t)T.getAsOpaquePtr(),
0, 0, 0, 0, 0, 0, Buffer,
@@ -1977,6 +2089,15 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
llvm::Type *TargetTy = IntPtrTy;
+ // Floating-point types which fit into intptr_t are bitcast to integers
+ // and then passed directly (after zero-extension, if necessary).
+ if (V->getType()->isFloatingPointTy()) {
+ unsigned Bits = V->getType()->getPrimitiveSizeInBits();
+ if (Bits <= TargetTy->getIntegerBitWidth())
+ V = Builder.CreateBitCast(V, llvm::Type::getIntNTy(getLLVMContext(),
+ Bits));
+ }
+
// Integers which fit in intptr_t are zero-extended and passed directly.
if (V->getType()->isIntegerTy() &&
V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth())
@@ -1984,7 +2105,7 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
// Pointers are passed directly, everything else is passed by address.
if (!V->getType()->isPointerTy()) {
- llvm::Value *Ptr = Builder.CreateAlloca(V->getType());
+ llvm::Value *Ptr = CreateTempAlloca(V->getType());
Builder.CreateStore(V, Ptr);
V = Ptr;
}
@@ -2016,23 +2137,39 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
}
void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
- llvm::ArrayRef<llvm::Constant *> StaticArgs,
- llvm::ArrayRef<llvm::Value *> DynamicArgs,
- bool Recoverable) {
+ ArrayRef<llvm::Constant *> StaticArgs,
+ ArrayRef<llvm::Value *> DynamicArgs,
+ CheckRecoverableKind RecoverKind) {
+ assert(SanOpts != &SanitizerOptions::Disabled);
+
+ if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
+ assert (RecoverKind != CRK_AlwaysRecoverable &&
+ "Runtime call required for AlwaysRecoverable kind!");
+ return EmitTrapCheck(Checked);
+ }
+
llvm::BasicBlock *Cont = createBasicBlock("cont");
llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName);
- Builder.CreateCondBr(Checked, Cont, Handler);
+
+ llvm::Instruction *Branch = Builder.CreateCondBr(Checked, Cont, Handler);
+
+ // Give hint that we very much don't expect to execute the handler
+ // Value chosen to match UR_NONTAKEN_WEIGHT, see BranchProbabilityInfo.cpp
+ llvm::MDBuilder MDHelper(getLLVMContext());
+ llvm::MDNode *Node = MDHelper.createBranchWeights((1U << 20) - 1, 1);
+ Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
+
EmitBlock(Handler);
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
llvm::GlobalValue *InfoPtr =
- new llvm::GlobalVariable(CGM.getModule(), Info->getType(), true,
+ new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
llvm::GlobalVariable::PrivateLinkage, Info);
InfoPtr->setUnnamedAddr(true);
- llvm::SmallVector<llvm::Value *, 4> Args;
- llvm::SmallVector<llvm::Type *, 4> ArgTypes;
+ SmallVector<llvm::Value *, 4> Args;
+ SmallVector<llvm::Type *, 4> ArgTypes;
Args.reserve(DynamicArgs.size() + 1);
ArgTypes.reserve(DynamicArgs.size() + 1);
@@ -2046,31 +2183,41 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArgTypes.push_back(IntPtrTy);
}
+ bool Recover = (RecoverKind == CRK_AlwaysRecoverable) ||
+ ((RecoverKind == CRK_Recoverable) &&
+ CGM.getCodeGenOpts().SanitizeRecover);
+
llvm::FunctionType *FnType =
llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
llvm::AttrBuilder B;
- if (!Recoverable) {
- B.addAttribute(llvm::Attributes::NoReturn)
- .addAttribute(llvm::Attributes::NoUnwind);
- }
- B.addAttribute(llvm::Attributes::UWTable);
- llvm::Value *Fn = CGM.CreateRuntimeFunction(FnType,
- ("__ubsan_handle_" + CheckName).str(),
- llvm::Attributes::get(getLLVMContext(),
- B));
- llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args);
- if (Recoverable) {
+ if (!Recover) {
+ B.addAttribute(llvm::Attribute::NoReturn)
+ .addAttribute(llvm::Attribute::NoUnwind);
+ }
+ B.addAttribute(llvm::Attribute::UWTable);
+
+ // Checks that have two variants use a suffix to differentiate them
+ 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::CallInst *HandlerCall = EmitNounwindRuntimeCall(Fn, Args);
+ if (Recover) {
Builder.CreateBr(Cont);
} else {
HandlerCall->setDoesNotReturn();
- HandlerCall->setDoesNotThrow();
Builder.CreateUnreachable();
}
EmitBlock(Cont);
}
-void CodeGenFunction::EmitTrapvCheck(llvm::Value *Checked) {
+void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) {
llvm::BasicBlock *Cont = createBasicBlock("cont");
// If we're optimizing, collapse all calls to trap down to just one per
@@ -2107,12 +2254,16 @@ static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
return SubExpr;
}
-LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
+ bool Accessed) {
// The index must always be an integer, which is not an aggregate. Emit it.
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
QualType IdxTy = E->getIdx()->getType();
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
+ if (SanOpts->Bounds)
+ EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
+
// If the base is a vector type, then we are forming a vector element lvalue
// with this subscript.
if (E->getBase()->getType()->isVectorType()) {
@@ -2173,7 +2324,13 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// "gep x, i" here. Emit one "gep A, 0, i".
assert(Array->getType()->isArrayType() &&
"Array to pointer decay must have array source type!");
- LValue ArrayLV = EmitLValue(Array);
+ 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))
+ ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true);
+ else
+ ArrayLV = EmitLValue(Array);
llvm::Value *ArrayPtr = ArrayLV.getAddress();
llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0);
llvm::Value *Args[] = { Zero, Idx };
@@ -2318,10 +2475,21 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
+ llvm::Value *Addr = base.getAddress();
+ unsigned Idx = RL.getLLVMFieldNo(field);
+ if (Idx != 0)
+ // For structs, we GEP to the field that the record layout suggests.
+ Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ // Get the access type.
+ llvm::Type *PtrTy = llvm::Type::getIntNPtrTy(
+ getLLVMContext(), Info.StorageSize,
+ CGM.getContext().getTargetAddressSpace(base.getType()));
+ if (Addr->getType() != PtrTy)
+ Addr = Builder.CreateBitCast(Addr, PtrTy);
+
QualType fieldType =
field->getType().withCVRQualifiers(base.getVRQualifiers());
- return LValue::MakeBitfield(base.getAddress(), Info, fieldType,
- base.getAlignment());
+ return LValue::MakeBitfield(Addr, Info, fieldType, base.getAlignment());
}
const RecordDecl *rec = field->getParent();
@@ -2337,9 +2505,12 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
llvm::Value *addr = base.getAddress();
unsigned cvr = base.getVRQualifiers();
+ bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA;
if (rec->isUnion()) {
// For unions, there is no pointer adjustment.
assert(!type->isReferenceType() && "union has reference member");
+ // TODO: handle path-aware TBAA for union.
+ TBAAPath = false;
} else {
// For structs, we GEP to the field that the record layout suggests.
unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
@@ -2351,6 +2522,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
if (cvr & Qualifiers::Volatile) load->setVolatile(true);
load->setAlignment(alignment.getQuantity());
+ // Loading the reference will disable path-aware TBAA.
+ TBAAPath = false;
if (CGM.shouldUseTBAA()) {
llvm::MDNode *tbaa;
if (mayAlias)
@@ -2384,6 +2557,16 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
LValue LV = MakeAddrLValue(addr, type, alignment);
LV.getQuals().addCVRQualifiers(cvr);
+ if (TBAAPath) {
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(field->getParent());
+ // Set the base type to be the base type of the base LValue and
+ // update offset to be relative to the base type.
+ LV.setTBAABaseType(base.getTBAABaseType());
+ LV.setTBAAOffset(base.getTBAAOffset() +
+ Layout.getFieldOffset(field->getFieldIndex()) /
+ getContext().getCharWidth());
+ }
// __weak attribute on a field is ignored.
if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
@@ -2462,8 +2645,7 @@ LValue CodeGenFunction::
EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
if (!expr->isGLValue()) {
// ?: here should be an aggregate.
- assert((hasAggregateLLVMType(expr->getType()) &&
- !expr->getType()->isAnyComplexType()) &&
+ assert(hasAggregateEvaluationKind(expr->getType()) &&
"Unexpected conditional operator!");
return EmitAggExprToLValue(expr);
}
@@ -2630,7 +2812,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
-
+
+ // 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)
+ EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
+ LV.getAddress(), E->getType());
+
// Perform the base-to-derived conversion
llvm::Value *Derived =
GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
@@ -2655,6 +2843,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
ConvertType(ToType));
return MakeAddrLValue(V, E->getType());
}
+ case CK_ZeroToOCLEvent:
+ llvm_unreachable("NULL to OpenCL event lvalue cast is not valid");
}
llvm_unreachable("Unhandled lvalue cast kind?");
@@ -2683,14 +2873,15 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
const FieldDecl *FD) {
QualType FT = FD->getType();
LValue FieldLV = EmitLValueForField(LV, FD);
- if (FT->isAnyComplexType())
- return RValue::getComplex(
- LoadComplexFromAddr(FieldLV.getAddress(),
- FieldLV.isVolatileQualified()));
- else if (CodeGenFunction::hasAggregateLLVMType(FT))
+ switch (getEvaluationKind(FT)) {
+ case TEK_Complex:
+ return RValue::getComplex(EmitLoadOfComplex(FieldLV));
+ case TEK_Aggregate:
return FieldLV.asAggregateRValue();
-
- return EmitLoadOfLValue(FieldLV);
+ case TEK_Scalar:
+ return EmitLoadOfLValue(FieldLV);
+ }
+ llvm_unreachable("bad evaluation kind");
}
//===--------------------------------------------------------------------===//
@@ -2699,8 +2890,14 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, E->getLocStart());
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ 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.
+ const FunctionDecl* Callee = E->getDirectCallee();
+ bool ForceColumnInfo = Callee && Callee->isInlineSpecified();
+ DI->EmitLocation(Builder, Loc, ForceColumnInfo);
+ }
// Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType())
@@ -2757,7 +2954,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
case Qualifiers::OCL_Strong:
EmitARCRelease(Builder.CreateLoad(BaseValue,
PseudoDtor->getDestroyedType().isVolatileQualified()),
- /*precise*/ true);
+ ARCPreciseLifetime);
break;
case Qualifiers::OCL_Weak:
@@ -2797,8 +2994,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
// Note that in all of these cases, __block variables need the RHS
// evaluated first just in case the variable gets moved by the RHS.
-
- if (!hasAggregateLLVMType(E->getType())) {
+
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Scalar: {
switch (E->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
return EmitARCStoreStrong(E, /*ignored*/ false).first;
@@ -2819,10 +3017,13 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return LV;
}
- if (E->getType()->isAnyComplexType())
+ case TEK_Complex:
return EmitComplexAssignmentLValue(E);
- return EmitAggExprToLValue(E);
+ case TEK_Aggregate:
+ return EmitAggExprToLValue(E);
+ }
+ llvm_unreachable("bad evaluation kind");
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -2895,7 +3096,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) {
llvm::Value *V =
- CGM.getObjCRuntime().GetSelector(Builder, E->getSelector(), true);
+ CGM.getObjCRuntime().GetSelector(*this, E->getSelector(), true);
return MakeAddrLValue(V, E->getType());
}
@@ -2981,7 +3182,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
// through an unprototyped function type works like a *non-variadic*
// call. The way we make this work is to cast to the exact type
// of the promoted arguments.
- if (isa<FunctionNoProtoType>(FnType) && !FnInfo.isVariadic()) {
+ if (isa<FunctionNoProtoType>(FnType)) {
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
CalleeTy = CalleeTy->getPointerTo();
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
@@ -3009,475 +3210,20 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
return MakeAddrLValue(AddV, MPT->getPointeeType());
}
-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) {
- llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
- llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- 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()));
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- case AtomicExpr::AO__atomic_load: {
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
- Load->setAtomic(Order);
- Load->setAlignment(Size);
- Load->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
- StoreDest->setAlignment(Align);
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n: {
- assert(!Dest && "Store does not return a value");
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
- Store->setAtomic(Order);
- Store->setAlignment(Size);
- Store->setVolatile(E->isVolatile());
- return;
+/// Given the address of a temporary variable, produce an r-value of
+/// its type.
+RValue CodeGenFunction::convertTempToRValue(llvm::Value *addr,
+ QualType type) {
+ LValue lvalue = MakeNaturalAlignAddrLValue(addr, type);
+ switch (getEvaluationKind(type)) {
+ case TEK_Complex:
+ return RValue::getComplex(EmitLoadOfComplex(lvalue));
+ case TEK_Aggregate:
+ return lvalue.asAggregateRValue();
+ case TEK_Scalar:
+ return RValue::get(EmitLoadOfScalar(lvalue));
}
-
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- Op = llvm::AtomicRMWInst::Xchg;
- break;
-
- case AtomicExpr::AO__atomic_add_fetch:
- PostOp = llvm::Instruction::Add;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_add:
- Op = llvm::AtomicRMWInst::Add;
- break;
-
- case AtomicExpr::AO__atomic_sub_fetch:
- PostOp = llvm::Instruction::Sub;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__atomic_fetch_sub:
- Op = llvm::AtomicRMWInst::Sub;
- break;
-
- case AtomicExpr::AO__atomic_and_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_and:
- Op = llvm::AtomicRMWInst::And;
- break;
-
- case AtomicExpr::AO__atomic_or_fetch:
- PostOp = llvm::Instruction::Or;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_or:
- Op = llvm::AtomicRMWInst::Or;
- break;
-
- case AtomicExpr::AO__atomic_xor_fetch:
- PostOp = llvm::Instruction::Xor;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_xor:
- Op = llvm::AtomicRMWInst::Xor;
- break;
-
- case AtomicExpr::AO__atomic_nand_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
- case AtomicExpr::AO__atomic_fetch_nand:
- Op = llvm::AtomicRMWInst::Nand;
- break;
- }
-
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::AtomicRMWInst *RMWI =
- CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
- RMWI->setVolatile(E->isVolatile());
-
- // For __atomic_*_fetch operations, perform the operation again to
- // determine the value which was written.
- llvm::Value *Result = RMWI;
- if (PostOp)
- Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
- if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
- Result = CGF.Builder.CreateNot(Result);
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
- StoreDest->setAlignment(Align);
-}
-
-// This function emits any expression (scalar, complex, or aggregate)
-// into a temporary alloca.
-static llvm::Value *
-EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
- llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
- CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
- /*Init*/ true);
- return DeclPtr;
-}
-
-static RValue ConvertTempToRValue(CodeGenFunction &CGF, QualType Ty,
- llvm::Value *Dest) {
- if (Ty->isAnyComplexType())
- return RValue::getComplex(CGF.LoadComplexFromAddr(Dest, false));
- if (CGF.hasAggregateLLVMType(Ty))
- return RValue::getAggregate(Dest);
- return RValue::get(CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(Dest, Ty)));
-}
-
-RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
- QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
- QualType MemTy = AtomicTy;
- if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
- MemTy = AT->getValueType();
- CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
- uint64_t Size = sizeChars.getQuantity();
- CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
- unsigned Align = alignChars.getQuantity();
- unsigned MaxInlineWidthInBits =
- getContext().getTargetInfo().getMaxAtomicInlineWidth();
- bool UseLibcall = (Size != Align ||
- getContext().toBits(sizeChars) > MaxInlineWidthInBits);
-
- llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
- Ptr = EmitScalarExpr(E->getPtr());
-
- if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
- assert(!Dest && "Init does not return a value");
- if (!hasAggregateLLVMType(E->getVal1()->getType())) {
- QualType PointeeType
- = E->getPtr()->getType()->getAs<PointerType>()->getPointeeType();
- EmitScalarInit(EmitScalarExpr(E->getVal1()),
- LValue::MakeAddr(Ptr, PointeeType, alignChars,
- getContext()));
- } else if (E->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(E->getVal1(), Ptr, E->isVolatile());
- } else {
- AggValueSlot Slot = AggValueSlot::forAddr(Ptr, alignChars,
- AtomicTy.getQualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
- EmitAggExpr(E->getVal1(), Slot);
- }
- return RValue::get(0);
- }
-
- Order = EmitScalarExpr(E->getOrder());
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- break;
-
- case AtomicExpr::AO__atomic_load:
- Dest = EmitScalarExpr(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_store:
- Val1 = EmitScalarExpr(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_exchange:
- Val1 = EmitScalarExpr(E->getVal1());
- Dest = EmitScalarExpr(E->getVal2());
- break;
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- case AtomicExpr::AO__atomic_compare_exchange:
- Val1 = EmitScalarExpr(E->getVal1());
- if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
- Val2 = EmitScalarExpr(E->getVal2());
- else
- Val2 = EmitValToTemp(*this, E->getVal2());
- OrderFail = EmitScalarExpr(E->getOrderFail());
- // Evaluate and discard the 'weak' argument.
- if (E->getNumSubExprs() == 6)
- EmitScalarExpr(E->getWeak());
- break;
-
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- if (MemTy->isPointerType()) {
- // For pointer arithmetic, we're required to do a bit of math:
- // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
- // ... but only for the C11 builtins. The GNU builtins expect the
- // user to multiply by sizeof(T).
- QualType Val1Ty = E->getVal1()->getType();
- llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
- CharUnits PointeeIncAmt =
- getContext().getTypeSizeInChars(MemTy->getPointeeType());
- Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
- Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
- EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
- break;
- }
- // Fall through.
- case AtomicExpr::AO__atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_sub:
- case AtomicExpr::AO__atomic_add_fetch:
- case AtomicExpr::AO__atomic_sub_fetch:
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_store_n:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_nand:
- case AtomicExpr::AO__atomic_and_fetch:
- case AtomicExpr::AO__atomic_or_fetch:
- case AtomicExpr::AO__atomic_xor_fetch:
- case AtomicExpr::AO__atomic_nand_fetch:
- Val1 = EmitValToTemp(*this, E->getVal1());
- break;
- }
-
- if (!E->getType()->isVoidType() && !Dest)
- Dest = CreateMemTemp(E->getType(), ".atomicdst");
-
- // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
- if (UseLibcall) {
-
- llvm::SmallVector<QualType, 5> Params;
- CallArgList Args;
- // Size is always the first parameter
- Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
- getContext().getSizeType());
- // Atomic address is always the second parameter
- Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
- getContext().VoidPtrTy);
-
- const char* LibCallName;
- QualType RetTy = getContext().VoidTy;
- switch (E->getOp()) {
- // There is only one libcall for compare an exchange, because there is no
- // optimisation benefit possible from a libcall version of a weak compare
- // and exchange.
- // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
- // void *desired, int success, int failure)
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- LibCallName = "__atomic_compare_exchange";
- RetTy = getContext().BoolTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(Order),
- getContext().IntTy);
- Order = OrderFail;
- break;
- // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
- // int order)
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- LibCallName = "__atomic_exchange";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
- break;
- // void __atomic_store(size_t size, void *mem, void *val, int order)
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n:
- LibCallName = "__atomic_store";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- break;
- // void __atomic_load(size_t size, void *mem, void *return, int order)
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- LibCallName = "__atomic_load";
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
- break;
-#if 0
- // These are only defined for 1-16 byte integers. It is not clear what
- // their semantics would be on anything else...
- case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
- case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
- case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
- case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
- case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
-#endif
- default: return EmitUnsupportedRValue(E, "atomic library call");
- }
- // order is always the last parameter
- Args.add(RValue::get(Order),
- getContext().IntTy);
-
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
- FunctionType::ExtInfo(), RequiredArgs::All);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
- if (E->isCmpXChg())
- return Res;
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), Dest);
- }
-
- bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store_n;
- bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load_n;
-
- llvm::Type *IPtrTy =
- llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
- llvm::Value *OrigDest = Dest;
- Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
- if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
- if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
- if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
-
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- switch (ord) {
- case 0: // memory_order_relaxed
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
- break;
- case 1: // memory_order_consume
- case 2: // memory_order_acquire
- if (IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
- break;
- case 3: // memory_order_release
- if (IsLoad)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
- break;
- case 4: // 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);
- break;
- case 5: // memory_order_seq_cst
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
- break;
- default: // invalid order
- // We should not ever get here normally, but it's hard to
- // enforce that in general.
- break;
- }
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), OrigDest);
- }
-
- // 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;
- MonotonicBB = createBasicBlock("monotonic", CurFn);
- if (!IsStore)
- AcquireBB = createBasicBlock("acquire", CurFn);
- if (!IsLoad)
- ReleaseBB = createBasicBlock("release", CurFn);
- if (!IsLoad && !IsStore)
- AcqRelBB = createBasicBlock("acqrel", CurFn);
- SeqCstBB = createBasicBlock("seqcst", CurFn);
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- // Create the switch for the split
- // 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.
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
-
- // Emit all the different atomics
- Builder.SetInsertPoint(MonotonicBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
- Builder.CreateBr(ContBB);
- if (!IsStore) {
- Builder.SetInsertPoint(AcquireBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(1), AcquireBB);
- SI->addCase(Builder.getInt32(2), AcquireBB);
- }
- if (!IsLoad) {
- Builder.SetInsertPoint(ReleaseBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(3), ReleaseBB);
- }
- if (!IsLoad && !IsStore) {
- Builder.SetInsertPoint(AcqRelBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(4), AcqRelBB);
- }
- Builder.SetInsertPoint(SeqCstBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(5), SeqCstBB);
-
- // Cleanup and return
- Builder.SetInsertPoint(ContBB);
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), OrigDest);
+ llvm_unreachable("bad evaluation kind");
}
void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) {
@@ -3502,7 +3248,7 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
const PseudoObjectExpr *E,
bool forLValue,
AggValueSlot slot) {
- llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+ SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
// Find the result expression, if any.
const Expr *resultExpr = E->getResultExpr();
@@ -3521,8 +3267,7 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
typedef CodeGenFunction::OpaqueValueMappingData OVMA;
OVMA opaqueData;
if (ov == resultExpr && ov->isRValue() && !forLValue &&
- CodeGenFunction::hasAggregateLLVMType(ov->getType()) &&
- !ov->getType()->isAnyComplexType()) {
+ CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) {
CGF.EmitAggExpr(ov->getSourceExpr(), slot);
LValue LV = CGF.MakeAddrLValue(slot.getAddr(), ov->getType());
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 718e8f999ce7..1ac13c01ed4e 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -12,16 +12,16 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Intrinsics.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -29,6 +29,14 @@ using namespace CodeGen;
// Aggregate Expression Emitter
//===----------------------------------------------------------------------===//
+llvm::Value *AggValueSlot::getPaddedAtomicAddr() const {
+ assert(isValueOfAtomic());
+ llvm::GEPOperator *op = cast<llvm::GEPOperator>(getAddr());
+ assert(op->getNumIndices() == 2);
+ assert(op->hasAllZeroIndices());
+ return op->getPointerOperand();
+}
+
namespace {
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
@@ -190,6 +198,38 @@ public:
CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr());
}
};
+
+/// A helper class for emitting expressions into the value sub-object
+/// of a padded atomic type.
+class ValueDestForAtomic {
+ AggValueSlot Dest;
+public:
+ ValueDestForAtomic(CodeGenFunction &CGF, AggValueSlot dest, QualType type)
+ : Dest(dest) {
+ assert(!Dest.isValueOfAtomic());
+ if (!Dest.isIgnored() && CGF.CGM.isPaddedAtomicType(type)) {
+ llvm::Value *valueAddr = CGF.Builder.CreateStructGEP(Dest.getAddr(), 0);
+ Dest = AggValueSlot::forAddr(valueAddr,
+ Dest.getAlignment(),
+ Dest.getQualifiers(),
+ Dest.isExternallyDestructed(),
+ Dest.requiresGCollection(),
+ Dest.isPotentiallyAliased(),
+ Dest.isZeroed(),
+ AggValueSlot::IsValueOfAtomic);
+ }
+ }
+
+ const AggValueSlot &getDest() const { return Dest; }
+
+ ~ValueDestForAtomic() {
+ // Kill the GEP if we made one and it didn't end up used.
+ if (Dest.isValueOfAtomic()) {
+ llvm::Instruction *addr = cast<llvm::GetElementPtrInst>(Dest.getAddr());
+ if (addr->use_empty()) addr->eraseFromParent();
+ }
+ }
+};
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -201,6 +241,14 @@ public:
/// then loads the result into DestPtr.
void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
LValue LV = CGF.EmitLValue(E);
+
+ // If the type of the l-value is atomic, then do an atomic load.
+ if (LV.getType()->isAtomicType()) {
+ ValueDestForAtomic valueDest(CGF, Dest, LV.getType());
+ CGF.EmitAtomicLoad(LV, valueDest.getDest());
+ return;
+ }
+
EmitFinalDestCopy(E->getType(), LV);
}
@@ -213,7 +261,7 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
// Don't mess with non-trivial C++ types.
RecordDecl *Record = RecordTy->getDecl();
if (isa<CXXRecordDecl>(Record) &&
- (!cast<CXXRecordDecl>(Record)->hasTrivialCopyConstructor() ||
+ (cast<CXXRecordDecl>(Record)->hasNonTrivialCopyConstructor() ||
!cast<CXXRecordDecl>(Record)->hasTrivialDestructor()))
return false;
@@ -531,12 +579,10 @@ void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
void
AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- if (E->getType().isPODType(CGF.getContext())) {
+ if (Dest.isPotentiallyAliased() &&
+ E->getType().isPODType(CGF.getContext())) {
// For a POD type, just emit a load of the lvalue + a copy, because our
// compound literal might alias the destination.
- // FIXME: This is a band-aid; the real problem appears to be in our handling
- // of assignments, where we store directly into the LHS without checking
- // whether anything in the RHS aliases.
EmitAggLoadOfLValue(E);
return;
}
@@ -545,6 +591,20 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
CGF.EmitAggExpr(E->getInitializer(), Slot);
}
+/// Attempt to look through various unimportant expressions to find a
+/// cast of the given kind.
+static Expr *findPeephole(Expr *op, CastKind kind) {
+ while (true) {
+ op = op->IgnoreParens();
+ if (CastExpr *castE = dyn_cast<CastExpr>(op)) {
+ if (castE->getCastKind() == kind)
+ return castE->getSubExpr();
+ if (castE->getCastKind() == CK_NoOp)
+ continue;
+ }
+ return 0;
+ }
+}
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
@@ -584,6 +644,75 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
"should have been unpacked before we got here");
}
+ case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ bool isToAtomic = (E->getCastKind() == CK_NonAtomicToAtomic);
+
+ // Determine the atomic and value types.
+ QualType atomicType = E->getSubExpr()->getType();
+ QualType valueType = E->getType();
+ if (isToAtomic) std::swap(atomicType, valueType);
+
+ assert(atomicType->isAtomicType());
+ assert(CGF.getContext().hasSameUnqualifiedType(valueType,
+ atomicType->castAs<AtomicType>()->getValueType()));
+
+ // Just recurse normally if we're ignoring the result or the
+ // atomic type doesn't change representation.
+ if (Dest.isIgnored() || !CGF.CGM.isPaddedAtomicType(atomicType)) {
+ return Visit(E->getSubExpr());
+ }
+
+ CastKind peepholeTarget =
+ (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
+
+ // These two cases are reverses of each other; try to peephole them.
+ if (Expr *op = findPeephole(E->getSubExpr(), peepholeTarget)) {
+ assert(CGF.getContext().hasSameUnqualifiedType(op->getType(),
+ E->getType()) &&
+ "peephole significantly changed types?");
+ return Visit(op);
+ }
+
+ // If we're converting an r-value of non-atomic type to an r-value
+ // of atomic type, just make an atomic temporary, emit into that,
+ // and then copy the value out. (FIXME: do we need to
+ // zero-initialize it first?)
+ if (isToAtomic) {
+ ValueDestForAtomic valueDest(CGF, Dest, atomicType);
+ CGF.EmitAggExpr(E->getSubExpr(), valueDest.getDest());
+ return;
+ }
+
+ // Otherwise, we're converting an atomic type to a non-atomic type.
+
+ // If the dest is a value-of-atomic subobject, drill back out.
+ if (Dest.isValueOfAtomic()) {
+ AggValueSlot atomicSlot =
+ AggValueSlot::forAddr(Dest.getPaddedAtomicAddr(),
+ Dest.getAlignment(),
+ Dest.getQualifiers(),
+ Dest.isExternallyDestructed(),
+ Dest.requiresGCollection(),
+ Dest.isPotentiallyAliased(),
+ Dest.isZeroed(),
+ AggValueSlot::IsNotValueOfAtomic);
+ CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
+ return;
+ }
+
+ // Otherwise, make an atomic temporary, emit into that, and then
+ // copy the value out.
+ AggValueSlot atomicSlot =
+ CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
+ CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
+
+ llvm::Value *valueAddr =
+ Builder.CreateStructGEP(atomicSlot.getAddr(), 0);
+ RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile());
+ return EmitFinalDestCopy(valueType, rvalue);
+ }
+
case CK_LValueToRValue:
// If we're loading from a volatile type, force the destination
// into existence.
@@ -591,11 +720,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
EnsureDest(E->getType());
return Visit(E->getSubExpr());
}
+
// fallthrough
case CK_NoOp:
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
@@ -648,6 +776,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -776,6 +905,12 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// Now emit the LHS and copy into it.
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
+ // That copy is an atomic copy if the LHS is atomic.
+ if (LHS.getType()->isAtomicType()) {
+ CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
+ return;
+ }
+
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
@@ -786,11 +921,25 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LHS = CGF.EmitLValue(E->getLHS());
+ // If we have an atomic type, evaluate into the destination and then
+ // do an atomic copy.
+ if (LHS.getType()->isAtomicType()) {
+ EnsureDest(E->getRHS()->getType());
+ Visit(E->getRHS());
+ CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
+ return;
+ }
+
// Codegen the RHS so that it stores directly into the LHS.
AggValueSlot LHSSlot =
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased);
+ // A non-volatile aggregate destination might have volatile member.
+ if (!LHSSlot.isVolatile() &&
+ CGF.hasVolatileMember(E->getLHS()->getType()))
+ LHSSlot.setVolatile(true);
+
CGF.EmitAggExpr(E->getRHS(), LHSSlot);
// Copy into the destination if the assignment isn't ignored.
@@ -931,24 +1080,34 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
// FIXME: Are initializers affected by volatile?
if (Dest.isZeroed() && isSimpleZero(E, CGF)) {
// Storing "i32 0" to a zero'd memory location is a noop.
- } else if (isa<ImplicitValueInitExpr>(E)) {
- EmitNullInitializationToLValue(LV);
+ return;
+ } else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
+ return EmitNullInitializationToLValue(LV);
} else if (type->isReferenceType()) {
RValue RV = CGF.EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
- CGF.EmitStoreThroughLValue(RV, LV);
- } else if (type->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
- } else if (CGF.hasAggregateLLVMType(type)) {
+ return CGF.EmitStoreThroughLValue(RV, LV);
+ }
+
+ switch (CGF.getEvaluationKind(type)) {
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(E, LV, /*isInit*/ true);
+ return;
+ case TEK_Aggregate:
CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
Dest.isZeroed()));
- } else if (LV.isSimple()) {
- CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
- } else {
- CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
+ return;
+ case TEK_Scalar:
+ if (LV.isSimple()) {
+ CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
+ } else {
+ CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
+ }
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
@@ -959,9 +1118,9 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(type))
return;
- if (!CGF.hasAggregateLLVMType(type)) {
- // For non-aggregates, we can store zero.
- llvm::Value *null = llvm::Constant::getNullValue(CGF.ConvertType(type));
+ if (CGF.hasScalarEvaluationKind(type)) {
+ // For non-aggregates, we can store the appropriate null constant.
+ llvm::Value *null = CGF.CGM.EmitNullConstant(type);
// Note that the following is not equivalent to
// EmitStoreThroughBitfieldLValue for ARC types.
if (lv.isBitField()) {
@@ -1250,7 +1409,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
/// the value of the aggregate expression is not needed. If VolatileDest is
/// true, DestPtr cannot be 0.
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
- assert(E && hasAggregateLLVMType(E->getType()) &&
+ assert(E && hasAggregateEvaluationKind(E->getType()) &&
"Invalid aggregate expression to emit");
assert((Slot.getAddr() != 0 || Slot.isIgnored()) &&
"slot has bits but no address");
@@ -1262,7 +1421,7 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
}
LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
- assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
+ assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed,
@@ -1285,7 +1444,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
Record->hasTrivialCopyAssignment() ||
Record->hasTrivialMoveConstructor() ||
Record->hasTrivialMoveAssignment()) &&
- "Trying to aggregate-copy a type without a trivial copy "
+ "Trying to aggregate-copy a type without a trivial copy/move "
"constructor or assignment operator");
// Ignore empty classes in C++.
if (Record->isEmpty())
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 7f640f6e6433..83c8ace98cd4 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/CodeGenOptions.h"
#include "CodeGenFunction.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
#include "CGDebugInfo.h"
-#include "llvm/Intrinsics.h"
+#include "CGObjCRuntime.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CallSite.h"
using namespace clang;
@@ -28,7 +28,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
- llvm::Value *VTT,
+ llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
assert(MD->isInstance() &&
@@ -46,10 +47,9 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
// Push the this ptr.
Args.add(RValue::get(This), MD->getThisType(getContext()));
- // If there is a VTT parameter, emit it.
- if (VTT) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
- Args.add(RValue::get(VTT), T);
+ // If there is an implicit parameter (e.g. VTT), emit it.
+ if (ImplicitParam) {
+ Args.add(RValue::get(ImplicitParam), ImplicitParamTy);
}
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
@@ -284,7 +284,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
llvm::Value *Callee;
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
if (UseVirtualCall) {
- Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty);
+ assert(CE->arg_begin() == CE->arg_end() &&
+ "Virtual destructor shouldn't have explicit parameters");
+ return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
+ Dtor_Complete,
+ CE->getExprLoc(),
+ ReturnValue, This);
} else {
if (getLangOpts().AppleKext &&
MD->isVirtual() &&
@@ -316,7 +321,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
- /*VTT=*/0, CE->arg_begin(), CE->arg_end());
+ /*ImplicitParam=*/0, QualType(),
+ CE->arg_begin(), CE->arg_end());
}
RValue
@@ -388,7 +394,8 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
- /*VTT=*/0, E->arg_begin() + 1, E->arg_end());
+ /*ImplicitParam=*/0, QualType(),
+ E->arg_begin() + 1, E->arg_end());
}
RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -485,11 +492,13 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
} else {
CXXCtorType Type = Ctor_Complete;
bool ForVirtualBase = false;
-
+ bool Delegating = false;
+
switch (E->getConstructionKind()) {
case CXXConstructExpr::CK_Delegating:
// We should be emitting a constructor; GlobalDecl will assert this
Type = CurGD.getCtorType();
+ Delegating = true;
break;
case CXXConstructExpr::CK_Complete:
@@ -505,7 +514,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
}
// Call the constructor.
- EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(),
+ EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating, Dest.getAddr(),
E->arg_begin(), E->arg_end());
}
}
@@ -811,14 +820,18 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
QualType AllocType, llvm::Value *NewPtr) {
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
- if (!CGF.hasAggregateLLVMType(AllocType))
+ switch (CGF.getEvaluationKind(AllocType)) {
+ case TEK_Scalar:
CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType,
Alignment),
false);
- else if (AllocType->isAnyComplexType())
- CGF.EmitComplexExprIntoAddr(Init, NewPtr,
- AllocType.isVolatileQualified());
- else {
+ return;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType,
+ Alignment),
+ /*isInit*/ true);
+ return;
+ case TEK_Aggregate: {
AggValueSlot Slot
= AggValueSlot::forAddr(NewPtr, Alignment, AllocType.getQualifiers(),
AggValueSlot::IsDestructed,
@@ -827,7 +840,10 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
CGF.EmitAggExpr(Init, Slot);
CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init);
+ return;
+ }
}
+ llvm_unreachable("bad evaluation kind");
}
void
@@ -1395,18 +1411,12 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
completePtr, OperatorDelete,
ElementType);
}
-
- llvm::Type *Ty =
- CGF.getTypes().GetFunctionType(
- CGF.getTypes().arrangeCXXDestructor(Dtor, Dtor_Complete));
-
- llvm::Value *Callee
- = CGF.BuildVirtualCall(Dtor,
- UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
- Ptr, Ty);
+
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
- Ptr, /*VTT=*/0, 0, 0);
+ CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+ CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
+ SourceLocation(),
+ ReturnValueSlot(), Ptr);
if (UseGlobalDelete) {
CGF.PopCleanupBlock();
@@ -1425,7 +1435,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false, Ptr);
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false,
+ Ptr);
else if (CGF.getLangOpts().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType()) {
switch (ElementType.getObjCLifetime()) {
@@ -1439,7 +1451,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr,
ElementType.isVolatileQualified());
- CGF.EmitARCRelease(PtrValue, /*precise*/ true);
+ CGF.EmitARCRelease(PtrValue, ARCPreciseLifetime);
break;
}
@@ -1612,7 +1624,7 @@ static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
static void EmitBadTypeidCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -1685,11 +1697,16 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
CGF.ConvertType(CGF.getContext().getPointerDiffType());
llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int8PtrTy, Args, false);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast");
+
+ 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) {
@@ -1700,10 +1717,62 @@ static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
static void EmitBadCastCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
+ 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,
@@ -1753,13 +1822,19 @@ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
llvm::Value *DestRTTI =
CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
- // FIXME: Actually compute a hint here.
- llvm::Value *OffsetHint = llvm::ConstantInt::get(PtrDiffLTy, -1ULL);
+ // 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);
- Value = CGF.Builder.CreateCall4(getDynamicCastFn(CGF), Value,
- SrcRTTI, DestRTTI, OffsetHint);
+
+ llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };
+ Value = CGF.EmitNounwindRuntimeCall(getDynamicCastFn(CGF), args);
Value = CGF.Builder.CreateBitCast(Value, DestLTy);
/// C++ [expr.dynamic.cast]p9:
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 66b6f8629a52..5fc73aa7901b 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -15,9 +15,9 @@
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
using namespace clang;
using namespace CodeGen;
@@ -27,12 +27,21 @@ using namespace CodeGen;
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
+/// Return the complex type that we are meant to emit.
+static const ComplexType *getComplexType(QualType type) {
+ type = type.getCanonicalType();
+ if (const ComplexType *comp = dyn_cast<ComplexType>(type)) {
+ return comp;
+ } else {
+ return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+ }
+}
+
namespace {
class ComplexExprEmitter
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
- // True is we should ignore the value of a
bool IgnoreReal;
bool IgnoreImag;
public:
@@ -63,25 +72,11 @@ public:
return EmitLoadOfLValue(CGF.EmitLValue(E));
}
- ComplexPairTy EmitLoadOfLValue(LValue LV) {
- assert(LV.isSimple() && "complex l-value must be simple");
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
- }
-
- /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
- /// the real and imaginary pieces.
- ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile);
-
- /// EmitStoreThroughLValue - Given an l-value of complex type, store
- /// a complex number into it.
- void EmitStoreThroughLValue(ComplexPairTy Val, LValue LV) {
- assert(LV.isSimple() && "complex l-value must be simple");
- return EmitStoreOfComplex(Val, LV.getAddress(), LV.isVolatileQualified());
- }
+ ComplexPairTy EmitLoadOfLValue(LValue LV);
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
- void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol);
+ void EmitStoreOfComplex(ComplexPairTy Val, LValue LV, bool isInit);
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
@@ -194,13 +189,13 @@ public:
}
ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
}
ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Constant *Null =
llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
@@ -286,10 +281,16 @@ public:
// Utilities
//===----------------------------------------------------------------------===//
-/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
+/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
/// load the real and imaginary pieces, returning them as Real/Imag.
-ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
- bool isVolatile) {
+ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue) {
+ assert(lvalue.isSimple() && "non-simple complex l-value?");
+ if (lvalue.getType()->isAtomicType())
+ return CGF.EmitAtomicLoad(lvalue).getComplexVal();
+
+ llvm::Value *SrcPtr = lvalue.getAddress();
+ bool isVolatile = lvalue.isVolatileQualified();
+
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal || isVolatile) {
@@ -308,13 +309,19 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
-void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
- bool isVolatile) {
+void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val,
+ LValue lvalue,
+ bool isInit) {
+ if (lvalue.getType()->isAtomicType())
+ return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
+
+ llvm::Value *Ptr = lvalue.getAddress();
llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real");
llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag");
- Builder.CreateStore(Val.first, RealPtr, isVolatile);
- Builder.CreateStore(Val.second, ImagPtr, isVolatile);
+ // TODO: alignment
+ Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
+ Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
}
@@ -326,7 +333,7 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
CGF.ErrorUnsupported(E, "complex expression");
llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ CGF.ConvertType(getComplexType(E->getType())->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
@@ -355,8 +362,8 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
QualType SrcType,
QualType DestType) {
// Get the src/dest element type.
- SrcType = SrcType->getAs<ComplexType>()->getElementType();
- DestType = DestType->getAs<ComplexType>()->getElementType();
+ SrcType = SrcType->castAs<ComplexType>()->getElementType();
+ DestType = DestType->castAs<ComplexType>()->getElementType();
// C99 6.3.1.6: When a value of complex type is converted to another
// complex type, both the real and imaginary parts follow the conversion
@@ -381,11 +388,12 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
return Visit(Op);
case CK_LValueBitCast: {
- llvm::Value *V = CGF.EmitLValue(Op).getAddress();
+ LValue origLV = CGF.EmitLValue(Op);
+ llvm::Value *V = origLV.getAddress();
V = Builder.CreateBitCast(V,
CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
- // FIXME: Are the qualifiers correct here?
- return EmitLoadOfComplex(V, DestTy.isVolatileQualified());
+ return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy,
+ origLV.getAlignment()));
}
case CK_BitCast:
@@ -428,6 +436,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -435,7 +444,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
llvm::Value *Elt = CGF.EmitScalarExpr(Op);
// Convert the input element to the element type of the complex.
- DestTy = DestTy->getAs<ComplexType>()->getElementType();
+ DestTy = DestTy->castAs<ComplexType>()->getElementType();
Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
// Return (realval, 0).
@@ -568,7 +577,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi); // a*d
llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8); // bc-ad
- if (Op.Ty->getAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
+ if (Op.Ty->castAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
DSTr = Builder.CreateUDiv(Tmp3, Tmp6);
DSTi = Builder.CreateUDiv(Tmp9, Tmp6);
} else {
@@ -628,7 +637,7 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Val = Result;
// Store the result value into the LHS lvalue.
- EmitStoreThroughLValue(Result, LHS);
+ EmitStoreOfComplex(Result, LHS, /*isInit*/ false);
return LHS;
}
@@ -648,7 +657,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ return EmitLoadOfLValue(LV);
}
LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
@@ -666,7 +675,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
LValue LHS = CGF.EmitLValue(E->getLHS());
// Store the result value into the LHS lvalue.
- EmitStoreThroughLValue(Val, LHS);
+ EmitStoreOfComplex(Val, LHS, /*isInit*/ false);
return LHS;
}
@@ -683,7 +692,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ return EmitLoadOfLValue(LV);
}
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -754,7 +763,7 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Empty init list intializes to null
assert(E->getNumInits() == 0 && "Unexpected number of inits");
- QualType Ty = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Ty = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Type* LTy = CGF.ConvertType(Ty);
llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
return ComplexPairTy(zeroConstant, zeroConstant);
@@ -767,13 +776,13 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
if (!ArgPtr) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ CGF.ConvertType(E->getType()->castAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
- // FIXME Volatility.
- return EmitLoadOfComplex(ArgPtr, false);
+ return EmitLoadOfLValue(
+ CGF.MakeNaturalAlignAddrLValue(ArgPtr, E->getType()));
}
//===----------------------------------------------------------------------===//
@@ -784,36 +793,31 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
/// complex type, ignoring the result.
ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
bool IgnoreImag) {
- assert(E && E->getType()->isAnyComplexType() &&
+ assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag)
.Visit(const_cast<Expr*>(E));
}
-/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
-/// of complex type, storing into the specified Value*.
-void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E,
- llvm::Value *DestAddr,
- bool DestIsVolatile) {
- assert(E && E->getType()->isAnyComplexType() &&
+void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest,
+ bool isInit) {
+ assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
ComplexExprEmitter Emitter(*this);
ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
- Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile);
+ Emitter.EmitStoreOfComplex(Val, dest, isInit);
}
-/// StoreComplexToAddr - Store a complex number into the specified address.
-void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V,
- llvm::Value *DestAddr,
- bool DestIsVolatile) {
- ComplexExprEmitter(*this).EmitStoreOfComplex(V, DestAddr, DestIsVolatile);
+/// EmitStoreOfComplex - Store a complex number into the specified l-value.
+void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest,
+ bool isInit) {
+ ComplexExprEmitter(*this).EmitStoreOfComplex(V, dest, isInit);
}
-/// LoadComplexFromAddr - Load a complex number from the specified address.
-ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
- bool SrcIsVolatile) {
- return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile);
+/// EmitLoadOfComplex - Load a complex number from the specified address.
+ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src) {
+ return ComplexExprEmitter(*this).EmitLoadOfLValue(src);
}
LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 206f74a30258..faaf6468f1e3 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
+#include "CodeGenModule.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
using namespace clang;
using namespace CodeGen;
@@ -455,7 +455,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
// Accumulate and sort bases, in order to visit them in address order, which
// may not be the same as declaration order.
- llvm::SmallVector<BaseInfo, 8> Bases;
+ SmallVector<BaseInfo, 8> Bases;
Bases.reserve(CD->getNumBases());
unsigned BaseNo = 0;
for (CXXRecordDecl::base_class_const_iterator Base = CD->bases_begin(),
@@ -747,6 +747,7 @@ public:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
+ case CK_ZeroToOCLEvent:
return 0;
}
llvm_unreachable("Invalid CastKind");
@@ -905,10 +906,8 @@ public:
if (!VD->hasLocalStorage()) {
if (VD->isFileVarDecl() || VD->hasExternalStorage())
return CGM.GetAddrOfGlobalVar(VD);
- else if (VD->isLocalVarDecl()) {
- assert(CGF && "Can't access static local vars without CGF");
- return CGF->GetAddrOfStaticLocalVar(VD);
- }
+ else if (VD->isLocalVarDecl())
+ return CGM.getStaticLocalDeclAddress(VD);
}
}
return 0;
@@ -1008,6 +1007,22 @@ public:
llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
CodeGenFunction *CGF) {
+ // Make a quick check if variable can be default NULL initialized
+ // and avoid going through rest of code which may do, for c++11,
+ // initialization of memory to all NULLs.
+ if (!D.hasLocalStorage()) {
+ QualType Ty = D.getType();
+ if (Ty->isArrayType())
+ Ty = Context.getBaseElementType(Ty);
+ if (Ty->isRecordType())
+ if (const CXXConstructExpr *E =
+ dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
+ const CXXConstructorDecl *CD = E->getConstructor();
+ if (CD->isTrivial() && CD->isDefaultConstructor())
+ return EmitNullConstant(D.getType());
+ }
+ }
+
if (const APValue *Value = D.evaluateValue())
return EmitConstantValueForMemory(*Value, D.getType(), CGF);
@@ -1124,7 +1139,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
}
case APValue::Float: {
const llvm::APFloat &Init = Value.getFloat();
- if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf)
+ if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf &&
+ !Context.getLangOpts().NativeHalfType)
return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
else
return llvm::ConstantFP::get(VMContext, Init);
@@ -1197,6 +1213,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
if (I < NumInitElts)
C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I),
CAT->getElementType(), CGF);
+ else
+ assert(Filler && "Missing filler for implicit elements of initializer");
if (I == 0)
CommonElementType = C->getType();
else if (C->getType() != CommonElementType)
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index b429b1d6e47e..ffd0eb5572db 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -11,24 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/CodeGenOptions.h"
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
+#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
-#include "CGDebugInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
+#include "clang/Frontend/CodeGenOptions.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 "llvm/DataLayout.h"
#include <cstdarg>
using namespace clang;
@@ -266,7 +266,7 @@ public:
Value *VisitInitListExpr(InitListExpr *E);
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- return CGF.CGM.EmitNullConstant(E->getType());
+ return EmitNullValue(E->getType());
}
Value *VisitExplicitCastExpr(ExplicitCastExpr *E) {
if (E->getType()->isVariablyModifiedType())
@@ -406,7 +406,7 @@ public:
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -414,6 +414,9 @@ public:
}
}
+ if (Ops.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ return EmitOverflowCheckedBinOp(Ops);
+
if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
@@ -425,6 +428,8 @@ public:
// Check for undefined division and modulus behaviors.
void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
+ // Common helper for getting how wide LHS of shift is.
+ static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS);
Value *EmitDiv(const BinOpInfo &Ops);
Value *EmitRem(const BinOpInfo &Ops);
Value *EmitAdd(const BinOpInfo &Ops);
@@ -578,62 +583,93 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
Check = Builder.CreateAnd(GE, LE);
}
} else {
- // Floating-point to integer or floating-point to floating-point. This has
- // undefined behavior if the source is +-Inf, NaN, or doesn't fit into the
- // destination type.
const llvm::fltSemantics &SrcSema =
CGF.getContext().getFloatTypeSemantics(OrigSrcType);
- APFloat MaxSrc(SrcSema, APFloat::uninitialized);
- APFloat MinSrc(SrcSema, APFloat::uninitialized);
-
if (isa<llvm::IntegerType>(DstTy)) {
+ // Floating-point to integer. This has undefined behavior if the source is
+ // +-Inf, NaN, or doesn't fit into the destination type (after truncation
+ // to an integer).
unsigned Width = CGF.getContext().getIntWidth(DstType);
bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
APSInt Min = APSInt::getMinValue(Width, Unsigned);
+ APFloat MinSrc(SrcSema, APFloat::uninitialized);
if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
APFloat::opOverflow)
// Don't need an overflow check for lower bound. Just check for
// -Inf/NaN.
- MinSrc = APFloat::getLargest(SrcSema, true);
+ MinSrc = APFloat::getInf(SrcSema, true);
+ else
+ // Find the largest value which is too small to represent (before
+ // truncation toward zero).
+ MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
APSInt Max = APSInt::getMaxValue(Width, Unsigned);
+ APFloat MaxSrc(SrcSema, APFloat::uninitialized);
if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
APFloat::opOverflow)
// Don't need an overflow check for upper bound. Just check for
// +Inf/NaN.
- MaxSrc = APFloat::getLargest(SrcSema, false);
+ MaxSrc = APFloat::getInf(SrcSema, false);
+ else
+ // Find the smallest value which is too large to represent (before
+ // truncation toward zero).
+ MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
+
+ // If we're converting from __half, convert the range to float to match
+ // the type of src.
+ if (OrigSrcType->isHalfType()) {
+ const llvm::fltSemantics &Sema =
+ CGF.getContext().getFloatTypeSemantics(SrcType);
+ bool IsInexact;
+ MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ }
+
+ llvm::Value *GE =
+ Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
+ llvm::Value *LE =
+ Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
+ Check = Builder.CreateAnd(GE, LE);
} else {
+ // FIXME: Maybe split this sanitizer out from float-cast-overflow.
+ //
+ // Floating-point to floating-point. This has undefined behavior if the
+ // source is not in the range of representable values of the destination
+ // type. The C and C++ standards are spectacularly unclear here. We
+ // diagnose finite out-of-range conversions, but allow infinities and NaNs
+ // to convert to the corresponding value in the smaller type.
+ //
+ // C11 Annex F gives all such conversions defined behavior for IEC 60559
+ // conforming implementations. Unfortunately, LLVM's fptrunc instruction
+ // does not.
+
+ // Converting from a lower rank to a higher rank can never have
+ // undefined behavior, since higher-rank types must have a superset
+ // of values of lower-rank types.
+ if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1)
+ return;
+
+ assert(!OrigSrcType->isHalfType() &&
+ "should not check conversion from __half, it has the lowest rank");
+
const llvm::fltSemantics &DstSema =
CGF.getContext().getFloatTypeSemantics(DstType);
- bool IsInexact;
-
- MinSrc = APFloat::getLargest(DstSema, true);
- if (MinSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
- APFloat::opOverflow)
- MinSrc = APFloat::getLargest(SrcSema, true);
+ APFloat MinBad = APFloat::getLargest(DstSema, false);
+ APFloat MaxBad = APFloat::getInf(DstSema, false);
- MaxSrc = APFloat::getLargest(DstSema, false);
- if (MaxSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
- APFloat::opOverflow)
- MaxSrc = APFloat::getLargest(SrcSema, false);
- }
-
- // If we're converting from __half, convert the range to float to match
- // the type of src.
- if (OrigSrcType->isHalfType()) {
- const llvm::fltSemantics &Sema =
- CGF.getContext().getFloatTypeSemantics(SrcType);
bool IsInexact;
- MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
- MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
+ MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
+
+ Value *AbsSrc = CGF.EmitNounwindRuntimeCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src);
+ llvm::Value *GE =
+ Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad));
+ llvm::Value *LE =
+ Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad));
+ Check = Builder.CreateNot(Builder.CreateAnd(GE, LE));
}
-
- llvm::Value *GE =
- Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc));
- llvm::Value *LE =
- Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
- Check = Builder.CreateAnd(GE, LE);
}
// FIXME: Provide a SourceLocation.
@@ -641,7 +677,8 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
CGF.EmitCheckTypeDescriptor(OrigSrcType),
CGF.EmitCheckTypeDescriptor(DstType)
};
- CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc);
+ CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc,
+ CodeGenFunction::CRK_Recoverable);
}
/// EmitScalarConversion - Emit a conversion from the specified type to the
@@ -658,9 +695,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
QualType OrigSrcType = SrcType;
llvm::Type *SrcTy = Src->getType();
- // Floating casts might be a bit special: if we're doing casts to / from half
- // FP, we should go via special intrinsics.
- if (SrcType->isHalfType()) {
+ // 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);
SrcType = CGF.getContext().FloatTy;
SrcTy = CGF.FloatTy;
@@ -707,17 +743,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
QualType EltTy = DstType->getAs<ExtVectorType>()->getElementType();
llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy);
- // Insert the element in element zero of an undef vector
- llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = Builder.getInt32(0);
- UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
-
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- llvm::Constant *Mask = llvm::ConstantVector::getSplat(NumElements,
- Builder.getInt32(0));
- llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
- return Yay;
+ return Builder.CreateVectorSplat(NumElements, Elt, "splat");
}
// Allow bitcast from vector to integer/fp of the same size.
@@ -731,12 +759,13 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// An overflowing conversion has undefined behavior if either the source type
// or the destination type is a floating-point type.
- if (CGF.getLangOpts().SanitizeFloatCastOverflow &&
+ if (CGF.SanOpts->FloatCastOverflow &&
(OrigSrcType->isFloatingType() || DstType->isFloatingType()))
- EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy);
+ EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType,
+ DstTy);
// Cast to half via float
- if (DstType->isHalfType())
+ if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
DstTy = CGF.FloatTy;
if (isa<llvm::IntegerType>(SrcTy)) {
@@ -777,7 +806,7 @@ Value *ScalarExprEmitter::
EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
QualType SrcTy, QualType DstTy) {
// Get the source element type.
- SrcTy = SrcTy->getAs<ComplexType>()->getElementType();
+ SrcTy = SrcTy->castAs<ComplexType>()->getElementType();
// Handle conversions to bool first, they are special: comparisons against 0.
if (DstTy->isBooleanType()) {
@@ -795,10 +824,7 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
}
Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
- if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
- return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
-
- return llvm::Constant::getNullValue(ConvertType(Ty));
+ return CGF.EmitFromMemory(CGF.CGM.EmitNullConstant(Ty), Ty);
}
/// \brief Emit a sanitization check for the given "binary" operation (which
@@ -806,8 +832,8 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
/// operation). The check passes if \p Check, which is an \c i1, is \c true.
void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
StringRef CheckName;
- llvm::SmallVector<llvm::Constant *, 4> StaticData;
- llvm::SmallVector<llvm::Value *, 2> DynamicData;
+ SmallVector<llvm::Constant *, 4> StaticData;
+ SmallVector<llvm::Value *, 2> DynamicData;
BinaryOperatorKind Opcode = Info.Opcode;
if (BinaryOperator::isCompoundAssignmentOp(Opcode))
@@ -831,7 +857,7 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
} else if (Opcode == BO_Div || Opcode == BO_Rem) {
// Divide or modulo by zero, or signed overflow (eg INT_MAX / -1).
CheckName = "divrem_overflow";
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
} else {
// Signed arithmetic overflow (+, -, *).
switch (Opcode) {
@@ -840,13 +866,14 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
case BO_Mul: CheckName = "mul_overflow"; break;
default: llvm_unreachable("unexpected opcode for bin op check");
}
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
}
DynamicData.push_back(Info.LHS);
DynamicData.push_back(Info.RHS);
}
- CGF.EmitCheck(Check, CheckName, StaticData, DynamicData);
+ CGF.EmitCheck(Check, CheckName, StaticData, DynamicData,
+ CodeGenFunction::CRK_Recoverable);
}
//===----------------------------------------------------------------------===//
@@ -990,7 +1017,12 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
// integer value.
Value *Base = Visit(E->getBase());
Value *Idx = Visit(E->getIdx());
- bool IdxSigned = E->getIdx()->getType()->isSignedIntegerOrEnumerationType();
+ QualType IdxTy = E->getIdx()->getType();
+
+ if (CGF.SanOpts->Bounds)
+ 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");
}
@@ -1224,7 +1256,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
- return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ llvm::Value *V = Visit(E);
+
+ // 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)
+ CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
+ V, DestTy->getPointeeType());
+
+ return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE));
}
@@ -1352,17 +1392,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Elt = EmitScalarConversion(Elt, E->getType(),
DestTy->getAs<VectorType>()->getElementType());
- // Insert the element in element zero of an undef vector
- llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = Builder.getInt32(0);
- UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
-
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- llvm::Constant *Zero = Builder.getInt32(0);
- llvm::Constant *Mask = llvm::ConstantVector::getSplat(NumElements, Zero);
- llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
- return Yay;
+ return Builder.CreateVectorSplat(NumElements, Elt, "splat");;
}
case CK_IntegralCast:
@@ -1394,6 +1426,11 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return EmitComplexToScalarConversion(V, E->getType(), DestTy);
}
+ case CK_ZeroToOCLEvent: {
+ assert(DestTy->isEventT() && "CK_ZeroToOCLEvent cast on non event type");
+ return llvm::Constant::getNullValue(ConvertType(DestTy));
+ }
+
}
llvm_unreachable("unknown scalar cast");
@@ -1417,7 +1454,7 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -1438,21 +1475,60 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
QualType type = E->getSubExpr()->getType();
- llvm::Value *value = EmitLoadOfLValue(LV);
- llvm::Value *input = value;
llvm::PHINode *atomicPHI = 0;
+ llvm::Value *value;
+ llvm::Value *input;
int amount = (isInc ? 1 : -1);
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
+ type = atomicTy->getValueType();
+ if (isInc && type->isBooleanType()) {
+ llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type);
+ if (isPre) {
+ Builder.Insert(new llvm::StoreInst(True,
+ LV.getAddress(), LV.isVolatileQualified(),
+ LV.getAlignment().getQuantity(),
+ llvm::SequentiallyConsistent));
+ return Builder.getTrue();
+ }
+ // For atomic bool increment, we just store true and return it for
+ // preincrement, do an atomic swap with true for postincrement
+ return Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ LV.getAddress(), True, llvm::SequentiallyConsistent);
+ }
+ // Special case for atomic increment / decrement on integers, emit
+ // atomicrmw instructions. We skip this if we want to be doing overflow
+ // checking, and fall into the slow path with the atomic cmpxchg loop.
+ if (!type->isBooleanType() && type->isIntegerType() &&
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ llvm::AtomicRMWInst::BinOp aop = isInc ? llvm::AtomicRMWInst::Add :
+ llvm::AtomicRMWInst::Sub;
+ llvm::Instruction::BinaryOps op = isInc ? llvm::Instruction::Add :
+ llvm::Instruction::Sub;
+ llvm::Value *amt = CGF.EmitToMemory(
+ llvm::ConstantInt::get(ConvertType(type), 1, true), type);
+ llvm::Value *old = Builder.CreateAtomicRMW(aop,
+ LV.getAddress(), amt, llvm::SequentiallyConsistent);
+ return isPre ? Builder.CreateBinOp(op, old, amt) : old;
+ }
+ value = EmitLoadOfLValue(LV);
+ input = value;
+ // For every other atomic operation, we need to emit a load-op-cmpxchg loop
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ value = CGF.EmitToMemory(value, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(value->getType(), 2);
atomicPHI->addIncoming(value, startBB);
- type = atomicTy->getValueType();
value = atomicPHI;
+ } else {
+ value = EmitLoadOfLValue(LV);
+ input = value;
}
// Special case of integer increment that we have to check first: bool++.
@@ -1472,11 +1548,22 @@ 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 (type->isSignedIntegerOrEnumerationType() &&
- value->getType()->getPrimitiveSizeInBits() >=
- CGF.IntTy->getBitWidth())
+ if (value->getType()->getPrimitiveSizeInBits() >=
+ CGF.IntTy->getBitWidth() &&
+ type->isSignedIntegerOrEnumerationType()) {
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
- else
+ } else if (value->getType()->getPrimitiveSizeInBits() >=
+ CGF.IntTy->getBitWidth() && type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) {
+ BinOpInfo BinOp;
+ BinOp.LHS = value;
+ BinOp.RHS = llvm::ConstantInt::get(value->getType(), 1, false);
+ BinOp.Ty = E->getType();
+ BinOp.Opcode = isInc ? BO_Add : BO_Sub;
+ BinOp.FPContractable = false;
+ BinOp.E = E;
+ value = EmitOverflowCheckedBinOp(BinOp);
+ } else
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
// Next most common: pointer increment.
@@ -1531,7 +1618,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Add the inc/dec to the real part.
llvm::Value *amt;
- if (type->isHalfType()) {
+ 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),
@@ -1553,7 +1640,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
- if (type->isHalfType())
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
value =
Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16),
value);
@@ -1579,7 +1666,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
llvm::Value *old = Builder.CreateAtomicCmpXchg(LV.getAddress(), atomicPHI,
- value, llvm::SequentiallyConsistent);
+ CGF.EmitToMemory(value, type), llvm::SequentiallyConsistent);
atomicPHI->addIncoming(old, opBB);
llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
@@ -1624,12 +1711,15 @@ Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
}
Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
-
// Perform vector logical not on comparison with zero vector.
if (E->getType()->isExtVectorType()) {
Value *Oper = Visit(E->getSubExpr());
Value *Zero = llvm::Constant::getNullValue(Oper->getType());
- Value *Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
+ Value *Result;
+ if (Oper->getType()->isFPOrFPVectorTy())
+ Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp");
+ else
+ Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
}
@@ -1852,20 +1942,63 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.E = E;
// Load/convert the LHS.
LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- OpInfo.LHS = EmitLoadOfLValue(LHSLV);
llvm::PHINode *atomicPHI = 0;
- if (LHSTy->isAtomicType()) {
+ if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
+ QualType type = atomicTy->getValueType();
+ if (!type->isBooleanType() && type->isIntegerType() &&
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP;
+ switch (OpInfo.Opcode) {
+ // We don't have atomicrmw operands for *, %, /, <<, >>
+ case BO_MulAssign: case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ break;
+ case BO_AddAssign:
+ aop = llvm::AtomicRMWInst::Add;
+ break;
+ case BO_SubAssign:
+ aop = llvm::AtomicRMWInst::Sub;
+ break;
+ case BO_AndAssign:
+ aop = llvm::AtomicRMWInst::And;
+ break;
+ case BO_XorAssign:
+ aop = llvm::AtomicRMWInst::Xor;
+ break;
+ case BO_OrAssign:
+ aop = llvm::AtomicRMWInst::Or;
+ break;
+ default:
+ llvm_unreachable("Invalid compound assignment type");
+ }
+ if (aop != llvm::AtomicRMWInst::BAD_BINOP) {
+ llvm::Value *amt = CGF.EmitToMemory(EmitScalarConversion(OpInfo.RHS,
+ E->getRHS()->getType(), LHSTy), LHSTy);
+ Builder.CreateAtomicRMW(aop, LHSLV.getAddress(), amt,
+ llvm::SequentiallyConsistent);
+ return LHSLV;
+ }
+ }
// FIXME: For floating point types, we should be saving and restoring the
// floating point environment in the loop.
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
+ OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2);
atomicPHI->addIncoming(OpInfo.LHS, startBB);
OpInfo.LHS = atomicPHI;
}
+ else
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
@@ -1880,7 +2013,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
llvm::Value *old = Builder.CreateAtomicCmpXchg(LHSLV.getAddress(), atomicPHI,
- Result, llvm::SequentiallyConsistent);
+ CGF.EmitToMemory(Result, LHSTy), llvm::SequentiallyConsistent);
atomicPHI->addIncoming(old, opBB);
llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
@@ -1926,10 +2059,10 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
llvm::Value *Cond = 0;
- if (CGF.getLangOpts().SanitizeDivideByZero)
+ if (CGF.SanOpts->IntegerDivideByZero)
Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
- if (CGF.getLangOpts().SanitizeSignedIntegerOverflow &&
+ if (CGF.SanOpts->SignedIntegerOverflow &&
Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
@@ -1948,16 +2081,17 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if (CGF.getLangOpts().SanitizeDivideByZero ||
- CGF.getLangOpts().SanitizeSignedIntegerOverflow) {
+ if ((CGF.SanOpts->IntegerDivideByZero ||
+ CGF.SanOpts->SignedIntegerOverflow) &&
+ Ops.Ty->isIntegerType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
-
- if (Ops.Ty->isIntegerType())
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- else if (CGF.getLangOpts().SanitizeDivideByZero &&
- Ops.Ty->isRealFloatingType())
- EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ 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()) {
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
if (CGF.getLangOpts().OpenCL) {
@@ -1978,10 +2112,10 @@ 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.getLangOpts().SanitizeDivideByZero) {
+ if (CGF.SanOpts->IntegerDivideByZero) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- if (Ops.Ty->isIntegerType())
+ if (Ops.Ty->isIntegerType())
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
}
@@ -1995,27 +2129,32 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
unsigned IID;
unsigned OpID = 0;
+ bool isSigned = Ops.Ty->isSignedIntegerOrEnumerationType();
switch (Ops.Opcode) {
case BO_Add:
case BO_AddAssign:
OpID = 1;
- IID = llvm::Intrinsic::sadd_with_overflow;
+ IID = isSigned ? llvm::Intrinsic::sadd_with_overflow :
+ llvm::Intrinsic::uadd_with_overflow;
break;
case BO_Sub:
case BO_SubAssign:
OpID = 2;
- IID = llvm::Intrinsic::ssub_with_overflow;
+ IID = isSigned ? llvm::Intrinsic::ssub_with_overflow :
+ llvm::Intrinsic::usub_with_overflow;
break;
case BO_Mul:
case BO_MulAssign:
OpID = 3;
- IID = llvm::Intrinsic::smul_with_overflow;
+ IID = isSigned ? llvm::Intrinsic::smul_with_overflow :
+ llvm::Intrinsic::umul_with_overflow;
break;
default:
llvm_unreachable("Unsupported operation for overflow detection");
}
OpID <<= 1;
- OpID |= 1;
+ if (isSigned)
+ OpID |= 1;
llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
@@ -2031,10 +2170,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 (CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!isSigned || CGF.SanOpts->SignedIntegerOverflow)
EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
else
- CGF.EmitTrapvCheck(Builder.CreateNot(overflow));
+ CGF.EmitTrapCheck(Builder.CreateNot(overflow));
return result;
}
@@ -2065,9 +2204,14 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Call the handler with the two arguments, the operation, and the size of
// the result.
- llvm::Value *handlerResult = Builder.CreateCall4(handler, lhs, rhs,
- Builder.getInt8(OpID),
- Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth()));
+ llvm::Value *handlerArgs[] = {
+ lhs,
+ rhs,
+ Builder.getInt8(OpID),
+ Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth())
+ };
+ llvm::Value *handlerResult =
+ CGF.EmitNounwindRuntimeCall(handler, handlerArgs);
// Truncate the result back to the desired size.
handlerResult = Builder.CreateTrunc(handlerResult, opTy);
@@ -2113,6 +2257,10 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
if (isSubtraction)
index = CGF.Builder.CreateNeg(index, "idx.neg");
+ if (CGF.SanOpts->Bounds)
+ CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
+ /*Accessed*/ false);
+
const PointerType *pointerType
= pointerOperand->getType()->getAs<PointerType>();
if (!pointerType) {
@@ -2217,7 +2365,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
// Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
// either disabled, or handled entirely by the LLVM backend).
- if (CGF.getLangOpts().getFPContractMode() != LangOptions::FPC_On)
+ if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On)
return 0;
// We have a potentially fusable op. Look for a mul on one of the operands.
@@ -2249,14 +2397,17 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
// Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
-
+
+ if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ return EmitOverflowCheckedBinOp(op);
+
if (op.LHS->getType()->isFPOrFPVectorTy()) {
// Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
@@ -2276,14 +2427,17 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
// Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
-
+
+ if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ return EmitOverflowCheckedBinOp(op);
+
if (op.LHS->getType()->isFPOrFPVectorTy()) {
// Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
@@ -2352,6 +2506,15 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div");
}
+Value *ScalarExprEmitter::GetWidthMinusOneValue(Value* LHS,Value* RHS) {
+ llvm::IntegerType *Ty;
+ if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(LHS->getType()))
+ Ty = cast<llvm::IntegerType>(VT->getElementType());
+ else
+ Ty = cast<llvm::IntegerType>(LHS->getType());
+ return llvm::ConstantInt::get(RHS->getType(), Ty->getBitWidth() - 1);
+}
+
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
// LLVM requires the LHS and RHS to be the same type: promote or truncate the
// RHS to the same size as the LHS.
@@ -2359,18 +2522,20 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.getLangOpts().SanitizeShift &&
+ if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
- unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::Value *WidthMinusOne =
- llvm::ConstantInt::get(RHS->getType(), Width - 1);
- // FIXME: Emit the branching explicitly rather than emitting the check
- // twice.
- EmitBinOpCheck(Builder.CreateICmpULE(RHS, WidthMinusOne), Ops);
+ llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
+ llvm::Value *Valid = Builder.CreateICmpULE(RHS, WidthMinusOne);
if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ llvm::BasicBlock *Orig = Builder.GetInsertBlock();
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
+ llvm::BasicBlock *CheckBitsShifted = CGF.createBasicBlock("check");
+ Builder.CreateCondBr(Valid, CheckBitsShifted, Cont);
+
// Check whether we are shifting any non-zero bits off the top of the
// integer.
+ CGF.EmitBlock(CheckBitsShifted);
llvm::Value *BitsShiftedOff =
Builder.CreateLShr(Ops.LHS,
Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
@@ -2385,9 +2550,19 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
}
llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
- EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops);
+ llvm::Value *SecondCheck = Builder.CreateICmpEQ(BitsShiftedOff, Zero);
+ CGF.EmitBlock(Cont);
+ llvm::PHINode *P = Builder.CreatePHI(Valid->getType(), 2);
+ P->addIncoming(Valid, Orig);
+ P->addIncoming(SecondCheck, CheckBitsShifted);
+ Valid = P;
}
+
+ EmitBinOpCheck(Valid, Ops);
}
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask");
return Builder.CreateShl(Ops.LHS, RHS, "shl");
}
@@ -2399,12 +2574,13 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.getLangOpts().SanitizeShift &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
- unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width);
- EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops);
- }
+ if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
+ isa<llvm::IntegerType>(Ops.LHS->getType()))
+ EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask");
if (Ops.Ty->hasUnsignedIntegerRepresentation())
return Builder.CreateLShr(Ops.LHS, RHS, "shr");
@@ -2633,16 +2809,20 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
-
// Perform vector logical and on comparisons with zero vectors.
if (E->getType()->isVectorType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
- LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
- RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ if (LHS->getType()->isFPOrFPVectorTy()) {
+ LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
+ RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
+ } else {
+ LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
+ RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ }
Value *And = Builder.CreateAnd(LHS, RHS);
- return Builder.CreateSExt(And, Zero->getType(), "sext");
+ return Builder.CreateSExt(And, ConvertType(E->getType()), "sext");
}
llvm::Type *ResTy = ConvertType(E->getType());
@@ -2700,16 +2880,20 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
-
// Perform vector logical or on comparisons with zero vectors.
if (E->getType()->isVectorType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
- LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
- RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ if (LHS->getType()->isFPOrFPVectorTy()) {
+ LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
+ RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
+ } else {
+ LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
+ RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ }
Value *Or = Builder.CreateOr(LHS, RHS);
- return Builder.CreateSExt(Or, Zero->getType(), "sext");
+ return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext");
}
llvm::Type *ResTy = ConvertType(E->getType());
@@ -3007,7 +3191,7 @@ Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
/// EmitScalarExpr - Emit the computation of the specified expression of scalar
/// type, ignoring the result.
Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
- assert(E && !hasAggregateLLVMType(E->getType()) &&
+ assert(E && hasScalarEvaluationKind(E->getType()) &&
"Invalid scalar expression to emit");
if (isa<CXXDefaultArgExpr>(E))
@@ -3023,7 +3207,7 @@ Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
/// specified destination type, both of which are LLVM scalar types.
Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
QualType DstTy) {
- assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) &&
+ assert(hasScalarEvaluationKind(SrcTy) && hasScalarEvaluationKind(DstTy) &&
"Invalid scalar expression to emit");
return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy);
}
@@ -3034,7 +3218,7 @@ Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
QualType SrcTy,
QualType DstTy) {
- assert(SrcTy->isAnyComplexType() && !hasAggregateLLVMType(DstTy) &&
+ assert(SrcTy->isAnyComplexType() && hasScalarEvaluationKind(DstTy) &&
"Invalid complex -> scalar conversion");
return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy,
DstTy);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index c90e4eca8476..79d97b99b40e 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -21,8 +21,8 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/DataLayout.h"
-#include "llvm/InlineAsm.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
using namespace clang;
using namespace CodeGen;
@@ -70,7 +70,7 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
// messaged (avoids pulling it out of the result type).
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
- llvm::Value *Receiver = Runtime.GetClass(Builder, ClassDecl);
+ llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
const ParmVarDecl *argDecl = *BoxingMethod->param_begin();
QualType ArgQT = argDecl->getType().getUnqualifiedType();
@@ -109,32 +109,50 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
if (DLE)
Keys = CreateMemTemp(ElementArrayType, "keys");
+ // In ARC, we may need to do extra work to keep all the keys and
+ // values alive until after the call.
+ SmallVector<llvm::Value *, 16> NeededObjects;
+ bool TrackNeededObjects =
+ (getLangOpts().ObjCAutoRefCount &&
+ CGM.getCodeGenOpts().OptimizationLevel != 0);
+
// Perform the actual initialialization of the array(s).
for (uint64_t i = 0; i < NumElements; i++) {
if (ALE) {
- // Emit the initializer.
+ // Emit the element and store it to the appropriate array slot.
const Expr *Rhs = ALE->getElement(i);
LValue LV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
ElementType,
Context.getTypeAlignInChars(Rhs->getType()),
Context);
- EmitScalarInit(Rhs, /*D=*/0, LV, /*capturedByInit=*/false);
+
+ llvm::Value *value = EmitScalarExpr(Rhs);
+ EmitStoreThroughLValue(RValue::get(value), LV, true);
+ if (TrackNeededObjects) {
+ NeededObjects.push_back(value);
+ }
} else {
- // Emit the key initializer.
+ // Emit the key and store it to the appropriate array slot.
const Expr *Key = DLE->getKeyValueElement(i).Key;
LValue KeyLV = LValue::MakeAddr(Builder.CreateStructGEP(Keys, i),
ElementType,
Context.getTypeAlignInChars(Key->getType()),
Context);
- EmitScalarInit(Key, /*D=*/0, KeyLV, /*capturedByInit=*/false);
+ llvm::Value *keyValue = EmitScalarExpr(Key);
+ EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
- // Emit the value initializer.
+ // Emit the value and store it to the appropriate array slot.
const Expr *Value = DLE->getKeyValueElement(i).Value;
LValue ValueLV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
ElementType,
Context.getTypeAlignInChars(Value->getType()),
Context);
- EmitScalarInit(Value, /*D=*/0, ValueLV, /*capturedByInit=*/false);
+ llvm::Value *valueValue = EmitScalarExpr(Value);
+ EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
+ if (TrackNeededObjects) {
+ NeededObjects.push_back(keyValue);
+ NeededObjects.push_back(valueValue);
+ }
}
}
@@ -163,7 +181,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
ObjCInterfaceDecl *Class
= InterfacePointerType->getObjectType()->getInterface();
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.GetClass(Builder, Class);
+ llvm::Value *Receiver = Runtime.GetClass(*this, Class);
// Generate the message send.
RValue result
@@ -172,6 +190,15 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
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.
+ // Therefore we must prevent the optimizer from releasing them until
+ // after the call.
+ if (TrackNeededObjects) {
+ EmitARCIntrinsicUse(NeededObjects);
+ }
+
return Builder.CreateBitCast(result.getScalarVal(),
ConvertType(E->getType()));
}
@@ -191,12 +218,12 @@ llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
// Note that this implementation allows for non-constant strings to be passed
// as arguments to @selector(). Currently, the only thing preventing this
// behaviour is the type checking in the front end.
- return CGM.getObjCRuntime().GetSelector(Builder, E->getSelector());
+ return CGM.getObjCRuntime().GetSelector(*this, E->getSelector());
}
llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
// FIXME: This should pass the Decl not the name.
- return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
+ return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
}
/// \brief Adjust the type of the result of an Objective-C message send
@@ -310,7 +337,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
assert(ObjTy && "Invalid Objective-C class message send");
OID = ObjTy->getInterface();
assert(OID && "Invalid Objective-C class message send");
- Receiver = Runtime.GetClass(Builder, OID);
+ Receiver = Runtime.GetClass(*this, OID);
isClassMessage = true;
break;
}
@@ -772,7 +799,7 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::Value *copyCppAtomicObjectFn =
- CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
+ CGF.CGM.getObjCRuntime().GetCppAtomicObjectGetFunction();
CGF.EmitCall(CGF.getTypes().arrangeFreeFunctionCall(CGF.getContext().VoidTy,
args,
FunctionType::ExtInfo(),
@@ -895,16 +922,21 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
QualType ivarType = ivar->getType();
- if (ivarType->isAnyComplexType()) {
- ComplexPairTy pair = LoadComplexFromAddr(LV.getAddress(),
- LV.isVolatileQualified());
- StoreComplexToAddr(pair, ReturnValue, LV.isVolatileQualified());
- } else if (hasAggregateLLVMType(ivarType)) {
+ switch (getEvaluationKind(ivarType)) {
+ case TEK_Complex: {
+ ComplexPairTy pair = EmitLoadOfComplex(LV);
+ EmitStoreOfComplex(pair,
+ MakeNaturalAlignAddrLValue(ReturnValue, ivarType),
+ /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
// The return value slot is guaranteed to not be aliased, but
// that's not necessarily the same as "on the stack", so
// we still potentially need objc_memmove_collectable.
EmitAggregateCopy(ReturnValue, LV.getAddress(), ivarType);
- } else {
+ return;
+ case TEK_Scalar: {
llvm::Value *value;
if (propType->isReferenceType()) {
value = LV.getAddress();
@@ -926,8 +958,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
}
EmitReturnOfRValue(RValue::get(value), propType);
+ return;
}
- return;
+ }
+ llvm_unreachable("bad evaluation kind");
}
}
@@ -1007,7 +1041,7 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::Value *copyCppAtomicObjectFn =
- CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
+ CGF.CGM.getObjCRuntime().GetCppAtomicObjectSetFunction();
CGF.EmitCall(CGF.getTypes().arrangeFreeFunctionCall(CGF.getContext().VoidTy,
args,
FunctionType::ExtInfo(),
@@ -1182,7 +1216,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
selfDecl->getType(), CK_LValueToRValue, &self,
VK_RValue);
ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(),
- SourceLocation(), &selfLoad, true, true);
+ SourceLocation(), SourceLocation(),
+ &selfLoad, true, true);
ParmVarDecl *argDecl = *setterMethod->param_begin();
QualType argType = argDecl->getType().getNonReferenceType();
@@ -1679,7 +1714,8 @@ namespace {
llvm::Value *object;
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitARCRelease(object, /*precise*/ true);
+ // Releases at the end of the full-expression are imprecise.
+ CGF.EmitARCRelease(object, ARCImpreciseLifetime);
}
};
}
@@ -1699,21 +1735,38 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
return EmitARCRetainAutorelease(type, value);
}
+/// Given a number of pointers, inform the optimizer that they're
+/// being intrinsically used up until this point in the program.
+void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
+ llvm::Constant *&fn = CGM.getARCEntrypoints().clang_arc_use;
+ if (!fn) {
+ llvm::FunctionType *fnType =
+ llvm::FunctionType::get(CGM.VoidTy, ArrayRef<llvm::Type*>(), true);
+ fn = CGM.CreateRuntimeFunction(fnType, "clang.arc.use");
+ }
+
+ // This isn't really a "runtime" function, but as an intrinsic it
+ // doesn't really matter as long as we align things up.
+ EmitNounwindRuntimeCall(fn, values);
+}
+
static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
llvm::FunctionType *type,
StringRef fnName) {
llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
- // If the target runtime doesn't naturally support ARC, emit weak
- // references to the runtime support library. We don't really
- // permit this to fail, but we need a particular relocation style.
if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) {
- if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC())
+ // If the target runtime doesn't naturally support ARC, emit weak
+ // references to the runtime support library. We don't really
+ // permit this to fail, but we need a particular relocation style.
+ if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC()) {
f->setLinkage(llvm::Function::ExternalWeakLinkage);
- // set nonlazybind attribute for these APIs for performance.
- if (fnName == "objc_retain" || fnName == "objc_release")
- f->addFnAttr(llvm::Attributes::NonLazyBind);
+ } else if (fnName == "objc_retain" || fnName == "objc_release") {
+ // If we have Native ARC, set nonlazybind attribute for these APIs for
+ // performance.
+ f->addFnAttr(llvm::Attribute::NonLazyBind);
+ }
}
return fn;
@@ -1725,13 +1778,13 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
llvm::Constant *&fn,
- StringRef fnName) {
+ StringRef fnName,
+ bool isTailCall = false) {
if (isa<llvm::ConstantPointerNull>(value)) return value;
if (!fn) {
- std::vector<llvm::Type*> args(1, CGF.Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1740,8 +1793,9 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
- llvm::CallInst *call = CGF.Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
+ if (isTailCall)
+ call->setTailCall();
// Cast the result back to the original type.
return CGF.Builder.CreateBitCast(call, origType);
@@ -1754,9 +1808,8 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
llvm::Constant *&fn,
StringRef fnName) {
if (!fn) {
- std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrPtrTy, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1765,11 +1818,9 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
// Call the function.
- llvm::CallInst *call = CGF.Builder.CreateCall(fn, addr);
- call->setDoesNotThrow();
+ llvm::Value *result = CGF.EmitNounwindRuntimeCall(fn, addr);
// Cast the result back to a dereference of the original type.
- llvm::Value *result = call;
if (origType != CGF.Int8PtrPtrTy)
result = CGF.Builder.CreateBitCast(result,
cast<llvm::PointerType>(origType)->getElementType());
@@ -1798,11 +1849,11 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
llvm::Type *origType = value->getType();
- addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
- value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
-
- llvm::CallInst *result = CGF.Builder.CreateCall2(fn, addr, value);
- result->setDoesNotThrow();
+ llvm::Value *args[] = {
+ CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy),
+ CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)
+ };
+ llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
if (ignored) return 0;
@@ -1819,17 +1870,18 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
assert(dst->getType() == src->getType());
if (!fn) {
- std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
+ llvm::Type *argTypes[] = { CGF.Int8PtrPtrTy, CGF.Int8PtrPtrTy };
+
llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
- dst = CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy);
- src = CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy);
-
- llvm::CallInst *result = CGF.Builder.CreateCall2(fn, dst, src);
- result->setDoesNotThrow();
+ llvm::Value *args[] = {
+ CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy),
+ CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy)
+ };
+ CGF.EmitNounwindRuntimeCall(fn, args);
}
/// Produce the code to do a retain. Based on the type, calls one of:
@@ -1932,14 +1984,14 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
/// Release the given object.
/// call void \@objc_release(i8* %value)
-void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
+void CodeGenFunction::EmitARCRelease(llvm::Value *value,
+ ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
}
@@ -1947,10 +1999,9 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
value = Builder.CreateBitCast(value, Int8PtrTy);
// Call objc_release.
- llvm::CallInst *call = Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
- if (!precise) {
+ if (precise == ARCImpreciseLifetime) {
SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), args));
@@ -1966,7 +2017,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
/// At -O1 and above, just load and call objc_release.
///
/// call void \@objc_storeStrong(i8** %addr, i8* null)
-void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) {
+void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr,
+ ARCPreciseLifetime_t precise) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType());
llvm::Value *null = llvm::ConstantPointerNull::get(
@@ -1995,10 +2047,11 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
}
- addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
- llvm::Value *castValue = Builder.CreateBitCast(value, Int8PtrTy);
-
- Builder.CreateCall2(fn, addr, castValue)->setDoesNotThrow();
+ llvm::Value *args[] = {
+ Builder.CreateBitCast(addr, Int8PtrPtrTy),
+ Builder.CreateBitCast(value, Int8PtrTy)
+ };
+ EmitNounwindRuntimeCall(fn, args);
if (ignored) return 0;
return value;
@@ -2035,7 +2088,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
EmitStoreOfScalar(newValue, dst);
// Finally, release the old value.
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, dst.isARCPreciseLifetime());
return newValue;
}
@@ -2054,7 +2107,8 @@ llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value,
CGM.getARCEntrypoints().objc_autoreleaseReturnValue,
- "objc_autoreleaseReturnValue");
+ "objc_autoreleaseReturnValue",
+ /*isTailCall*/ true);
}
/// Do a fused retain/autorelease of the given object.
@@ -2063,7 +2117,8 @@ llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value,
CGM.getARCEntrypoints().objc_retainAutoreleaseReturnValue,
- "objc_retainAutoreleaseReturnValue");
+ "objc_retainAutoreleaseReturnValue",
+ /*isTailCall*/ true);
}
/// Do a fused retain/autorelease of the given object.
@@ -2144,17 +2199,15 @@ void CodeGenFunction::EmitARCInitWeak(llvm::Value *addr, llvm::Value *value) {
void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrPtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrPtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
}
// Cast the argument to 'id*'.
addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
- llvm::CallInst *call = Builder.CreateCall(fn, addr);
- call->setDoesNotThrow();
+ EmitNounwindRuntimeCall(fn, addr);
}
/// void \@objc_moveWeak(i8** %dest, i8** %src)
@@ -2185,10 +2238,7 @@ llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
}
- llvm::CallInst *call = Builder.CreateCall(fn);
- call->setDoesNotThrow();
-
- return call;
+ return EmitNounwindRuntimeCall(fn);
}
/// Produce the code to do a primitive release.
@@ -2198,17 +2248,15 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
// We don't want to use a weak import here; instead we should not
// fall into this path.
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop");
}
- llvm::CallInst *call = Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ EmitNounwindRuntimeCall(fn, value);
}
/// Produce the code to do an MRR version objc_autoreleasepool_push.
@@ -2218,7 +2266,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
///
llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(Builder);
+ llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this);
// [NSAutoreleasePool alloc]
IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
Selector AllocSel = getContext().Selectors.getSelector(0, &II);
@@ -2252,13 +2300,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- CGF.EmitARCDestroyStrong(addr, /*precise*/ true);
+ CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime);
}
void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- CGF.EmitARCDestroyStrong(addr, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime);
}
void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
@@ -2440,7 +2488,7 @@ static bool shouldEmitSeparateBlockRetain(const Expr *e) {
/// This massively duplicates emitPseudoObjectRValue.
static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
const PseudoObjectExpr *E) {
- llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+ SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
// Find the result expression.
const Expr *resultExpr = E->getResultExpr();
@@ -2490,12 +2538,10 @@ static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
- // Look through cleanups.
- if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
- CGF.enterFullExpression(cleanups);
- CodeGenFunction::RunCleanupsScope scope(CGF);
- return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr());
- }
+ // We should *never* see a nested full-expression here, because if
+ // we fail to emit at +1, our caller must not retain after we close
+ // out the full-expression.
+ assert(!isa<ExprWithCleanups>(e));
// The desired result type, if it differs from the type of the
// ultimate opaque expression.
@@ -2647,6 +2693,13 @@ static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
/// best-effort attempt to peephole expressions that naturally produce
/// retained objects.
llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
+ // The retain needs to happen within the full-expression.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ enterFullExpression(cleanups);
+ RunCleanupsScope scope(*this);
+ return EmitARCRetainScalarExpr(cleanups->getSubExpr());
+ }
+
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
llvm::Value *value = result.getPointer();
if (!result.getInt())
@@ -2656,6 +2709,13 @@ llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
+ // The retain needs to happen within the full-expression.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ enterFullExpression(cleanups);
+ RunCleanupsScope scope(*this);
+ return EmitARCRetainAutoreleaseScalarExpr(cleanups->getSubExpr());
+ }
+
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
llvm::Value *value = result.getPointer();
if (result.getInt())
@@ -2687,17 +2747,7 @@ llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
// In ARC, retain and autorelease the expression.
if (getLangOpts().ObjCAutoRefCount) {
// Do so before running any cleanups for the full-expression.
- // tryEmitARCRetainScalarExpr does make an effort to do things
- // inside cleanups, but there are crazy cases like
- // @throw A().foo;
- // where a full retain+autorelease is required and would
- // otherwise happen after the destructor for the temporary.
- if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr)) {
- enterFullExpression(ewc);
- expr = ewc->getSubExpr();
- }
-
- CodeGenFunction::RunCleanupsScope cleanups(*this);
+ // EmitARCRetainAutoreleaseScalarExpr does this for us.
return EmitARCRetainAutoreleaseScalarExpr(expr);
}
@@ -2733,7 +2783,7 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
llvm::Value *oldValue =
EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue);
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
} else {
value = EmitARCStoreStrong(lvalue, value, ignored);
}
@@ -2791,12 +2841,7 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
/* side effects */ true);
object = Builder.CreateBitCast(object, VoidPtrTy);
- Builder.CreateCall(extender, object)->setDoesNotThrow();
-}
-
-static bool hasAtomicCopyHelperAPI(const ObjCRuntime &runtime) {
- // For now, only NeXT has these APIs.
- return runtime.isNeXTFamily();
+ EmitNounwindRuntimeCall(extender, object);
}
/// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with
@@ -2806,9 +2851,8 @@ static bool hasAtomicCopyHelperAPI(const ObjCRuntime &runtime) {
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
- // FIXME. This api is for NeXt runtime only for now.
if (!getLangOpts().CPlusPlus ||
- !hasAtomicCopyHelperAPI(getLangOpts().ObjCRuntime))
+ !getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return 0;
QualType Ty = PID->getPropertyIvarDecl()->getType();
if (!Ty->isRecordType())
@@ -2831,7 +2875,6 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false,
false);
@@ -2890,9 +2933,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
- // FIXME. This api is for NeXt runtime only for now.
if (!getLangOpts().CPlusPlus ||
- !hasAtomicCopyHelperAPI(getLangOpts().ObjCRuntime))
+ !getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return 0;
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
QualType Ty = PD->getType();
@@ -2917,7 +2959,6 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false,
false);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 68d234dde6ea..fbf8a1abb013 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -15,26 +15,24 @@
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
-#include "CodeGenModule.h"
-#include "CodeGenFunction.h"
#include "CGCleanup.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
-#include "llvm/LLVMContext.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.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 "llvm/DataLayout.h"
-
#include <cstdarg>
@@ -194,7 +192,7 @@ protected:
/// The element types must match the types of the structure elements in the
/// first argument.
llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty,
- llvm::ArrayRef<llvm::Constant*> V,
+ ArrayRef<llvm::Constant *> V,
StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
@@ -206,7 +204,7 @@ protected:
/// elements that the array type declares, of the type specified as the array
/// element type.
llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty,
- llvm::ArrayRef<llvm::Constant*> V,
+ ArrayRef<llvm::Constant *> V,
StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
@@ -217,7 +215,7 @@ protected:
/// Generates a global array, inferring the array type from the specified
/// element type and the size of the initialiser.
llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty,
- llvm::ArrayRef<llvm::Constant*> V,
+ ArrayRef<llvm::Constant *> V,
StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
@@ -227,7 +225,7 @@ protected:
/// Returns a property name and encoding string.
llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
const Decl *Container) {
- ObjCRuntime R = CGM.getLangOpts().ObjCRuntime;
+ const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
if ((R.getKind() == ObjCRuntime::GNUstep) &&
(R.getVersion() >= VersionTuple(1, 6))) {
std::string NameAndAttributes;
@@ -238,15 +236,44 @@ protected:
NameAndAttributes += TypeStr;
NameAndAttributes += '\0';
NameAndAttributes += PD->getNameAsString();
+ NameAndAttributes += '\0';
return llvm::ConstantExpr::getGetElementPtr(
CGM.GetAddrOfConstantString(NameAndAttributes), Zeros);
}
return MakeConstantString(PD->getNameAsString());
}
+ /// Push the property attributes into two structure fields.
+ void PushPropertyAttributes(std::vector<llvm::Constant*> &Fields,
+ ObjCPropertyDecl *property, bool isSynthesized=true, bool
+ isDynamic=true) {
+ int attrs = property->getPropertyAttributes();
+ // For read-only properties, clear the copy and retain flags
+ if (attrs & ObjCPropertyDecl::OBJC_PR_readonly) {
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_copy;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_retain;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_weak;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_strong;
+ }
+ // The first flags field has the same attribute values as clang uses internally
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff));
+ attrs >>= 8;
+ attrs <<= 2;
+ // For protocol properties, synthesized and dynamic have no meaning, so we
+ // reuse these flags to indicate that this is a protocol property (both set
+ // has no meaning, as a property can't be both synthesized and dynamic)
+ attrs |= isSynthesized ? (1<<0) : 0;
+ attrs |= isDynamic ? (1<<1) : 0;
+ // The second field is the next four fields left shifted by two, with the
+ // low bit set to indicate whether the field is synthesized or dynamic.
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff));
+ // Two padding fields
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ }
/// Ensures that the value has the required type, by inserting a bitcast if
/// required. This function lets us avoid inserting bitcasts that are
/// redundant.
- llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, llvm::Type *Ty){
+ llvm::Value* EnforceType(CGBuilderTy &B, llvm::Value *V, llvm::Type *Ty) {
if (V->getType() == Ty) return V;
return B.CreateBitCast(V, Ty);
}
@@ -385,7 +412,7 @@ private:
/// a class defined in the runtime, declaring no methods, but adopting the
/// protocols. This is a horribly ugly hack, but it allows us to collect all
/// of the protocols without changing the ABI.
- void GenerateProtocolHolderCategory(void);
+ void GenerateProtocolHolderCategory();
/// Generates a class structure.
llvm::Constant *GenerateClassStructure(
llvm::Constant *MetaClass,
@@ -409,7 +436,7 @@ private:
ArrayRef<llvm::Constant *> MethodTypes);
/// Returns a selector with the specified type encoding. An empty string is
/// used to return an untyped selector (with the types field set to NULL).
- llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval);
/// Returns the variable used to store the offset of an instance variable.
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
@@ -419,7 +446,7 @@ private:
protected:
void EmitClassRef(const std::string &className);
/// Emits a pointer to the named class
- virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
const std::string &Name, bool isWeak);
/// Looks up the method for sending a message to the specified object. This
/// mechanism differs between the GCC and GNU runtimes, so this method must be
@@ -472,11 +499,11 @@ public:
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval = false);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method);
virtual llvm::Constant *GetEHType(QualType T);
@@ -485,7 +512,7 @@ public:
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD);
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
@@ -494,8 +521,9 @@ public:
virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
bool copy);
virtual llvm::Constant *GetSetStructFunction();
- virtual llvm::Constant *GetCppAtomicObjectFunction();
virtual llvm::Constant *GetGetStructFunction();
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction();
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGenFunction &CGF,
@@ -503,7 +531,8 @@ public:
virtual void EmitSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
virtual void EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S);
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true);
virtual llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGenFunction &CGF,
@@ -528,7 +557,7 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return NULLPtr;
@@ -537,6 +566,12 @@ public:
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
+
+ virtual llvm::Constant *BuildByrefLayout(CodeGenModule &CGM,
+ QualType T) {
+ return NULLPtr;
+ }
+
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
return 0;
}
@@ -566,7 +601,7 @@ protected:
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
@@ -576,7 +611,7 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
@@ -597,6 +632,20 @@ class CGObjCGNUstep : public CGObjCGNU {
/// arguments. Returns the slot for the corresponding method. Superclass
/// message lookup rarely changes, so this is a good caching opportunity.
LazyRuntimeFunction SlotLookupSuperFn;
+ /// Specialised function for setting atomic retain properties
+ LazyRuntimeFunction SetPropertyAtomic;
+ /// Specialised function for setting atomic copy properties
+ LazyRuntimeFunction SetPropertyAtomicCopy;
+ /// Specialised function for setting nonatomic retain properties
+ LazyRuntimeFunction SetPropertyNonAtomic;
+ /// Specialised function for setting nonatomic copy properties
+ LazyRuntimeFunction SetPropertyNonAtomicCopy;
+ /// Function to perform atomic copies of C++ objects with nontrivial copy
+ /// constructors from Objective-C ivars.
+ LazyRuntimeFunction CxxAtomicObjectGetFn;
+ /// Function to perform atomic copies of C++ objects with nontrivial copy
+ /// constructors to Objective-C ivars.
+ LazyRuntimeFunction CxxAtomicObjectSetFn;
/// Type of an slot structure pointer. This is returned by the various
/// lookup functions.
llvm::Type *SlotTy;
@@ -629,7 +678,7 @@ class CGObjCGNUstep : public CGObjCGNU {
EnforceType(Builder, ReceiverPtr, PtrToIdTy),
EnforceType(Builder, cmd, SelectorTy),
EnforceType(Builder, self, IdTy) };
- llvm::CallSite slot = CGF.EmitCallOrInvoke(LookupFn, args);
+ llvm::CallSite slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args);
slot.setOnlyReadsMemory();
slot->setMetadata(msgSendMDKind, node);
@@ -648,13 +697,16 @@ class CGObjCGNUstep : public CGObjCGNU {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs);
+ llvm::CallInst *slot =
+ CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs);
slot->setOnlyReadsMemory();
return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
}
public:
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
+ const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
+
llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
PtrTy, PtrTy, IntTy, IMPTy, NULL);
SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
@@ -672,8 +724,69 @@ class CGObjCGNUstep : public CGObjCGNU {
// void __cxa_end_catch(void)
ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL);
// void _Unwind_Resume_or_Rethrow(void*)
- ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL);
+ ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
+ PtrTy, NULL);
+ } 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);
+ // void objc_end_catch(void)
+ ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy, NULL);
+ // void _Unwind_Resume_or_Rethrow(void*)
+ ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy,
+ PtrTy, NULL);
}
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+ SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
+ SelectorTy, IdTy, PtrDiffTy, NULL);
+ SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
+ IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy,
+ IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy",
+ VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ // void objc_setCppObjectAtomic(void *dest, const void *src, void
+ // *helper);
+ CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy,
+ PtrTy, PtrTy, NULL);
+ // void objc_getCppObjectAtomic(void *dest, const void *src, void
+ // *helper);
+ CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy,
+ PtrTy, PtrTy, NULL);
+ }
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction() {
+ // 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() {
+ // 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) {
+ // 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.
+ assert ((CGM.getLangOpts().getGC() == LangOptions::NonGC));
+ // The optimised functions were added in version 1.7 of the GNUstep
+ // runtime.
+ assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
+ VersionTuple(1, 7));
+
+ if (atomic) {
+ if (copy) return SetPropertyAtomicCopy;
+ return SetPropertyAtomic;
+ }
+ if (copy) return SetPropertyNonAtomicCopy;
+ return SetPropertyNonAtomic;
+
+ return 0;
}
};
@@ -697,7 +810,7 @@ protected:
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
@@ -708,13 +821,13 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
- virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
const std::string &Name, bool isWeak) {
if (isWeak)
- return CGObjCGNU::GetClassNamed(Builder, Name, isWeak);
+ return CGObjCGNU::GetClassNamed(CGF, Name, isWeak);
EmitClassRef(Name);
@@ -894,7 +1007,7 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
}
-llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
const std::string &Name,
bool isWeak) {
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(Name);
@@ -907,25 +1020,25 @@ llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
// with memoized versions or with static references if it's safe to do so.
if (!isWeak)
EmitClassRef(Name);
- ClassName = Builder.CreateStructGEP(ClassName, 0);
+ ClassName = CGF.Builder.CreateStructGEP(ClassName, 0);
llvm::Constant *ClassLookupFn =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
"objc_lookup_class");
- return Builder.CreateCall(ClassLookupFn, ClassName);
+ return CGF.EmitNounwindRuntimeCall(ClassLookupFn, ClassName);
}
// This has to perform the lookup every time, since posing and related
// techniques can modify the name -> class mapping.
-llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) {
- return GetClassNamed(Builder, OID->getNameAsString(), OID->isWeakImported());
+ return GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported());
}
-llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
- return GetClassNamed(Builder, "NSAutoreleasePool", false);
+llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
+ return GetClassNamed(CGF, "NSAutoreleasePool", false);
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval) {
SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
@@ -948,23 +1061,23 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
}
if (lval) {
- llvm::Value *tmp = Builder.CreateAlloca(SelValue->getType());
- Builder.CreateStore(SelValue, tmp);
+ llvm::Value *tmp = CGF.CreateTempAlloca(SelValue->getType());
+ CGF.Builder.CreateStore(SelValue, tmp);
return tmp;
}
return SelValue;
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval) {
- return GetSelector(Builder, Sel, std::string(), lval);
+ return GetSelector(CGF, Sel, std::string(), lval);
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
- *Method) {
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF,
+ const ObjCMethodDecl *Method) {
std::string SelTypes;
CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes);
- return GetSelector(Builder, Method->getSelector(), SelTypes, false);
+ return GetSelector(CGF, Method->getSelector(), SelTypes, false);
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
@@ -1114,7 +1227,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
}
}
- llvm::Value *cmd = GetSelector(Builder, Sel);
+ llvm::Value *cmd = GetSelector(CGF, Sel);
CallArgList ActualArgs;
@@ -1249,9 +1362,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
if (Method)
- cmd = GetSelector(Builder, Method);
+ cmd = GetSelector(CGF, Method);
else
- cmd = GetSelector(Builder, Sel);
+ cmd = GetSelector(CGF, Sel);
cmd = EnforceType(Builder, cmd, SelectorTy);
Receiver = EnforceType(Builder, Receiver, IdTy);
@@ -1594,12 +1707,12 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRef<std::string>Protocols){
return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
}
-llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
llvm::Type *T =
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
- return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
+ return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
}
llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
@@ -1703,8 +1816,8 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// simplify the runtime library by allowing it to use the same data
// structures for protocol metadata everywhere.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
- PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
std::vector<llvm::Constant*> OptionalProperties;
@@ -1716,12 +1829,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> Fields;
ObjCPropertyDecl *property = *iter;
+ Fields.push_back(MakePropertyEncodingString(property, 0));
+ PushPropertyAttributes(Fields, property);
- Fields.push_back(MakePropertyEncodingString(property, PD));
-
- Fields.push_back(llvm::ConstantInt::get(Int8Ty,
- property->getPropertyAttributes()));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
@@ -1804,7 +1914,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
".objc_protocol"), IdTy);
}
-void CGObjCGNU::GenerateProtocolHolderCategory(void) {
+void CGObjCGNU::GenerateProtocolHolderCategory() {
// Collect information about instance methods
SmallVector<Selector, 1> MethodSels;
SmallVector<llvm::Constant*, 1> MethodTypes;
@@ -1872,7 +1982,7 @@ llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
}
return llvm::ConstantInt::get(IntPtrTy, val);
}
- llvm::SmallVector<llvm::Constant*, 8> values;
+ SmallVector<llvm::Constant *, 8> values;
int v=0;
while (v < bitCount) {
int32_t word = 0;
@@ -1951,15 +2061,13 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
SmallVectorImpl<Selector> &InstanceMethodSels,
SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
ASTContext &Context = CGM.getContext();
- //
- // Property metadata: name, attributes, isSynthesized, setter name, setter
- // types, getter name, getter types.
+ // Property metadata: name, attributes, attributes2, padding1, padding2,
+ // setter name, setter types, getter name, getter types.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
- PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
-
// Add all of the property methods need adding to the method list and to the
// property metadata list.
for (ObjCImplDecl::propimpl_iterator
@@ -1970,11 +2078,11 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
ObjCPropertyImplDecl *propertyImpl = *iter;
bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize);
+ bool isDynamic = (propertyImpl->getPropertyImplementation() ==
+ ObjCPropertyImplDecl::Dynamic);
Fields.push_back(MakePropertyEncodingString(property, OID));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty,
- property->getPropertyAttributes()));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized));
+ PushPropertyAttributes(Fields, property, isSynthesized, isDynamic);
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
@@ -2531,7 +2639,10 @@ llvm::Constant *CGObjCGNU::GetGetStructFunction() {
llvm::Constant *CGObjCGNU::GetSetStructFunction() {
return SetStructPropertyFn;
}
-llvm::Constant *CGObjCGNU::GetCppAtomicObjectFunction() {
+llvm::Constant *CGObjCGNU::GetCppAtomicObjectGetFunction() {
+ return 0;
+}
+llvm::Constant *CGObjCGNU::GetCppAtomicObjectSetFunction() {
return 0;
}
@@ -2563,7 +2674,8 @@ void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF,
}
void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) {
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint) {
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
@@ -2576,22 +2688,23 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
}
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallSite Throw =
- CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Throw.setDoesNotReturn();
CGF.Builder.CreateUnreachable();
- CGF.Builder.ClearInsertionPoint();
+ if (ClearInsertionPoint)
+ CGF.Builder.ClearInsertionPoint();
}
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy);
return B.CreateCall(WeakReadFn, AddrWeakObj);
}
void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(WeakAssignFn, src, dst);
@@ -2600,7 +2713,7 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
if (!threadlocal)
@@ -2613,7 +2726,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, IdTy);
B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
@@ -2621,7 +2734,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(StrongCastAssignFn, src, dst);
@@ -2631,7 +2744,7 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *Size) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
DestPtr = EnforceType(B, DestPtr, PtrTy);
SrcPtr = EnforceType(B, SrcPtr, PtrTy);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2203f0182800..6274e1bfe395 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -12,12 +12,11 @@
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
-
-#include "CGRecordLayout.h"
-#include "CodeGenModule.h"
-#include "CodeGenFunction.h"
#include "CGBlocks.h"
#include "CGCleanup.h"
+#include "CGRecordLayout.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -25,18 +24,17 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
-
-#include "llvm/InlineAsm.h"
-#include "llvm/IntrinsicInst.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Module.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.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 "llvm/DataLayout.h"
#include <cstdio>
using namespace clang;
@@ -63,11 +61,13 @@ private:
// Add the non-lazy-bind attribute, since objc_msgSend is likely to
// be called a lot.
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NonLazyBind));
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ params, true),
+ "objc_msgSend",
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -581,11 +581,13 @@ public:
llvm::Constant *getSetJmpFn() {
// This is specifically the prototype for x86.
llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
- params, false),
- "_setjmp",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NonLazyBind));
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
+ params, false),
+ "_setjmp",
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
public:
@@ -881,16 +883,16 @@ protected:
llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
/// DefinedClasses - List of defined classes.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
+ SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
+ SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
/// DefinedCategories - List of defined categories.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
+ SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
+ SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
/// GetNameForMethod - Return a name for the given method.
/// \param[out] NameOut - The return value.
@@ -943,7 +945,7 @@ protected:
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
- Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT);
+ Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout);
void UpdateRunSkipBlockVars(bool IsByref,
Qualifiers::ObjCLifetime LifeTime,
@@ -951,15 +953,19 @@ protected:
CharUnits FieldSize);
void BuildRCBlockVarRecordLayout(const RecordType *RT,
- CharUnits BytePos, bool &HasUnion);
+ CharUnits BytePos, bool &HasUnion,
+ bool ByrefLayout=false);
void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
const RecordDecl *RD,
ArrayRef<const FieldDecl*> RecFields,
- CharUnits BytePos, bool &HasUnion);
+ CharUnits BytePos, bool &HasUnion,
+ bool ByrefLayout);
uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
+ llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout);
+
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
@@ -982,7 +988,7 @@ protected:
/// PushProtocolProperties - Push protocol's property on the input stack.
void PushProtocolProperties(
llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
- llvm::SmallVectorImpl<llvm::Constant*> &Properties,
+ SmallVectorImpl<llvm::Constant*> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes);
@@ -1053,6 +1059,8 @@ public:
virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo);
+ virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T);
};
class CGObjCMac : public CGObjCCommonMac {
@@ -1078,13 +1086,13 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
- llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
@@ -1162,7 +1170,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lval=false);
public:
@@ -1191,15 +1199,15 @@ public:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval = false);
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method);
virtual llvm::Constant *GetEHType(QualType T);
@@ -1210,7 +1218,7 @@ public:
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetPropertyGetFunction();
@@ -1219,7 +1227,8 @@ public:
bool copy);
virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *GetSetStructFunction();
- virtual llvm::Constant *GetCppAtomicObjectFunction();
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction();
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
@@ -1228,7 +1237,8 @@ public:
const ObjCAtSynchronizedStmt &S);
void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S);
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
@@ -1360,22 +1370,22 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
- llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
- llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
- llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
@@ -1387,7 +1397,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lval=false);
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
@@ -1422,6 +1432,25 @@ private:
/// class implementation is "non-lazy".
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
+ // initialised value that may depend on objc_msgSend to perform a fixup on
+ // the first message dispatch.
+ //
+ // An additional opportunity to mark the load as invariant arises when the
+ // 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;
+ return false;
+ }
+
public:
CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
// FIXME. All stubs for now!
@@ -1448,18 +1477,18 @@ public:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lvalue = false)
- { return EmitSelector(Builder, Sel, lvalue); }
+ { return EmitSelector(CGF, Sel, lvalue); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method)
- { return EmitSelector(Builder, Method->getSelector()); }
+ { return EmitSelector(CGF, Method->getSelector()); }
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
@@ -1467,7 +1496,7 @@ public:
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetEHType(QualType T);
@@ -1490,7 +1519,10 @@ public:
virtual llvm::Constant *GetGetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
- virtual llvm::Constant *GetCppAtomicObjectFunction() {
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction() {
+ return ObjCTypes.getCppAtomicObjectFunction();
+ }
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction() {
return ObjCTypes.getCppAtomicObjectFunction();
}
@@ -1503,7 +1535,8 @@ public:
virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S);
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
@@ -1533,16 +1566,18 @@ public:
/// value.
struct NullReturnState {
llvm::BasicBlock *NullBB;
- llvm::BasicBlock *callBB;
- NullReturnState() : NullBB(0), callBB(0) {}
+ NullReturnState() : NullBB(0) {}
+ /// Perform a null-check of the given receiver.
void init(CodeGenFunction &CGF, llvm::Value *receiver) {
- // Make blocks for the null-init and call edges.
- NullBB = CGF.createBasicBlock("msgSend.nullinit");
- callBB = CGF.createBasicBlock("msgSend.call");
+ // Make blocks for the null-receiver and call edges.
+ NullBB = CGF.createBasicBlock("msgSend.null-receiver");
+ llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
// Check for a null receiver and, if there is one, jump to the
- // null-init test.
+ // null-receiver block. There's no point in trying to avoid it:
+ // we're always going to put *something* there, because otherwise
+ // we shouldn't have done this null-check in the first place.
llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
@@ -1550,25 +1585,29 @@ struct NullReturnState {
CGF.EmitBlock(callBB);
}
+ /// Complete the null-return operation. It is valid to call this
+ /// regardless of whether 'init' has been called.
RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ // If we never had to do a null-check, just use the raw result.
if (!NullBB) return result;
-
- llvm::Value *NullInitPtr = 0;
- if (result.isScalar() && !resultType->isVoidType()) {
- NullInitPtr = CGF.CreateTempAlloca(result.getScalarVal()->getType());
- CGF.Builder.CreateStore(result.getScalarVal(), NullInitPtr);
- }
+ // 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;
+
// Finish the call path.
- llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
- if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
+ llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock();
+ if (callBB) {
+ contBB = CGF.createBasicBlock("msgSend.cont");
+ CGF.Builder.CreateBr(contBB);
+ }
- // Emit the null-init block and perform the null-initialization there.
+ // Okay, start emitting the null-receiver block.
CGF.EmitBlock(NullBB);
- // Release consumed arguments along the null-receiver path.
+ // Release any consumed arguments we've got.
if (Method) {
CallArgList::const_iterator I = CallArgs.begin();
for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
@@ -1578,43 +1617,64 @@ struct NullReturnState {
RValue RV = I->RV;
assert(RV.isScalar() &&
"NullReturnState::complete - arg not on object");
- CGF.EmitARCRelease(RV.getScalarVal(), true);
+ CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
}
}
}
-
+
+ // The phi code below assumes that we haven't needed any control flow yet.
+ assert(CGF.Builder.GetInsertBlock() == NullBB);
+
+ // If we've got a void return, just jump to the continuation block.
+ if (result.isScalar() && resultType->isVoidType()) {
+ // No jumps required if the message-send was noreturn.
+ if (contBB) CGF.EmitBlock(contBB);
+ return result;
+ }
+
+ // If we've got a scalar return, build a phi.
if (result.isScalar()) {
- if (NullInitPtr)
- CGF.EmitNullInitialization(NullInitPtr, resultType);
- // Jump to the continuation block.
+ // Derive the null-initialization value.
+ llvm::Constant *null = CGF.CGM.EmitNullConstant(resultType);
+
+ // If no join is necessary, just flow out.
+ if (!contBB) return RValue::get(null);
+
+ // Otherwise, build a phi.
CGF.EmitBlock(contBB);
- return NullInitPtr ? RValue::get(CGF.Builder.CreateLoad(NullInitPtr))
- : result;
+ llvm::PHINode *phi = CGF.Builder.CreatePHI(null->getType(), 2);
+ phi->addIncoming(result.getScalarVal(), callBB);
+ phi->addIncoming(null, NullBB);
+ return RValue::get(phi);
}
-
- if (!resultType->isAnyComplexType()) {
+
+ // If we've got an aggregate return, null the buffer out.
+ // FIXME: maybe we should be doing things differently for all the
+ // cases where the ABI has us returning (1) non-agg values in
+ // memory or (2) agg values in registers.
+ if (result.isAggregate()) {
assert(result.isAggregate() && "null init of non-aggregate result?");
CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
- // Jump to the continuation block.
- CGF.EmitBlock(contBB);
+ if (contBB) CGF.EmitBlock(contBB);
return result;
}
- // _Complex type
- // FIXME. Now easy to handle any other scalar type whose result is returned
- // in memory due to ABI limitations.
+ // Complex types.
CGF.EmitBlock(contBB);
- CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
- llvm::Type *MemberType = CallCV.first->getType();
- llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
- // Create phi instruction for scalar complex value.
- llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2);
- PHIReal->addIncoming(ZeroCV, NullBB);
- PHIReal->addIncoming(CallCV.first, callBB);
- llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2);
- PHIImag->addIncoming(ZeroCV, NullBB);
- PHIImag->addIncoming(CallCV.second, callBB);
- return RValue::getComplex(PHIReal, PHIImag);
+ CodeGenFunction::ComplexPairTy callResult = result.getComplexVal();
+
+ // Find the scalar type and its zero value.
+ llvm::Type *scalarTy = callResult.first->getType();
+ llvm::Constant *scalarZero = llvm::Constant::getNullValue(scalarTy);
+
+ // Build phis for both coordinates.
+ llvm::PHINode *real = CGF.Builder.CreatePHI(scalarTy, 2);
+ real->addIncoming(callResult.first, callBB);
+ real->addIncoming(scalarZero, NullBB);
+ llvm::PHINode *imag = CGF.Builder.CreatePHI(scalarTy, 2);
+ imag->addIncoming(callResult.second, callBB);
+ imag->addIncoming(scalarZero, NullBB);
+ return RValue::getComplex(real, imag);
}
};
@@ -1655,19 +1715,19 @@ CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
/// GetClass - Return a reference to the class for the given interface
/// decl.
-llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRef(Builder, ID);
+ return EmitClassRef(CGF, ID);
}
/// GetSelector - Return the pointer to the unique'd string for this selector.
-llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval) {
- return EmitSelector(Builder, Sel, lval);
+ return EmitSelector(CGF, Sel, lval);
}
-llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method) {
- return EmitSelector(Builder, Method->getSelector());
+ return EmitSelector(CGF, Method->getSelector());
}
llvm::Constant *CGObjCMac::GetEHType(QualType T) {
@@ -1750,7 +1810,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// _metaclass_ for the current class, pointed at by
// the class's "isa" pointer. The following assumes that
// isa" is the first ivar in a class (which it must be).
- Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = EmitClassRef(CGF, Class->getSuperClass());
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
} else {
@@ -1761,7 +1821,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
}
else if (isCategoryImpl)
- Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = EmitClassRef(CGF, Class->getSuperClass());
else {
llvm::Value *ClassPtr = EmitSuperClassRef(Class);
ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
@@ -1775,7 +1835,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
@@ -1790,7 +1850,7 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
@@ -1968,13 +2028,14 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
/// getBlockCaptureLifetime - This routine returns life time of the captured
/// block variable for the purpose of block layout meta-data generation. FQT is
/// the type of the variable captured in the block.
-Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT) {
+Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT,
+ bool ByrefLayout) {
if (CGM.getLangOpts().ObjCAutoRefCount)
return FQT.getObjCLifetime();
// MRR.
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
- return Qualifiers::OCL_ExplicitNone;
+ return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong;
return Qualifiers::OCL_None;
}
@@ -2005,7 +2066,8 @@ void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
const RecordDecl *RD,
ArrayRef<const FieldDecl*> RecFields,
- CharUnits BytePos, bool &HasUnion) {
+ CharUnits BytePos, bool &HasUnion,
+ bool ByrefLayout) {
bool IsUnion = (RD && RD->isUnion());
CharUnits MaxUnionSize = CharUnits::Zero();
const FieldDecl *MaxField = 0;
@@ -2088,7 +2150,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
}
} else {
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(FQT),
+ getBlockCaptureLifetime(FQT, ByrefLayout),
BytePos + FieldOffset,
FieldSize);
}
@@ -2104,7 +2166,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
CharUnits Size = CharUnits::fromQuantity(UnsSize);
Size += LastBitfieldOrUnnamedOffset;
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
+ ByrefLayout),
BytePos + LastBitfieldOrUnnamedOffset,
Size);
} else {
@@ -2113,7 +2176,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
CharUnits FieldSize
= CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
+ ByrefLayout),
BytePos + LastBitfieldOrUnnamedOffset,
FieldSize);
}
@@ -2121,14 +2185,15 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
if (MaxField)
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(MaxField->getType()),
+ getBlockCaptureLifetime(MaxField->getType(), ByrefLayout),
BytePos + MaxFieldOffset,
MaxUnionSize);
}
void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
CharUnits BytePos,
- bool &HasUnion) {
+ bool &HasUnion,
+ bool ByrefLayout) {
const RecordDecl *RD = RT->getDecl();
SmallVector<const FieldDecl*, 16> Fields;
for (RecordDecl::field_iterator i = RD->field_begin(),
@@ -2138,7 +2203,7 @@ void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
const llvm::StructLayout *RecLayout =
CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
- BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion);
+ BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion, ByrefLayout);
}
/// InlineLayoutInstruction - This routine produce an inline instruction for the
@@ -2247,64 +2312,19 @@ uint64_t CGObjCCommonMac::InlineLayoutInstruction(
return Result;
}
-llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
-
+llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
- RunSkipBlockVars.clear();
- bool hasUnion = false;
-
+ if (RunSkipBlockVars.empty())
+ return nullPtr;
unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- // Calculate the basic layout of the block structure.
- const llvm::StructLayout *layout =
- CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
-
- // Ignore the optional 'this' capture: C++ objects are not assumed
- // 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();
- QualType type = variable->getType();
-
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-
- // Ignore constant captures.
- if (capture.isConstant()) continue;
-
- CharUnits fieldOffset =
- CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
-
- assert(!type->isArrayType() && "array variable should not be caught");
- if (const RecordType *record = type->getAs<RecordType>()) {
- BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
- continue;
- }
- CharUnits fieldSize;
- if (ci->isByRef())
- fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
- else
- fieldSize = CGM.getContext().getTypeSizeInChars(type);
- UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type),
- fieldOffset, fieldSize);
- }
-
- if (RunSkipBlockVars.empty())
- return nullPtr;
-
// Sort on byte position; captures might not be allocated in order,
// and unions can do funny things.
llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end());
SmallVector<unsigned char, 16> Layout;
-
+
unsigned size = RunSkipBlockVars.size();
for (unsigned i = 0; i < size; i++) {
enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
@@ -2320,11 +2340,11 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
break;
}
CharUnits size_in_bytes =
- end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
+ end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
if (j < size) {
CharUnits gap =
- RunSkipBlockVars[j].block_var_bytepos -
- RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
+ RunSkipBlockVars[j].block_var_bytepos -
+ RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
size_in_bytes += gap;
}
CharUnits residue_in_bytes = CharUnits::Zero();
@@ -2333,7 +2353,7 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
size_in_bytes -= residue_in_bytes;
opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS;
}
-
+
unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes;
while (size_in_words >= 16) {
// Note that value in imm. is one less that the actual
@@ -2350,7 +2370,7 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
}
if (residue_in_bytes > CharUnits::Zero()) {
unsigned char inst =
- (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
+ (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
Layout.push_back(inst);
}
}
@@ -2369,7 +2389,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
if (Result != 0) {
// Block variable layout instruction has been inlined.
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n Inline instruction for block variable layout: ");
+ if (ComputeByrefLayout)
+ printf("\n Inline instruction for BYREF variable layout: ");
+ else
+ printf("\n Inline instruction for block variable layout: ");
printf("0x0%llx\n", (unsigned long long)Result);
}
if (WordSizeInBytes == 8) {
@@ -2389,7 +2412,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
BitMap += Layout[i];
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n block variable layout: ");
+ if (ComputeByrefLayout)
+ printf("\n BYREF variable layout: ");
+ else
+ printf("\n block variable layout: ");
for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
unsigned char inst = BitMap[i];
enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
@@ -2417,10 +2443,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
case BLOCK_LAYOUT_UNRETAINED:
printf("BL_UNRETAINED:");
break;
- }
+ }
// Actual value of word count is one more that what is in the imm.
// field of the instruction
- printf("%d", (inst & 0xf) + delta);
+ printf("%d", (inst & 0xf) + delta);
if (i < e-1)
printf(", ");
else
@@ -2429,13 +2455,84 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
}
llvm::GlobalVariable * Entry =
- CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
llvm::ConstantDataArray::getString(VMContext, BitMap,false),
"__TEXT,__objc_classname,cstring_literals", 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
-llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+
+ RunSkipBlockVars.clear();
+ bool hasUnion = false;
+
+ unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
+
+ const BlockDecl *blockDecl = blockInfo.getBlockDecl();
+
+ // Calculate the basic layout of the block structure.
+ const llvm::StructLayout *layout =
+ CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
+
+ // Ignore the optional 'this' capture: C++ objects are not assumed
+ // to be GC'ed.
+ if (blockInfo.BlockHeaderForcedGapSize != CharUnits::Zero())
+ UpdateRunSkipBlockVars(false, Qualifiers::OCL_None,
+ 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();
+ QualType type = variable->getType();
+
+ const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
+
+ // Ignore constant captures.
+ if (capture.isConstant()) continue;
+
+ CharUnits fieldOffset =
+ CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
+
+ assert(!type->isArrayType() && "array variable should not be caught");
+ if (!ci->isByRef())
+ if (const RecordType *record = type->getAs<RecordType>()) {
+ BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
+ continue;
+ }
+ CharUnits fieldSize;
+ if (ci->isByRef())
+ fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
+ else
+ fieldSize = CGM.getContext().getTypeSizeInChars(type);
+ UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type, false),
+ fieldOffset, fieldSize);
+ }
+ return getBitmapBlockLayout(false);
+}
+
+
+llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T) {
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+ assert(!T->isArrayType() && "__block array variable should not be caught");
+ CharUnits fieldOffset;
+ RunSkipBlockVars.clear();
+ bool hasUnion = false;
+ if (const RecordType *record = T->getAs<RecordType>()) {
+ BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
+ llvm::Constant *Result = getBitmapBlockLayout(true);
+ return Result;
+ }
+ llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+ return nullPtr;
+}
+
+llvm::Value *CGObjCMac::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
// resolved. Investigate. Its also wasteful to look this up over and over.
@@ -2644,7 +2741,7 @@ llvm::Constant *
CGObjCMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
- llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
+ SmallVector<llvm::Constant *, 16> ProtocolRefs;
for (; begin != end; ++begin)
ProtocolRefs.push_back(GetProtocolRef(*begin));
@@ -2675,7 +2772,7 @@ CGObjCMac::EmitProtocolList(Twine Name,
void CGObjCCommonMac::
PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
- llvm::SmallVectorImpl<llvm::Constant*> &Properties,
+ SmallVectorImpl<llvm::Constant *> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes) {
@@ -2711,7 +2808,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
- llvm::SmallVector<llvm::Constant*, 16> Properties;
+ 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) {
@@ -2846,7 +2943,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
<< OCD->getName();
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
+ SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods;
for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
@@ -2974,7 +3071,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= FragileABI_Class_Hidden;
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
+ SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
@@ -3368,7 +3465,10 @@ llvm::Constant *CGObjCMac::GetSetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
-llvm::Constant *CGObjCMac::GetCppAtomicObjectFunction() {
+llvm::Constant *CGObjCMac::GetCppAtomicObjectGetFunction() {
+ return ObjCTypes.getCppAtomicObjectFunction();
+}
+llvm::Constant *CGObjCMac::GetCppAtomicObjectSetFunction() {
return ObjCTypes.getCppAtomicObjectFunction();
}
@@ -3411,14 +3511,17 @@ namespace {
FinallyCallExit, FinallyNoCallExit);
CGF.EmitBlock(FinallyCallExit);
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
+ ExceptionData);
CGF.EmitBlock(FinallyNoCallExit);
if (isa<ObjCAtTryStmt>(S)) {
if (const ObjCAtFinallyStmt* FinallyStmt =
cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
+ // Don't try to do the @finally if this is an EH cleanup.
+ if (flags.isForEHCleanup()) return;
+
// Save the current cleanup destination in case there's
// control flow inside the finally statement.
llvm::Value *CurCleanupDest =
@@ -3438,8 +3541,7 @@ namespace {
// Emit objc_sync_exit(expr); as finally's sole statement for
// @synchronized.
llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
- CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncExitFn(), SyncArg);
}
}
};
@@ -3516,12 +3618,14 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
void FragileHazards::emitWriteHazard() {
if (Locals.empty()) return;
- CGF.Builder.CreateCall(WriteHazard, Locals)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
}
void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
assert(!Locals.empty());
- Builder.CreateCall(ReadHazard, Locals)->setDoesNotThrow();
+ llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
+ call->setDoesNotThrow();
+ call->setCallingConv(CGF.getRuntimeCC());
}
/// Emit read hazards in all the protected blocks, i.e. all the blocks
@@ -3726,8 +3830,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(), "sync.arg");
CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
@@ -3760,7 +3863,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *PropagatingExnVar = 0;
// Push a normal cleanup to leave the try scope.
- CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S,
+ CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
SyncArgSlot,
CallTryExitVar,
ExceptionData,
@@ -3769,8 +3872,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Enter a try block:
// - Call objc_exception_try_enter to push ExceptionData on top of
// the EH stack.
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
// - Call setjmp on the exception data buffer.
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
@@ -3778,8 +3880,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *SetJmpBuffer =
CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer");
llvm::CallInst *SetJmpResult =
- CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
- SetJmpResult->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setCanReturnTwice();
// If setjmp returned 0, enter the protected block; otherwise,
@@ -3816,9 +3917,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Retrieve the exception object. We may emit multiple blocks but
// nothing can cross this so the value is already in SSA form.
llvm::CallInst *Caught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
- Caught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
// Push the exception to rethrow onto the EH value stack for the
// benefit of any @throws in the handlers.
@@ -3839,13 +3939,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Enter a new exception try block (in case a @catch block
// throws an exception).
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
+ ExceptionData);
llvm::CallInst *SetJmpResult =
- CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer,
- "setjmp.result");
- SetJmpResult->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
+ SetJmpBuffer, "setjmp.result");
SetJmpResult->setCanReturnTwice();
llvm::Value *Threw =
@@ -3913,12 +4012,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
assert(IDecl && "Catch parameter must have Objective-C type!");
// Check if the @catch block matches the exception object.
- llvm::Value *Class = EmitClassRef(CGF.Builder, IDecl);
+ llvm::Value *Class = EmitClassRef(CGF, IDecl);
+ llvm::Value *matchArgs[] = { Class, Caught };
llvm::CallInst *Match =
- CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(),
- Class, Caught, "match");
- Match->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionMatchFn(),
+ matchArgs, "match");
llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
@@ -3975,9 +4074,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// propagating-exception slot.
assert(PropagatingExnVar);
llvm::CallInst *NewCaught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
- NewCaught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
// Don't pop the catch handler; the throw already did.
@@ -4008,14 +4106,13 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Otherwise, just look in the buffer for the exception to throw.
} else {
llvm::CallInst *Caught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData);
- Caught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData);
PropagatingExn = Caught;
}
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), PropagatingExn)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionThrowFn(),
+ PropagatingExn);
CGF.Builder.CreateUnreachable();
}
@@ -4023,7 +4120,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
}
void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) {
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint) {
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
@@ -4036,12 +4134,13 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
+ CGF.EmitRuntimeCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
// Clear the insertion point to indicate we are in unreachable code.
- CGF.Builder.ClearInsertionPoint();
+ if (ClearInsertionPoint)
+ CGF.Builder.ClearInsertionPoint();
}
/// EmitObjCWeakRead - Code gen for loading value of a __weak
@@ -4053,8 +4152,9 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ llvm::Value *read_weak =
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -4074,8 +4174,9 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
- src, dst, "weakassign");
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
+ args, "weakassign");
return;
}
@@ -4095,12 +4196,13 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *args[] = { src, dst };
if (!threadlocal)
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
- src, dst, "globalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
+ args, "globalassign");
else
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
- src, dst, "threadlocalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
+ args, "threadlocalassign");
return;
}
@@ -4121,8 +4223,8 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
- src, dst, ivarOffset);
+ llvm::Value *args[] = { src, dst, ivarOffset };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
return;
}
@@ -4141,8 +4243,9 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
- src, dst, "weakassign");
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
+ args, "weakassign");
return;
}
@@ -4152,9 +4255,8 @@ void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
- DestPtr, SrcPtr, size);
- return;
+ llvm::Value *args[] = { DestPtr, SrcPtr, size };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
/// EmitObjCValueForIvar - Code Gen for ivar reference.
@@ -4318,8 +4420,8 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
-llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
- IdentifierInfo *II) {
+llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
+ IdentifierInfo *II) {
LazySymbols.insert(II);
llvm::GlobalVariable *&Entry = ClassReferences[II];
@@ -4334,20 +4436,20 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
4, true);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
-llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(Builder, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier());
}
-llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(Builder, II);
+ return EmitClassRefFromId(CGF, II);
}
-llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lvalue) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -4359,11 +4461,12 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted,
"__OBJC,__message_refs,literal_pointers,no_dead_strip",
4, true);
+ Entry->setExternallyInitialized(true);
}
if (lvalue)
return Entry;
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
@@ -5825,7 +5928,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
/// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
/// which will hold address of the protocol meta-data.
///
-llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
// This routine is called for @protocol only. So, we must build definition
@@ -5840,7 +5943,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateLoad(PTGV);
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -5850,7 +5953,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
- return Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateLoad(PTGV);
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -6288,7 +6391,7 @@ llvm::Constant *
CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
- llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
+ SmallVector<llvm::Constant *, 16> ProtocolRefs;
// Just return null for empty protocol lists
if (begin == end)
@@ -6365,10 +6468,12 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
unsigned CVRQualifiers) {
ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
- if (llvm::LoadInst *LI = dyn_cast<llvm::LoadInst>(Offset))
- LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext,
- ArrayRef<llvm::Value*>()));
+
+ 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);
}
@@ -6530,7 +6635,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
@@ -6548,7 +6653,7 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
return GV;
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II) {
llvm::GlobalVariable *&Entry = ClassReferences[II];
@@ -6567,22 +6672,22 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(Builder, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier());
}
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
- CGBuilderTy &Builder) {
+ CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(Builder, II);
+ return EmitClassRefFromId(CGF, II);
}
llvm::Value *
-CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
+CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
@@ -6601,17 +6706,17 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
///
-llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
@@ -6627,12 +6732,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
/// GetClass - Return a reference to the class for the given interface
/// decl.
-llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
if (ID->isWeakImported()) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
@@ -6640,7 +6745,7 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
- return EmitClassRef(Builder, ID);
+ return EmitClassRef(CGF, ID);
}
/// Generates a message send where the super is the receiver. This is
@@ -6671,9 +6776,9 @@ 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.Builder, Class);
+ Target = EmitMetaClassRef(CGF, Class);
else
- Target = EmitSuperClassRef(CGF.Builder, Class);
+ Target = EmitSuperClassRef(CGF, Class);
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
@@ -6688,12 +6793,12 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
Selector Sel, bool lval) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -6705,13 +6810,14 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
llvm::GlobalValue::InternalLinkage,
Casted, "\01L_OBJC_SELECTOR_REFERENCES_");
+ Entry->setExternallyInitialized(true);
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
if (lval)
return Entry;
- llvm::LoadInst* LI = Builder.CreateLoad(Entry);
+ llvm::LoadInst* LI = CGF.Builder.CreateLoad(Entry);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(VMContext,
@@ -6735,9 +6841,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
- src, dst, ivarOffset);
- return;
+ llvm::Value *args[] = { src, dst, ivarOffset };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
}
/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
@@ -6756,9 +6861,9 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
- src, dst, "weakassign");
- return;
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
+ args, "weakassign");
}
void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
@@ -6768,9 +6873,8 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
llvm::Value *Size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
- DestPtr, SrcPtr, Size);
- return;
+ llvm::Value *args[] = { DestPtr, SrcPtr, Size };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
/// EmitObjCWeakRead - Code gen for loading value of a __weak
@@ -6782,8 +6886,9 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
llvm::Type* DestTy =
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ llvm::Value *read_weak =
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -6803,9 +6908,9 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
- src, dst, "weakassign");
- return;
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
+ args, "weakassign");
}
/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
@@ -6824,13 +6929,13 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *args[] = { src, dst };
if (!threadlocal)
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
- src, dst, "globalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
+ args, "globalassign");
else
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
- src, dst, "threadlocalassign");
- return;
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
+ args, "threadlocalassign");
}
void
@@ -6876,19 +6981,21 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
/// EmitThrowStmt - Generate code for a throw statement.
void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) {
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint) {
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
+ CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
.setDoesNotReturn();
} else {
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
+ CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
.setDoesNotReturn();
}
CGF.Builder.CreateUnreachable();
- CGF.Builder.ClearInsertionPoint();
+ if (ClearInsertionPoint)
+ CGF.Builder.ClearInsertionPoint();
}
llvm::Constant *
@@ -6946,7 +7053,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
ID->getIdentifier()->getName()));
}
- if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility)
+ if (ID->getVisibility() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.EHTypeTy));
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 6932dd709d16..abd10a29c9e2 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -14,15 +14,12 @@
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
-
+#include "CGCleanup.h"
#include "CGRecordLayout.h"
-#include "CodeGenModule.h"
#include "CodeGenFunction.h"
-#include "CGCleanup.h"
-
+#include "CodeGenModule.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
-
#include "llvm/Support/CallSite.h"
using namespace clang;
@@ -92,14 +89,13 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- llvm::Type *I8Ptr = CGF.Int8PtrTy;
QualType IvarTy = Ivar->getType();
llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
- llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
+ llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy);
V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
- V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
if (!Ivar->isBitField()) {
+ V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy);
LV.getQuals().addCVRQualifiers(CVRQualifiers);
return LV;
@@ -119,16 +115,14 @@ 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.
- const ASTRecordLayout &RL =
- CGF.CGM.getContext().getASTObjCInterfaceLayout(OID);
- uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize());
uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar);
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
- uint64_t ContainingTypeAlign = CGF.CGM.getContext().getTargetInfo().getCharAlign();
- uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset);
+ uint64_t AlignmentBits = CGF.CGM.getContext().getTargetInfo().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
- CharUnits ContainingTypeAlignCharUnits =
- CGF.CGM.getContext().toCharUnitsFromBits(ContainingTypeAlign);
+ CharUnits StorageSize =
+ CGF.CGM.getContext().toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(BitOffset + BitFieldSize, AlignmentBits));
+ CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits);
// Allocate a new CGBitFieldInfo object to describe this access.
//
@@ -138,11 +132,15 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// objects.
CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
- ContainingTypeSize, ContainingTypeAlign));
+ CGF.CGM.getContext().toBits(StorageSize),
+ Alignment.getQuantity()));
+ V = CGF.Builder.CreateBitCast(V,
+ llvm::Type::getIntNPtrTy(CGF.getLLVMContext(),
+ Info->StorageSize));
return LValue::MakeBitfield(V, *Info,
IvarTy.withCVRQualifiers(CVRQualifiers),
- ContainingTypeAlignCharUnits);
+ Alignment);
}
namespace {
@@ -165,7 +163,7 @@ namespace {
return;
}
- CGF.EmitCallOrInvoke(Fn);
+ CGF.EmitRuntimeCallOrInvoke(Fn);
}
};
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 3e77875e6baf..7f030f2341da 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -15,12 +15,11 @@
#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
#define CLANG_CODEGEN_OBCJRUNTIME_H
-#include "clang/Basic/IdentifierTable.h" // Selector
-#include "clang/AST/DeclObjC.h"
-
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGValue.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/IdentifierTable.h" // Selector
namespace llvm {
class Constant;
@@ -120,11 +119,11 @@ public:
/// Get a selector for the specified name and type values. The
/// return value should have the LLVM type for pointer-to
/// ASTContext::getObjCSelType().
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
Selector Sel, bool lval=false) = 0;
/// Get a typed selector.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method) = 0;
/// Get the type constant to catch for the given ObjC pointer type.
@@ -180,7 +179,7 @@ public:
/// Emit the code to return the named protocol as an object, as in a
/// \@protocol expression.
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *OPD) = 0;
/// Generate the named protocol. Protocols contain method metadata but no
@@ -210,17 +209,20 @@ public:
virtual llvm::Constant *GetGetStructFunction() = 0;
// API for atomic copying of qualified aggregates in setter.
virtual llvm::Constant *GetSetStructFunction() = 0;
- // API for atomic copying of qualified aggregates with non-trivial copy
- // assignment (c++) in setter/getter.
- virtual llvm::Constant *GetCppAtomicObjectFunction() = 0;
+ /// API for atomic copying of qualified aggregates with non-trivial copy
+ /// assignment (c++) in setter.
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction() = 0;
+ /// API for atomic copying of qualified aggregates with non-trivial copy
+ /// assignment (c++) in getter.
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction() = 0;
/// GetClass - Return a reference to the class for the given
/// interface decl.
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) = 0;
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
llvm_unreachable("autoreleasepool unsupported in this ABI");
}
@@ -233,7 +235,8 @@ public:
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S) = 0;
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) = 0;
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true) = 0;
virtual llvm::Value *EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) = 0;
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
@@ -263,6 +266,8 @@ public:
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+ virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T) = 0;
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
struct MessageSendInfo {
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 3a0e116e5ab1..7c454ac7c695 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -15,7 +15,9 @@
#include "CGOpenCLRuntime.h"
#include "CodeGenFunction.h"
-#include "llvm/GlobalValue.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/GlobalValue.h"
+#include <assert.h>
using namespace clang;
using namespace CodeGen;
@@ -26,3 +28,37 @@ void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
const VarDecl &D) {
return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
}
+
+llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
+ assert(T->isOpenCLSpecificType() &&
+ "Not an OpenCL specific type!");
+
+ switch (cast<BuiltinType>(T)->getKind()) {
+ default:
+ llvm_unreachable("Unexpected opencl builtin type!");
+ return 0;
+ case BuiltinType::OCLImage1d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_t"), 0);
+ case BuiltinType::OCLImage1dArray:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_array_t"), 0);
+ case BuiltinType::OCLImage1dBuffer:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_buffer_t"), 0);
+ case BuiltinType::OCLImage2d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image2d_t"), 0);
+ case BuiltinType::OCLImage2dArray:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image2d_array_t"), 0);
+ case BuiltinType::OCLImage3d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image3d_t"), 0);
+ case BuiltinType::OCLSampler:
+ return llvm::IntegerType::get(CGM.getLLVMContext(),32);
+ case BuiltinType::OCLEvent:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.event_t"), 0);
+ }
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 9a8430fb7500..7b675c3bc1e7 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -16,6 +16,10 @@
#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H
#define CLANG_CODEGEN_OPENCLRUNTIME_H
+#include "clang/AST/Type.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+
namespace clang {
class VarDecl;
@@ -38,6 +42,8 @@ public:
/// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D.
virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
const VarDecl &D);
+
+ virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
};
}
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 7c83d39f8bce..869843cbd4e8 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -13,10 +13,10 @@
#include "CodeGenModule.h"
#include "CGCXXABI.h"
+#include "CGObjCRuntime.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "CGObjCRuntime.h"
using namespace clang;
using namespace CodeGen;
@@ -191,6 +191,14 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
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:
@@ -244,10 +252,12 @@ static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
/// 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) {
+static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
+ QualType Ty) {
ASTContext &Context = CGM.getContext();
- // If RTTI is disabled, don't consider key functions.
+ // 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)) {
@@ -258,7 +268,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
if (!RD->isDynamicClass())
return false;
- return !CGM.getVTables().ShouldEmitVTableInThisTU(RD);
+ // FIXME: this may need to be reconsidered if the key function
+ // changes.
+ return CGM.getVTables().isVTableExternal(RD);
}
return false;
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 3db5e0483bab..b29fc987a120 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -14,7 +14,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/DerivedTypes.h"
+#include "llvm/IR/DerivedTypes.h"
namespace llvm {
class StructType;
@@ -23,122 +23,71 @@ namespace llvm {
namespace clang {
namespace CodeGen {
-/// \brief Helper object for describing how to generate the code for access to a
-/// bit-field.
+/// \brief Structure with information about how a bitfield should be accessed.
///
-/// This structure is intended to describe the "policy" of how the bit-field
-/// should be accessed, which may be target, language, or ABI dependent.
-class CGBitFieldInfo {
-public:
- /// Descriptor for a single component of a bit-field access. The entire
- /// bit-field is constituted of a bitwise OR of all of the individual
- /// components.
- ///
- /// Each component describes an accessed value, which is how the component
- /// should be transferred to/from memory, and a target placement, which is how
- /// that component fits into the constituted bit-field. The pseudo-IR for a
- /// load is:
- ///
- /// %0 = gep %base, 0, FieldIndex
- /// %1 = gep (i8*) %0, FieldByteOffset
- /// %2 = (i(AccessWidth) *) %1
- /// %3 = load %2, align AccessAlignment
- /// %4 = shr %3, FieldBitStart
- ///
- /// and the composed bit-field is formed as the boolean OR of all accesses,
- /// masked to TargetBitWidth bits and shifted to TargetBitOffset.
- struct AccessInfo {
- /// Offset of the field to load in the LLVM structure, if any.
- unsigned FieldIndex;
-
- /// Byte offset from the field address, if any. This should generally be
- /// unused as the cleanest IR comes from having a well-constructed LLVM type
- /// with proper GEP instructions, but sometimes its use is required, for
- /// example if an access is intended to straddle an LLVM field boundary.
- CharUnits FieldByteOffset;
-
- /// Bit offset in the accessed value to use. The width is implied by \see
- /// TargetBitWidth.
- unsigned FieldBitStart;
-
- /// Bit width of the memory access to perform.
- unsigned AccessWidth;
-
- /// The alignment of the memory access, assuming the parent is aligned.
- CharUnits AccessAlignment;
-
- /// Offset for the target value.
- unsigned TargetBitOffset;
-
- /// Number of bits in the access that are destined for the bit-field.
- unsigned TargetBitWidth;
- };
-
-private:
- /// The components to use to access the bit-field. We may need up to three
- /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte
- /// accesses).
- //
- // FIXME: De-hardcode this, just allocate following the struct.
- AccessInfo Components[3];
+/// Often we layout a sequence of bitfields as a contiguous sequence of bits.
+/// When the AST record layout does this, we represent it in the LLVM IR's type
+/// as either a sequence of i8 members or a byte array to reserve the number of
+/// bytes touched without forcing any particular alignment beyond the basic
+/// character alignment.
+///
+/// Then accessing a particular bitfield involves converting this byte array
+/// into a single integer of that size (i24 or i40 -- may not be power-of-two
+/// size), loading it, and shifting and masking to extract the particular
+/// subsequence of bits which make up that particular bitfield. This structure
+/// encodes the information used to construct the extraction code sequences.
+/// The CGRecordLayout also has a field index which encodes which byte-sequence
+/// this bitfield falls within. Let's assume the following C struct:
+///
+/// struct S {
+/// char a, b, c;
+/// unsigned bits : 3;
+/// unsigned more_bits : 4;
+/// unsigned still_more_bits : 7;
+/// };
+///
+/// This will end up as the following LLVM type. The first array is the
+/// bitfield, and the second is the padding out to a 4-byte alignmnet.
+///
+/// %t = type { i8, i8, i8, i8, i8, [3 x i8] }
+///
+/// When generating code to access more_bits, we'll generate something
+/// essentially like this:
+///
+/// define i32 @foo(%t* %base) {
+/// %0 = gep %t* %base, i32 0, i32 3
+/// %2 = load i8* %1
+/// %3 = lshr i8 %2, 3
+/// %4 = and i8 %3, 15
+/// %5 = zext i8 %4 to i32
+/// ret i32 %i
+/// }
+///
+struct CGBitFieldInfo {
+ /// The offset within a contiguous run of bitfields that are represented as
+ /// a single "field" within the LLVM struct type. This offset is in bits.
+ unsigned Offset : 16;
/// The total size of the bit-field, in bits.
- unsigned Size;
-
- /// The number of access components to use.
- unsigned NumComponents;
+ unsigned Size : 15;
/// Whether the bit-field is signed.
- bool IsSigned : 1;
+ unsigned IsSigned : 1;
-public:
- CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components,
- bool IsSigned) : Size(Size), NumComponents(NumComponents),
- IsSigned(IsSigned) {
- assert(NumComponents <= 3 && "invalid number of components!");
- for (unsigned i = 0; i != NumComponents; ++i)
- Components[i] = _Components[i];
-
- // Check some invariants.
- unsigned AccessedSize = 0;
- for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
- const AccessInfo &AI = getComponent(i);
- AccessedSize += AI.TargetBitWidth;
-
- // We shouldn't try to load 0 bits.
- assert(AI.TargetBitWidth > 0);
-
- // We can't load more bits than we accessed.
- assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth);
-
- // We shouldn't put any bits outside the result size.
- assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size);
- }
-
- // Check that the total number of target bits matches the total bit-field
- // size.
- assert(AccessedSize == Size && "Total size does not match accessed size!");
- }
-
-public:
- /// \brief Check whether this bit-field access is (i.e., should be sign
- /// extended on loads).
- bool isSigned() const { return IsSigned; }
-
- /// \brief Get the size of the bit-field, in bits.
- unsigned getSize() const { return Size; }
+ /// The storage size in bits which should be used when accessing this
+ /// bitfield.
+ unsigned StorageSize;
- /// @name Component Access
- /// @{
+ /// The alignment which should be used when accessing the bitfield.
+ unsigned StorageAlignment;
- unsigned getNumComponents() const { return NumComponents; }
+ CGBitFieldInfo()
+ : Offset(), Size(), IsSigned(), StorageSize(), StorageAlignment() {}
- const AccessInfo &getComponent(unsigned Index) const {
- assert(Index < getNumComponents() && "Invalid access!");
- return Components[Index];
- }
-
- /// @}
+ CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
+ unsigned StorageSize, unsigned StorageAlignment)
+ : Offset(Offset), Size(Size), IsSigned(IsSigned),
+ StorageSize(StorageSize), StorageAlignment(StorageAlignment) {}
void print(raw_ostream &OS) const;
void dump() const;
@@ -146,17 +95,11 @@ public:
/// \brief Given a bit-field decl, build an appropriate helper object for
/// accessing that field (which is expected to have the given offset and
/// size).
- static CGBitFieldInfo MakeInfo(class CodeGenTypes &Types, const FieldDecl *FD,
- uint64_t FieldOffset, uint64_t FieldSize);
-
- /// \brief Given a bit-field decl, build an appropriate helper object for
- /// accessing that field (which is expected to have the given offset and
- /// size). The field decl should be known to be contained within a type of at
- /// least the given size and with the given alignment.
- static CGBitFieldInfo MakeInfo(CodeGenTypes &Types, const FieldDecl *FD,
- uint64_t FieldOffset, uint64_t FieldSize,
- uint64_t ContainingTypeSizeInBits,
- unsigned ContainingTypeAlign);
+ static CGBitFieldInfo MakeInfo(class CodeGenTypes &Types,
+ const FieldDecl *FD,
+ uint64_t Offset, uint64_t Size,
+ uint64_t StorageSize,
+ uint64_t StorageAlignment);
};
/// CGRecordLayout - This class handles struct and union layout info while
@@ -240,7 +183,6 @@ public:
/// \brief Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
- assert(!FD->isBitField() && "Invalid call for bit-field decl!");
assert(FieldInfo.count(FD) && "Invalid field for record!");
return FieldInfo.lookup(FD);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 26ef3efe73e6..2c6438b0b67c 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "CGRecordLayout.h"
+#include "CGCXXABI.h"
+#include "CodeGenTypes.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
@@ -19,13 +21,11 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "CodeGenTypes.h"
-#include "CGCXXABI.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Type.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -100,10 +100,6 @@ private:
/// Alignment - Contains the alignment of the RecordDecl.
CharUnits Alignment;
- /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
- /// this will have the number of bits still available in the field.
- char BitsAvailableInLastField;
-
/// NextFieldOffset - Holds the next field offset.
CharUnits NextFieldOffset;
@@ -115,6 +111,12 @@ private:
/// 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);
+
/// LayoutField - try to layout all fields in the record decl.
/// Returns false if the operation failed because the struct is not packed.
bool LayoutFields(const RecordDecl *D);
@@ -194,7 +196,7 @@ public:
: BaseSubobjectType(0),
IsZeroInitializable(true), IsZeroInitializableAsBase(true),
Packed(false), IsMsStruct(false),
- Types(Types), BitsAvailableInLastField(0) { }
+ Types(Types) { }
/// Layout - Will layout a RecordDecl.
void Layout(const RecordDecl *D);
@@ -230,13 +232,10 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
}
CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t FieldOffset,
- uint64_t FieldSize,
- uint64_t ContainingTypeSizeInBits,
- unsigned ContainingTypeAlign) {
- assert(ContainingTypeAlign && "Expected alignment to be specified");
-
+ 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));
@@ -244,7 +243,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
- if (FieldSize > TypeSizeInBits) {
+ 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:
//
@@ -254,173 +253,131 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
//
// T t : sizeof(T);
//
- FieldSize = TypeSizeInBits;
+ Size = TypeSizeInBits;
}
- // in big-endian machines the first fields are in higher bit positions,
- // so revert the offset. The byte offsets are reversed(back) later.
+ // 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()) {
- FieldOffset = ((ContainingTypeSizeInBits)-FieldOffset-FieldSize);
- }
-
- // Compute the access components. The policy we use is to start by attempting
- // to access using the width of the bit-field type itself and to always access
- // at aligned indices of that type. If such an access would fail because it
- // extends past the bound of the type, then we reduce size to the next smaller
- // power of two and retry. The current algorithm assumes pow2 sized types,
- // although this is easy to fix.
- //
- assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!");
- CGBitFieldInfo::AccessInfo Components[3];
- unsigned NumComponents = 0;
- unsigned AccessedTargetBits = 0; // The number of target bits accessed.
- unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt.
-
- // If requested, widen the initial bit-field access to be register sized. The
- // theory is that this is most likely to allow multiple accesses into the same
- // structure to be coalesced, and that the backend should be smart enough to
- // narrow the store if no coalescing is ever done.
- //
- // The subsequent code will handle align these access to common boundaries and
- // guaranteeing that we do not access past the end of the structure.
- if (Types.getCodeGenOpts().UseRegisterSizedBitfieldAccess) {
- if (AccessWidth < Types.getTarget().getRegisterWidth())
- AccessWidth = Types.getTarget().getRegisterWidth();
+ Offset = StorageSize - (Offset + Size);
}
- // Round down from the field offset to find the first access position that is
- // at an aligned offset of the initial access type.
- uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth);
-
- // Adjust initial access size to fit within record.
- while (AccessWidth > Types.getTarget().getCharWidth() &&
- AccessStart + AccessWidth > ContainingTypeSizeInBits) {
- AccessWidth >>= 1;
- AccessStart = FieldOffset - (FieldOffset % AccessWidth);
- }
-
- while (AccessedTargetBits < FieldSize) {
- // Check that we can access using a type of this size, without reading off
- // the end of the structure. This can occur with packed structures and
- // -fno-bitfield-type-align, for example.
- if (AccessStart + AccessWidth > ContainingTypeSizeInBits) {
- // If so, reduce access size to the next smaller power-of-two and retry.
- AccessWidth >>= 1;
- assert(AccessWidth >= Types.getTarget().getCharWidth()
- && "Cannot access under byte size!");
- continue;
- }
-
- // Otherwise, add an access component.
-
- // First, compute the bits inside this access which are part of the
- // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the
- // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits
- // in the target that we are reading.
- assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!");
- assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!");
- uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset);
- uint64_t AccessBitsInFieldSize =
- std::min(AccessWidth + AccessStart,
- FieldOffset + FieldSize) - AccessBitsInFieldStart;
-
- assert(NumComponents < 3 && "Unexpected number of components!");
- CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++];
- AI.FieldIndex = 0;
- // FIXME: We still follow the old access pattern of only using the field
- // byte offset. We should switch this once we fix the struct layout to be
- // pretty.
-
- // on big-endian machines we reverted the bit offset because first fields are
- // in higher bits. But this also reverts the bytes, so fix this here by reverting
- // the byte offset on big-endian machines.
- if (Types.getDataLayout().isBigEndian()) {
- AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(
- ContainingTypeSizeInBits - AccessStart - AccessWidth);
- } else {
- AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(AccessStart);
- }
- AI.FieldBitStart = AccessBitsInFieldStart - AccessStart;
- AI.AccessWidth = AccessWidth;
- AI.AccessAlignment = Types.getContext().toCharUnitsFromBits(
- llvm::MinAlign(ContainingTypeAlign, AccessStart));
- AI.TargetBitOffset = AccessedTargetBits;
- AI.TargetBitWidth = AccessBitsInFieldSize;
-
- AccessStart += AccessWidth;
- AccessedTargetBits += AI.TargetBitWidth;
- }
-
- assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!");
- return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned);
+ return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment);
}
-CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t FieldOffset,
- uint64_t FieldSize) {
- const RecordDecl *RD = FD->getParent();
- const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD);
- uint64_t ContainingTypeSizeInBits = Types.getContext().toBits(RL.getSize());
- unsigned ContainingTypeAlign = Types.getContext().toBits(RL.getAlignment());
-
- return MakeInfo(Types, FD, FieldOffset, FieldSize, ContainingTypeSizeInBits,
- ContainingTypeAlign);
-}
-
-void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
- uint64_t fieldOffset) {
- uint64_t fieldSize = D->getBitWidthValue(Types.getContext());
-
- if (fieldSize == 0)
- return;
-
- uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- CharUnits numBytesToAppend;
- unsigned charAlign = Types.getContext().getTargetInfo().getCharAlign();
-
- if (fieldOffset < nextFieldOffsetInBits && !BitsAvailableInLastField) {
- assert(fieldOffset % charAlign == 0 &&
- "Field offset not aligned correctly");
-
- CharUnits fieldOffsetInCharUnits =
- Types.getContext().toCharUnitsFromBits(fieldOffset);
+/// \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.getContext().getTargetInfo().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))
- nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- }
-
- if (fieldOffset < nextFieldOffsetInBits) {
- assert(BitsAvailableInLastField && "Bitfield size mismatch!");
- assert(!NextFieldOffset.isZero() && "Must have laid out at least one byte");
-
- // The bitfield begins in the previous bit-field.
- numBytesToAppend = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField,
- charAlign));
- } else {
- assert(fieldOffset % charAlign == 0 &&
- "Field offset not aligned correctly");
-
- // Append padding if necessary.
- AppendPadding(Types.getContext().toCharUnitsFromBits(fieldOffset),
- CharUnits::One());
+ if (!ResizeLastBaseFieldIfNecessary(FieldOffsetInCharUnits))
+ llvm_unreachable("We must be able to resize the last base if we need to "
+ "pack bits into it.");
- numBytesToAppend = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(fieldSize, charAlign));
-
- assert(!numBytesToAppend.isZero() && "No bytes to append!");
+ NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
+ assert(FirstFieldOffset >= NextFieldOffsetInBits);
}
- // Add the bit field info.
- BitFields.insert(std::make_pair(D,
- CGBitFieldInfo::MakeInfo(Types, D, fieldOffset, fieldSize)));
-
- AppendBytes(numBytesToAppend);
+ // 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.getContext().getTargetInfo().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));
+ }
- BitsAvailableInLastField =
- Types.getContext().toBits(NextFieldOffset) - (fieldOffset + fieldSize);
+ 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;
}
bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
@@ -429,15 +386,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
if (!Packed && D->hasAttr<PackedAttr>())
return false;
- if (D->isBitField()) {
- // We must use packed structs for unnamed bit fields since they
- // don't affect the struct alignment.
- if (!Packed && !D->getDeclName())
- return false;
-
- LayoutBitField(D, fieldOffset);
- return true;
- }
+ assert(!D->isBitField() && "Bitfields should be laid out seperately.");
CheckZeroInitializable(D->getType());
@@ -497,6 +446,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
llvm::Type *
CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
const ASTRecordLayout &Layout) {
+ Fields[Field] = 0;
if (Field->isBitField()) {
uint64_t FieldSize = Field->getBitWidthValue(Types.getContext());
@@ -504,22 +454,23 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
if (FieldSize == 0)
return 0;
- llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
- CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(FieldSize,
- Types.getContext().getTargetInfo().getCharAlign()));
+ unsigned StorageBits = llvm::RoundUpToAlignment(
+ FieldSize, Types.getContext().getTargetInfo().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.insert(std::make_pair(Field,
- CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize)));
+ BitFields[Field] = CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize,
+ StorageBits,
+ Alignment.getQuantity());
return FieldTy;
}
// This is a regular union field.
- Fields[Field] = 0;
return Types.ConvertTypeForMem(Field->getType());
}
@@ -815,20 +766,38 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
unsigned FieldNo = 0;
const FieldDecl *LastFD = 0;
- for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ for (RecordDecl::field_iterator FI = D->field_begin(), FE = D->field_end();
+ FI != FE; ++FI, ++FieldNo) {
+ FieldDecl *FD = *FI;
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are
// ignored:
- const FieldDecl *FD = *Field;
if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
--FieldNo;
continue;
}
LastFD = FD;
}
-
- if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) {
+
+ // 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)
+ 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;
@@ -845,7 +814,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Lay out the virtual bases. The MS ABI uses a different
// algorithm here due to the lack of primary virtual bases.
- if (Types.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ if (Types.getContext().getTargetInfo().getCXXABI().hasPrimaryVBases()) {
RD->getIndirectPrimaryBases(IndirectPrimaryBases);
if (Layout.isPrimaryBaseVirtual())
IndirectPrimaryBases.insert(Layout.getPrimaryBase());
@@ -889,7 +858,6 @@ void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset,
FieldTypes.push_back(fieldType);
NextFieldOffset = fieldOffset + fieldSize;
- BitsAvailableInLastField = 0;
}
void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset,
@@ -1090,18 +1058,39 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
LastFD = FD;
continue;
}
-
+
+ // Don't inspect zero-length bitfields.
+ if (FD->getBitWidthValue(getContext()) == 0)
+ continue;
+
const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
- for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
- const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
-
- // Verify that every component access is within the structure.
- uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex);
- uint64_t AccessBitOffset = FieldOffset +
- getContext().toBits(AI.FieldByteOffset);
- assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits &&
- "Invalid bit-field access (out of range)!");
+ llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD));
+
+ // Unions have overlapping elements dictating their layout, but for
+ // non-unions we can verify that this section of the layout is the exact
+ // expected size.
+ if (D->isUnion()) {
+ // For unions we verify that the start is zero and the size
+ // is in-bounds. However, on BE systems, the offset may be non-zero, but
+ // the size + offset should match the storage size in that case as it
+ // "starts" at the back.
+ if (getDataLayout().isBigEndian())
+ assert(static_cast<unsigned>(Info.Offset + Info.Size) ==
+ Info.StorageSize &&
+ "Big endian union bitfield does not end at the back");
+ else
+ assert(Info.Offset == 0 &&
+ "Little endian union bitfield with a non-zero offset");
+ assert(Info.StorageSize <= SL->getSizeInBits() &&
+ "Union not large enough for bitfield storage");
+ } else {
+ assert(Info.StorageSize ==
+ getDataLayout().getTypeAllocSizeInBits(ElementTy) &&
+ "Storage size does not match the element type size");
}
+ assert(Info.Size > 0 && "Empty bitfield!");
+ assert(static_cast<unsigned>(Info.Offset) + Info.Size <= Info.StorageSize &&
+ "Bitfield outside of its allocated storage");
}
#endif
@@ -1143,32 +1132,12 @@ void CGRecordLayout::dump() const {
}
void CGBitFieldInfo::print(raw_ostream &OS) const {
- OS << "<CGBitFieldInfo";
- OS << " Size:" << Size;
- OS << " IsSigned:" << IsSigned << "\n";
-
- OS.indent(4 + strlen("<CGBitFieldInfo"));
- OS << " NumComponents:" << getNumComponents();
- OS << " Components: [";
- if (getNumComponents()) {
- OS << "\n";
- for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
- const AccessInfo &AI = getComponent(i);
- OS.indent(8);
- OS << "<AccessInfo"
- << " FieldIndex:" << AI.FieldIndex
- << " FieldByteOffset:" << AI.FieldByteOffset.getQuantity()
- << " FieldBitStart:" << AI.FieldBitStart
- << " AccessWidth:" << AI.AccessWidth << "\n";
- OS.indent(8 + strlen("<AccessInfo"));
- OS << " AccessAlignment:" << AI.AccessAlignment.getQuantity()
- << " TargetBitOffset:" << AI.TargetBitOffset
- << " TargetBitWidth:" << AI.TargetBitWidth
- << ">\n";
- }
- OS.indent(4);
- }
- OS << "]>";
+ OS << "<CGBitFieldInfo"
+ << " Offset:" << Offset
+ << " Size:" << Size
+ << " IsSigned:" << IsSigned
+ << " StorageSize:" << StorageSize
+ << " StorageAlignment:" << StorageAlignment << ">";
}
void CGBitFieldInfo::dump() const {
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 3548dbac6fc1..3153ca8ca70f 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -11,17 +11,17 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenFunction.h"
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
-#include "CodeGenFunction.h"
#include "TargetInfo.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/InlineAsm.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -198,6 +198,12 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
// Keep track of the current cleanup stack depth, including debug scopes.
LexicalScope Scope(*this, S.getSourceRange());
+ return EmitCompoundStmtWithoutScope(S, GetLast, AggSlot);
+}
+
+RValue CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool GetLast,
+ AggValueSlot AggSlot) {
+
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
@@ -313,6 +319,12 @@ CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
}
void CodeGenFunction::EmitLabel(const LabelDecl *D) {
+ // Add this label to the current lexical scope if we're within any
+ // normal cleanups. Jumps "in" to this label --- when permitted by
+ // the language --- may need to be routed around such cleanups.
+ if (EHStack.hasNormalCleanups() && CurLexicalScope)
+ CurLexicalScope->addLabel(D);
+
JumpDest &Dest = LabelMap[D];
// If we didn't need a forward reference to this label, just go
@@ -324,16 +336,36 @@ void CodeGenFunction::EmitLabel(const LabelDecl *D) {
// it from the branch-fixups list.
} else {
assert(!Dest.getScopeDepth().isValid() && "already emitted label!");
- Dest = JumpDest(Dest.getBlock(),
- EHStack.stable_begin(),
- Dest.getDestIndex());
-
+ Dest.setScopeDepth(EHStack.stable_begin());
ResolveBranchFixups(Dest.getBlock());
}
EmitBlock(Dest.getBlock());
}
+/// Change the cleanup scope of the labels in this lexical scope to
+/// match the scope of the enclosing context.
+void CodeGenFunction::LexicalScope::rescopeLabels() {
+ assert(!Labels.empty());
+ EHScopeStack::stable_iterator innermostScope
+ = CGF.EHStack.getInnermostNormalCleanup();
+
+ // Change the scope depth of all the labels.
+ for (SmallVectorImpl<const LabelDecl*>::const_iterator
+ i = Labels.begin(), e = Labels.end(); i != e; ++i) {
+ assert(CGF.LabelMap.count(*i));
+ JumpDest &dest = CGF.LabelMap.find(*i)->second;
+ assert(dest.getScopeDepth().isValid());
+ assert(innermostScope.encloses(dest.getScopeDepth()));
+ dest.setScopeDepth(innermostScope);
+ }
+
+ // Reparent the labels if the new scope also has cleanups.
+ if (innermostScope != EHScopeStack::stable_end() && ParentScope) {
+ ParentScope->Labels.append(Labels.begin(), Labels.end());
+ }
+}
+
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
EmitLabel(S.getDecl());
@@ -735,7 +767,9 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
} else if (RV.isAggregate()) {
EmitAggregateCopy(ReturnValue, RV.getAggregateAddr(), Ty);
} else {
- StoreComplexToAddr(RV.getComplexVal(), ReturnValue, false);
+ EmitStoreOfComplex(RV.getComplexVal(),
+ MakeNaturalAlignAddrLValue(ReturnValue, Ty),
+ /*init*/ true);
}
EmitBranchThroughCleanup(ReturnBlock);
}
@@ -760,8 +794,7 @@ 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() &&
- !Target.useGlobalsForAutomaticVariables()) {
+ if (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.
@@ -782,16 +815,26 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// rather than the value.
RValue Result = EmitReferenceBindingToExpr(RV, /*InitializedDecl=*/0);
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
- } else if (!hasAggregateLLVMType(RV->getType())) {
- Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
- } else if (RV->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
- EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased));
+ switch (getEvaluationKind(RV->getType())) {
+ case TEK_Scalar:
+ Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
+ break;
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(RV,
+ MakeNaturalAlignAddrLValue(ReturnValue, RV->getType()),
+ /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
+ CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment,
+ Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
+ break;
+ }
+ }
}
cleanupScope.ForceCleanup();
@@ -1349,7 +1392,7 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
std::string &ConstraintStr) {
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
- if (!CodeGenFunction::hasAggregateLLVMType(InputType)) {
+ if (CodeGenFunction::hasScalarEvaluationKind(InputType)) {
Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
llvm::Type *Ty = ConvertType(InputType);
@@ -1378,7 +1421,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
const Expr *InputExpr,
std::string &ConstraintStr) {
if (Info.allowsRegister() || !Info.allowsMemory())
- if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType()))
+ if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
return EmitScalarExpr(InputExpr);
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
@@ -1473,7 +1516,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
- if (!Info.allowsMemory() && !hasAggregateLLVMType(OutExpr->getType())) {
+ if (!Info.allowsMemory() && hasScalarEvaluationKind(OutExpr->getType())) {
Constraints += "=" + OutputConstraint;
ResultRegQualTys.push_back(OutExpr->getType());
ResultRegDests.push_back(Dest);
@@ -1640,9 +1683,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
/* IsAlignStack */ false, AsmDialect);
llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(llvm::AttrListPtr::FunctionIndex,
- llvm::Attributes::get(getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind);
// Slap the source location of the inline asm into a !srcloc metadata on the
// call. FIXME: Handle metadata for MS-style inline asms.
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 5b37fe4b9634..069cd5f9e738 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
+#include "CodeGenModule.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
@@ -31,33 +31,6 @@ using namespace CodeGen;
CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
: CGM(CGM), VTContext(CGM.getContext()) { }
-bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) {
- assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
-
- TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
- if (TSK == TSK_ExplicitInstantiationDeclaration)
- return false;
-
- const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
- if (!KeyFunction)
- return true;
-
- // Itanium C++ ABI, 5.2.6 Instantiated Templates:
- // An instantiation of a class template requires:
- // - In the object where instantiated, the virtual table...
- if (TSK == TSK_ImplicitInstantiation ||
- TSK == TSK_ExplicitInstantiationDefinition)
- return true;
-
- // If we're building with optimization, we always emit VTables since that
- // allows for virtual function calls to be devirtualized.
- // (We don't want to do this in -fapple-kext mode however).
- if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
- return true;
-
- return KeyFunction->hasBody();
-}
-
llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -143,7 +116,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
return;
- if (MD->getExplicitVisibility())
+ if (MD->getExplicitVisibility(ValueDecl::VisibilityForValue))
return;
switch (MD->getTemplateSpecializationKind()) {
@@ -388,7 +361,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(CurFnInfo->getReturnType()))
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType()))
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
// Now emit our call.
@@ -645,9 +618,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
if (VTable)
return VTable;
- // We may need to generate a definition for this vtable.
- if (ShouldEmitVTableInThisTU(RD))
- CGM.DeferredVTables.push_back(RD);
+ // Queue up this v-table for possible deferred emission.
+ CGM.addDeferredVTable(RD);
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
@@ -714,6 +686,14 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
llvm::ArrayType *ArrayType =
llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents());
+ // Construction vtable symbols are not part of the Itanium ABI, so we cannot
+ // guarantee that they actually will be available externally. Instead, when
+ // emitting an available_externally VTT, we provide references to an internal
+ // linkage construction vtable. The ABI only requires complete-object vtables
+ // to be the same for all instances of a type, not construction vtables.
+ if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
+ Linkage = llvm::GlobalVariable::InternalLinkage;
+
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage);
@@ -734,18 +714,111 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
return VTable;
}
+/// Compute the required linkage of the v-table for the given class.
+///
+/// Note that we only call this at the end of the translation unit.
+llvm::GlobalVariable::LinkageTypes
+CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
+ if (RD->getLinkage() != ExternalLinkage)
+ return llvm::GlobalVariable::InternalLinkage;
+
+ // We're at the end of the translation unit, so the current key
+ // function is fully correct.
+ 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;
+ if (keyFunction->hasBody(def))
+ keyFunction = cast<CXXMethodDecl>(def);
+
+ switch (keyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ // When compiling with optimizations turned on, we emit all vtables,
+ // even if the key function is not defined in the current translation
+ // unit. If this is the case, use available_externally linkage.
+ if (!def && CodeGenOpts.OptimizationLevel)
+ return llvm::GlobalVariable::AvailableExternallyLinkage;
+
+ if (keyFunction->isInlined())
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::LinkOnceODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ return llvm::GlobalVariable::ExternalLinkage;
+
+ case TSK_ImplicitInstantiation:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::LinkOnceODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::WeakODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::AvailableExternallyLinkage :
+ llvm::Function::InternalLinkage;
+ }
+ }
+
+ // -fapple-kext mode does not support weak linkage, so we must use
+ // internal linkage.
+ if (Context.getLangOpts().AppleKext)
+ return llvm::Function::InternalLinkage;
+
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ImplicitInstantiation:
+ return llvm::GlobalVariable::LinkOnceODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return llvm::GlobalVariable::AvailableExternallyLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
+
+ llvm_unreachable("Invalid TemplateSpecializationKind!");
+}
+
+/// This is a callback from Sema to tell us that it believes that a
+/// particular v-table is required to be emitted in this translation
+/// unit.
+///
+/// The reason we don't simply trust this callback is because Sema
+/// will happily report that something is used even when it's used
+/// only in code that we don't actually have to emit.
+///
+/// \param isRequired - if true, the v-table is mandatory, e.g.
+/// because the translation unit defines the key function
+void CodeGenModule::EmitVTable(CXXRecordDecl *theClass, bool isRequired) {
+ if (!isRequired) return;
+
+ VTables.GenerateClassData(theClass);
+}
+
void
-CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
+CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
+ // First off, check whether we've already emitted the v-table and
+ // associated stuff.
llvm::GlobalVariable *VTable = GetAddrOfVTable(RD);
if (VTable->hasInitializer())
return;
+ llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
EmitVTableDefinition(VTable, Linkage, RD);
if (RD->getNumVBases()) {
- llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
- EmitVTTDefinition(VTT, Linkage, RD);
+ if (!CGM.getTarget().getCXXABI().isMicrosoft()) {
+ llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
+ EmitVTTDefinition(VTT, Linkage, RD);
+ } else {
+ // FIXME: Emit vbtables here.
+ }
}
// If this is the magic class __cxxabiv1::__fundamental_type_info,
@@ -760,3 +833,80 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
DC->getParent()->isTranslationUnit())
CGM.EmitFundamentalRTTIDescriptors();
}
+
+/// At this point in the translation unit, does it appear that can we
+/// rely on the vtable being defined elsewhere in the program?
+///
+/// The response is really only definitive when called at the end of
+/// the translation unit.
+///
+/// The only semantic restriction here is that the object file should
+/// not contain a v-table definition when that v-table is defined
+/// 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.");
+
+ // If we have an explicit instantiation declaration (and not a
+ // definition), the v-table is defined elsewhere.
+ TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ return true;
+
+ // Otherwise, if the class is an instantiated template, the
+ // v-table must be defined here.
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_ExplicitInstantiationDefinition)
+ return false;
+
+ // Otherwise, if the class doesn't have a key function (possibly
+ // anymore), the v-table must be defined here.
+ const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD);
+ if (!keyFunction)
+ return false;
+
+ // Otherwise, if we don't have a definition of the key function, the
+ // v-table must be defined somewhere else.
+ return !keyFunction->hasBody();
+}
+
+/// Given that we're currently at the end of the translation unit, and
+/// we've emitted a reference to the v-table for this class, should
+/// we define that v-table?
+static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
+ const CXXRecordDecl *RD) {
+ // If we're building with optimization, we always emit v-tables
+ // since that allows for virtual function calls to be devirtualized.
+ // If the v-table is defined strongly elsewhere, this definition
+ // will be emitted available_externally.
+ //
+ // However, we don't want to do this in -fapple-kext mode, because
+ // kext mode does not permit devirtualization.
+ if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
+ return true;
+
+ return !CGM.getVTables().isVTableExternal(RD);
+}
+
+/// Given that at some point we emitted a reference to one or more
+/// v-tables, and that we are now at the end of the translation unit,
+/// decide whether we should emit them.
+void CodeGenModule::EmitDeferredVTables() {
+#ifndef NDEBUG
+ // Remember the size of DeferredVTables, because we're going to assume
+ // that this entire operation doesn't modify it.
+ size_t savedSize = DeferredVTables.size();
+#endif
+
+ typedef std::vector<const CXXRecordDecl *>::const_iterator const_iterator;
+ for (const_iterator i = DeferredVTables.begin(),
+ e = DeferredVTables.end(); i != e; ++i) {
+ const CXXRecordDecl *RD = *i;
+ if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
+ VTables.GenerateClassData(RD);
+ }
+
+ assert(savedSize == DeferredVTables.size() &&
+ "deferred extra v-tables during v-table emission?");
+ DeferredVTables.clear();
+}
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 828330e5e3c4..bd3bdb13583d 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -14,13 +14,13 @@
#ifndef CLANG_CODEGEN_CGVTABLE_H
#define CLANG_CODEGEN_CGVTABLE_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/GlobalVariable.h"
-#include "clang/Basic/ABI.h"
#include "clang/AST/BaseSubobject.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/VTableBuilder.h"
+#include "clang/Basic/ABI.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/GlobalVariable.h"
namespace clang {
class CXXRecordDecl;
@@ -77,10 +77,6 @@ public:
VTableContext &getVTableContext() { return VTContext; }
- /// \brief True if the VTable of this record must be emitted in the
- /// translation unit.
- bool ShouldEmitVTableInThisTU(const CXXRecordDecl *RD);
-
/// needsVTTParameter - Return whether the given global decl needs a VTT
/// parameter, which it does if it's a base constructor or destructor with
/// virtual bases.
@@ -127,13 +123,13 @@ public:
/// EmitThunks - Emit the associated thunks for the given global decl.
void EmitThunks(GlobalDecl GD);
- /// GenerateClassData - Generate all the class data required to be generated
- /// upon definition of a KeyFunction. This includes the vtable, the
- /// rtti data structure and the VTT.
- ///
- /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT.
- void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD);
+ /// GenerateClassData - Generate all the class data required to be
+ /// generated upon definition of a KeyFunction. This includes the
+ /// vtable, the RTTI data structure (if RTTI is enabled) and the VTT
+ /// (if the class has virtual bases).
+ void GenerateClassData(const CXXRecordDecl *RD);
+
+ bool isVTableExternal(const CXXRecordDecl *RD);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index c2b8e4da820c..b625b866c072 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -18,16 +18,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
+#include "llvm/IR/Value.h"
namespace llvm {
class Constant;
- class Value;
+ class MDNode;
}
namespace clang {
namespace CodeGen {
class AggValueSlot;
- class CGBitFieldInfo;
+ struct CGBitFieldInfo;
/// RValue - This trivial value class is used to represent the result of an
/// expression that is evaluated. It can be one of three things: either a
@@ -96,6 +97,10 @@ public:
}
};
+/// Does an ARC strong l-value have precise lifetime?
+enum ARCPreciseLifetime_t {
+ ARCImpreciseLifetime, ARCPreciseLifetime
+};
/// LValue - This represents an lvalue references. Because C/C++ allow
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
@@ -146,8 +151,17 @@ class LValue {
// Lvalue is a thread local reference
bool ThreadLocalRef : 1;
+ // Lvalue has ARC imprecise lifetime. We store this inverted to try
+ // to make the default bitfield pattern all-zeroes.
+ bool ImpreciseLifetime : 1;
+
Expr *BaseIvarExp;
+ /// Used by struct-path-aware TBAA.
+ QualType TBAABaseType;
+ /// Offset relative to the base type.
+ uint64_t TBAAOffset;
+
/// TBAAInfo - TBAA information to attach to dereferences of this LValue.
llvm::MDNode *TBAAInfo;
@@ -163,8 +177,13 @@ private:
// Initialize Objective-C flags.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
+ this->ImpreciseLifetime = false;
this->ThreadLocalRef = false;
this->BaseIvarExp = 0;
+
+ // Initialize fields for TBAA.
+ this->TBAABaseType = Type;
+ this->TBAAOffset = 0;
this->TBAAInfo = TBAAInfo;
}
@@ -201,6 +220,13 @@ public:
bool isThreadLocalRef() const { return ThreadLocalRef; }
void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;}
+ ARCPreciseLifetime_t isARCPreciseLifetime() const {
+ return ARCPreciseLifetime_t(!ImpreciseLifetime);
+ }
+ void setARCPreciseLifetime(ARCPreciseLifetime_t value) {
+ ImpreciseLifetime = (value == ARCImpreciseLifetime);
+ }
+
bool isObjCWeak() const {
return Quals.getObjCGCAttr() == Qualifiers::Weak;
}
@@ -215,6 +241,12 @@ public:
Expr *getBaseIvarExp() const { return BaseIvarExp; }
void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
+ QualType getTBAABaseType() const { return TBAABaseType; }
+ void setTBAABaseType(QualType T) { TBAABaseType = T; }
+
+ uint64_t getTBAAOffset() const { return TBAAOffset; }
+ void setTBAAOffset(uint64_t O) { TBAAOffset = O; }
+
llvm::MDNode *getTBAAInfo() const { return TBAAInfo; }
void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; }
@@ -245,7 +277,7 @@ public:
}
// bitfield lvalue
- llvm::Value *getBitFieldBaseAddr() const {
+ llvm::Value *getBitFieldAddr() const {
assert(isBitField());
return V;
}
@@ -289,16 +321,16 @@ public:
/// \brief Create a new object to represent a bit-field access.
///
- /// \param BaseValue - The base address of the structure containing the
- /// bit-field.
+ /// \param Addr - The base address of the bit-field sequence this
+ /// bit-field refers to.
/// \param Info - The information describing how to perform the bit-field
/// access.
- static LValue MakeBitfield(llvm::Value *BaseValue,
+ static LValue MakeBitfield(llvm::Value *Addr,
const CGBitFieldInfo &Info,
QualType type, CharUnits Alignment) {
LValue R;
R.LVType = BitField;
- R.V = BaseValue;
+ R.V = Addr;
R.BitFieldInfo = &Info;
R.Initialize(type, type.getQualifiers(), Alignment);
return R;
@@ -349,11 +381,23 @@ class AggValueSlot {
/// evaluating an expression which constructs such an object.
bool AliasedFlag : 1;
+ /// ValueOfAtomicFlag - This is set to true if the slot is the value
+ /// subobject of an object the size of an _Atomic(T). The specific
+ /// guarantees this makes are:
+ /// - the address is guaranteed to be a getelementptr into the
+ /// padding struct and
+ /// - it is okay to store something the width of an _Atomic(T)
+ /// into the address.
+ /// Tracking this allows us to avoid some obviously unnecessary
+ /// memcpys.
+ bool ValueOfAtomicFlag : 1;
+
public:
enum IsAliased_t { IsNotAliased, IsAliased };
enum IsDestructed_t { IsNotDestructed, IsDestructed };
enum IsZeroed_t { IsNotZeroed, IsZeroed };
enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
+ enum IsValueOfAtomic_t { IsNotValueOfAtomic, IsValueOfAtomic };
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
@@ -377,7 +421,9 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed) {
+ IsZeroed_t isZeroed = IsNotZeroed,
+ IsValueOfAtomic_t isValueOfAtomic
+ = IsNotValueOfAtomic) {
AggValueSlot AV;
AV.Addr = addr;
AV.Alignment = align.getQuantity();
@@ -386,6 +432,7 @@ public:
AV.ObjCGCFlag = needsGC;
AV.ZeroedFlag = isZeroed;
AV.AliasedFlag = isAliased;
+ AV.ValueOfAtomicFlag = isValueOfAtomic;
return AV;
}
@@ -393,9 +440,12 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed) {
+ IsZeroed_t isZeroed = IsNotZeroed,
+ IsValueOfAtomic_t isValueOfAtomic
+ = IsNotValueOfAtomic) {
return forAddr(LV.getAddress(), LV.getAlignment(),
- LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed);
+ LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed,
+ isValueOfAtomic);
}
IsDestructed_t isExternallyDestructed() const {
@@ -411,6 +461,10 @@ public:
return Quals.hasVolatile();
}
+ void setVolatile(bool flag) {
+ Quals.setVolatile(flag);
+ }
+
Qualifiers::ObjCLifetime getObjCLifetime() const {
return Quals.getObjCLifetime();
}
@@ -423,6 +477,12 @@ public:
return Addr;
}
+ IsValueOfAtomic_t isValueOfAtomic() const {
+ return IsValueOfAtomic_t(ValueOfAtomicFlag);
+ }
+
+ llvm::Value *getPaddedAtomicAddr() const;
+
bool isIgnored() const {
return Addr == 0;
}
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 76be85f939a3..9ca2295a9229 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
asmparser
bitreader
bitwriter
+ irreader
instrumentation
ipo
linker
@@ -10,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangCodeGen
BackendUtil.cpp
+ CGAtomic.cpp
CGBlocks.cpp
CGBuiltin.cpp
CGCall.cpp
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 9d6d183d97d9..679cfeb6ed3c 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -8,24 +8,24 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenAction.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Linker.h"
-#include "llvm/Module.h"
-#include "llvm/Pass.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/ReaderWriter.h"
-#include "llvm/Support/IRReader.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Linker.h"
+#include "llvm/Pass.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Timer.h"
@@ -67,7 +67,7 @@ namespace clang {
AsmOutStream(OS),
Context(),
LLVMIRGeneration("LLVM IR Generation Time"),
- Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts, targetopts, C)),
LinkModule(LinkModule)
{
llvm::TimePassesIsEnabled = TimePasses;
@@ -398,7 +398,7 @@ void CodeGenAction::ExecuteAction() {
Msg = Msg.substr(7);
// Escape '%', which is interpreted as a format character.
- llvm::SmallString<128> EscapedMessage;
+ SmallString<128> EscapedMessage;
for (unsigned i = 0, e = Msg.size(); i != e; ++i) {
if (Msg[i] == '%')
EscapedMessage += '%';
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 18f1623d242e..2c3cabe98510 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -12,19 +12,21 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
-#include "clang/Basic/TargetInfo.h"
+#include "CodeGenModule.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/Frontend/CodeGenOptions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/MDBuilder.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Operator.h"
using namespace clang;
using namespace CodeGen;
@@ -32,20 +34,32 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm),
Target(CGM.getContext().getTargetInfo()),
Builder(cgm.getModule().getContext()),
- SanitizePerformTypeCheck(CGM.getLangOpts().SanitizeNull |
- CGM.getLangOpts().SanitizeAlignment |
- CGM.getLangOpts().SanitizeObjectSize |
- CGM.getLangOpts().SanitizeVptr),
+ 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(0), DisableDebugInfo(false), DidCallStackSave(false),
+ DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
+ DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
- CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0),
- CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0),
+ CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
+ CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
+ OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0),
TerminateHandler(0), TrapBB(0) {
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
+
+ llvm::FastMathFlags FMF;
+ if (CGM.getLangOpts().FastMath)
+ FMF.setUnsafeAlgebra();
+ if (CGM.getLangOpts().FiniteMathOnly) {
+ FMF.setNoNaNs();
+ FMF.setNoInfs();
+ }
+ Builder.SetFastMathFlags(FMF);
}
CodeGenFunction::~CodeGenFunction() {
@@ -65,45 +79,53 @@ llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
-bool CodeGenFunction::hasAggregateLLVMType(QualType type) {
- switch (type.getCanonicalType()->getTypeClass()) {
+TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
+ type = type.getCanonicalType();
+ while (true) {
+ switch (type->getTypeClass()) {
#define TYPE(name, parent)
#define ABSTRACT_TYPE(name, parent)
#define NON_CANONICAL_TYPE(name, parent) case Type::name:
#define DEPENDENT_TYPE(name, parent) case Type::name:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
#include "clang/AST/TypeNodes.def"
- llvm_unreachable("non-canonical or dependent type in IR-generation");
-
- case Type::Builtin:
- case Type::Pointer:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- case Type::Enum:
- case Type::ObjCObjectPointer:
- return false;
+ llvm_unreachable("non-canonical or dependent type in IR-generation");
- // Complexes, arrays, records, and Objective-C objects.
- case Type::Complex:
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::Record:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- return true;
+ // Various scalar types.
+ case Type::Builtin:
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Enum:
+ case Type::ObjCObjectPointer:
+ return TEK_Scalar;
- // In IRGen, atomic types are just the underlying type
- case Type::Atomic:
- return hasAggregateLLVMType(type->getAs<AtomicType>()->getValueType());
+ // Complexes.
+ case Type::Complex:
+ return TEK_Complex;
+
+ // Arrays, records, and Objective-C objects.
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Record:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ return TEK_Aggregate;
+
+ // We operate on atomic values according to their underlying type.
+ case Type::Atomic:
+ type = cast<AtomicType>(type)->getValueType();
+ continue;
+ }
+ llvm_unreachable("unknown type kind!");
}
- llvm_unreachable("unknown type kind!");
}
void CodeGenFunction::EmitReturnBlock() {
@@ -132,7 +154,10 @@ void CodeGenFunction::EmitReturnBlock() {
dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->use_begin());
if (BI && BI->isUnconditional() &&
BI->getSuccessor(0) == ReturnBlock.getBlock()) {
- // Reset insertion point, including debug location, and delete the branch.
+ // Reset insertion point, including debug location, and delete the
+ // branch. This is really subtle and only works because the next change
+ // in location will hit the caching in CGDebugInfo::EmitLocation and not
+ // override this.
Builder.SetCurrentDebugLocation(BI->getDebugLoc());
Builder.SetInsertPoint(BI->getParent());
BI->eraseFromParent();
@@ -159,6 +184,9 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitLocation(Builder, EndLoc);
+
// Pop any cleanups that might have been associated with the
// parameters. Do this in whatever block we're currently in; it's
// important to do this before we enter the return block or return
@@ -174,7 +202,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Emit debug descriptor for function end.
if (CGDebugInfo *DI = getDebugInfo()) {
- DI->setLocation(EndLoc);
DI->EmitFunctionEnd(Builder);
}
@@ -190,12 +217,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
EmitBlock(IndirectBranch->getParent());
Builder.ClearInsertionPoint();
}
-
+
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
llvm::Instruction *Ptr = AllocaInsertPt;
AllocaInsertPt = 0;
Ptr->eraseFromParent();
-
+
// If someone took the address of a label but never did an indirect goto, we
// made a zero entry PHI node, which is illegal, zap it now.
if (IndirectBranch) {
@@ -241,9 +268,12 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
llvm::ConstantInt::get(Int32Ty, 0),
"callsite");
- Builder.CreateCall2(F,
- llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
- CallSite);
+ llvm::Value *args[] = {
+ llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
+ CallSite
+ };
+
+ EmitNounwindRuntimeCall(F, args);
}
void CodeGenFunction::EmitMCountInstrumentation() {
@@ -251,37 +281,114 @@ void CodeGenFunction::EmitMCountInstrumentation() {
llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy,
Target.getMCountName());
- Builder.CreateCall(MCountFn);
+ EmitNounwindRuntimeCall(MCountFn);
}
// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
// information in the program executable. The argument information stored
// includes the argument name, its type, the address and access qualifiers used.
-// FIXME: Add type, address, and access qualifiers.
static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
CodeGenModule &CGM,llvm::LLVMContext &Context,
- llvm::SmallVector <llvm::Value*, 5> &kernelMDArgs) {
-
- // Create MDNodes that represents the kernel arg metadata.
+ SmallVector <llvm::Value*, 5> &kernelMDArgs,
+ CGBuilderTy& Builder, ASTContext &ASTCtx) {
+ // Create MDNodes that represent the kernel arg metadata.
// 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.
-
+
+ // MDNode for the kernel argument address space qualifiers.
+ SmallVector<llvm::Value*, 8> addressQuals;
+ addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space"));
+
+ // MDNode for the kernel argument access qualifiers (images only).
+ SmallVector<llvm::Value*, 8> accessQuals;
+ accessQuals.push_back(llvm::MDString::get(Context, "kernel_arg_access_qual"));
+
+ // MDNode for the kernel argument type names.
+ SmallVector<llvm::Value*, 8> argTypeNames;
+ argTypeNames.push_back(llvm::MDString::get(Context, "kernel_arg_type"));
+
+ // MDNode for the kernel argument type qualifiers.
+ SmallVector<llvm::Value*, 8> argTypeQuals;
+ argTypeQuals.push_back(llvm::MDString::get(Context, "kernel_arg_type_qual"));
+
// MDNode for the kernel argument names.
SmallVector<llvm::Value*, 8> argNames;
argNames.push_back(llvm::MDString::get(Context, "kernel_arg_name"));
-
+
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
const ParmVarDecl *parm = FD->getParamDecl(i);
+ QualType ty = parm->getType();
+ std::string typeQuals;
+
+ if (ty->isPointerType()) {
+ QualType pointeeTy = ty->getPointeeType();
+
+ // Get address qualifier.
+ addressQuals.push_back(Builder.getInt32(ASTCtx.getTargetAddressSpace(
+ pointeeTy.getAddressSpace())));
+
+ // Get argument type name.
+ std::string typeName = pointeeTy.getUnqualifiedType().getAsString() + "*";
+
+ // Turn "unsigned type" to "utype"
+ std::string::size_type pos = typeName.find("unsigned");
+ if (pos != std::string::npos)
+ typeName.erase(pos+1, 8);
+
+ argTypeNames.push_back(llvm::MDString::get(Context, typeName));
+
+ // Get argument type qualifiers:
+ if (ty.isRestrictQualified())
+ typeQuals = "restrict";
+ if (pointeeTy.isConstQualified() ||
+ (pointeeTy.getAddressSpace() == LangAS::opencl_constant))
+ typeQuals += typeQuals.empty() ? "const" : " const";
+ if (pointeeTy.isVolatileQualified())
+ typeQuals += typeQuals.empty() ? "volatile" : " volatile";
+ } else {
+ addressQuals.push_back(Builder.getInt32(0));
+
+ // Get argument type name.
+ std::string typeName = ty.getUnqualifiedType().getAsString();
+
+ // Turn "unsigned type" to "utype"
+ std::string::size_type pos = typeName.find("unsigned");
+ if (pos != std::string::npos)
+ typeName.erase(pos+1, 8);
+
+ argTypeNames.push_back(llvm::MDString::get(Context, typeName));
+
+ // Get argument type qualifiers:
+ if (ty.isConstQualified())
+ typeQuals = "const";
+ 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)
+ accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
+ else
+ accessQuals.push_back(llvm::MDString::get(Context, "read_only"));
+ } else
+ accessQuals.push_back(llvm::MDString::get(Context, "none"));
+
// Get argument name.
argNames.push_back(llvm::MDString::get(Context, parm->getName()));
-
}
- // Add MDNode to the list of all metadata.
+
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, addressQuals));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, accessQuals));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeNames));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeQuals));
kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames));
}
-void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
+void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::Function *Fn)
{
if (!FD->hasAttr<OpenCLKernelAttr>())
@@ -289,37 +396,49 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::LLVMContext &Context = getLLVMContext();
- llvm::SmallVector <llvm::Value*, 5> kernelMDArgs;
+ SmallVector <llvm::Value*, 5> kernelMDArgs;
kernelMDArgs.push_back(Fn);
if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
- GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs);
-
+ GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs,
+ Builder, getContext());
+
+ if (FD->hasAttr<VecTypeHintAttr>()) {
+ VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>();
+ QualType hintQTy = attr->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::ConstantInt::get(
+ llvm::IntegerType::get(Context, 32),
+ llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0)))
+ };
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
+ }
+
if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
- llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
- attrMDArgs.push_back(llvm::MDString::get(Context, "work_group_size_hint"));
WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>();
- llvm::Type *iTy = llvm::IntegerType::get(Context, 32);
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getXDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getYDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getZDim())));
+ llvm::Value *attrMDArgs[] = {
+ llvm::MDString::get(Context, "work_group_size_hint"),
+ Builder.getInt32(attr->getXDim()),
+ Builder.getInt32(attr->getYDim()),
+ Builder.getInt32(attr->getZDim())
+ };
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
- llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
- attrMDArgs.push_back(llvm::MDString::get(Context, "reqd_work_group_size"));
ReqdWorkGroupSizeAttr *attr = FD->getAttr<ReqdWorkGroupSizeAttr>();
- llvm::Type *iTy = llvm::IntegerType::get(Context, 32);
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getXDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getYDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getZDim())));
+ llvm::Value *attrMDArgs[] = {
+ llvm::MDString::get(Context, "reqd_work_group_size"),
+ Builder.getInt32(attr->getXDim()),
+ Builder.getInt32(attr->getYDim()),
+ Builder.getInt32(attr->getZDim())
+ };
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
@@ -335,7 +454,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const FunctionArgList &Args,
SourceLocation StartLoc) {
const Decl *D = GD.getDecl();
-
+
DidCallStackSave = false;
CurCodeDecl = CurFuncDecl = D;
FnRetTy = RetTy;
@@ -343,14 +462,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");
+ 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 (!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)
if (RI->isInlineSpecified()) {
- Fn->addFnAttr(llvm::Attributes::InlineHint);
+ Fn->addFnAttr(llvm::Attribute::InlineHint);
break;
}
@@ -376,19 +500,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
- unsigned NumArgs = 0;
- QualType *ArgsArray = new QualType[Args.size()];
+ SmallVector<QualType, 16> ArgTypes;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) {
- ArgsArray[NumArgs++] = (*i)->getType();
+ ArgTypes.push_back((*i)->getType());
}
QualType FnType =
- getContext().getFunctionType(RetTy, ArgsArray, NumArgs,
+ getContext().getFunctionType(RetTy, ArgTypes,
FunctionProtoType::ExtProtoInfo());
- delete[] ArgsArray;
-
DI->setLocation(StartLoc);
DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
}
@@ -403,7 +524,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Void type; nothing to return.
ReturnValue = 0;
} else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(CurFnInfo->getReturnType())) {
+ !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();
@@ -454,7 +575,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// emit the type size.
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) {
- QualType Ty = (*i)->getType();
+ const VarDecl *VD = *i;
+
+ // Dig out the type as written from ParmVarDecls; it's unclear whether
+ // the standard (C99 6.9.1p10) requires this, but we're following the
+ // precedent set by gcc.
+ QualType Ty;
+ if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD))
+ Ty = PVD->getOriginalType();
+ else
+ Ty = VD->getType();
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
@@ -467,7 +597,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl());
assert(FD->getBody());
- EmitStmt(FD->getBody());
+ if (const CompoundStmt *S = dyn_cast<CompoundStmt>(FD->getBody()))
+ EmitCompoundStmtWithoutScope(*S);
+ else
+ EmitStmt(FD->getBody());
}
/// Tries to mark the given function nounwind based on the
@@ -493,7 +626,7 @@ static void TryMarkNoThrow(llvm::Function *F) {
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-
+
// Check if we should generate debug info for this function.
if (!FD->hasAttr<NoDebugAttr>())
maybeInitializeDebugInfo();
@@ -511,6 +644,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
+ // CalleeWithThisReturn keeps track of the last callee inside this function
+ // that returns 'this'. Before starting the function, we set it to null.
+ CalleeWithThisReturn = 0;
+
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@@ -533,6 +670,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// The lambda "__invoke" function is special, because it forwards or
// clones the body of the function call operator (but is actually static).
EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
+ } else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator()) {
+ // Implicit copy-assignment gets the same special treatment as implicit
+ // copy-constructors.
+ emitImplicitAssignmentOperatorBody(Args);
}
else
EmitFunctionBody(Args);
@@ -545,10 +687,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// function call is used by the caller, the behavior is undefined.
if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
!FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
- if (getLangOpts().SanitizeReturn)
+ if (SanOpts->Return)
EmitCheck(Builder.getFalse(), "missing_return",
EmitCheckSourceLocation(FD->getLocation()),
- llvm::ArrayRef<llvm::Value*>());
+ ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
Builder.CreateUnreachable();
@@ -557,6 +699,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
+ // CalleeWithThisReturn keeps track of the last callee inside this function
+ // that returns 'this'. After finishing the function, we set it to null.
+ CalleeWithThisReturn = 0;
// If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can.
@@ -578,7 +723,7 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
// can't jump to one from outside their declared region.
if (isa<LabelStmt>(S))
return true;
-
+
// If this is a case/default statement, and we haven't seen a switch, we have
// to emit the code.
if (isa<SwitchCase>(S) && !IgnoreCaseStmts)
@@ -608,15 +753,15 @@ bool CodeGenFunction::containsBreak(const Stmt *S) {
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S) ||
isa<ForStmt>(S))
return false;
-
+
if (isa<BreakStmt>(S))
return true;
-
+
// Scan subexpressions for verboten breaks.
for (Stmt::const_child_range I = S->children(); I; ++I)
if (containsBreak(*I))
return true;
-
+
return false;
}
@@ -629,7 +774,7 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
llvm::APSInt ResultInt;
if (!ConstantFoldsToSimpleInteger(Cond, ResultInt))
return false;
-
+
ResultBool = ResultInt.getBoolValue();
return true;
}
@@ -698,7 +843,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
return;
}
-
+
if (CondBOp->getOpcode() == BO_LOr) {
// If we have "0 || X", simplify the code. "1 || X" would have constant
// folded if the case was simple enough.
@@ -781,7 +926,7 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
/// base element of the array
/// \param sizeInChars - the total size of the VLA, in chars
static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
- llvm::Value *dest, llvm::Value *src,
+ llvm::Value *dest, llvm::Value *src,
llvm::Value *sizeInChars) {
std::pair<CharUnits,CharUnits> baseSizeAndAlign
= CGF.getContext().getTypeInfoInChars(baseType);
@@ -821,7 +966,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
cur->addIncoming(next, loopBB);
CGF.EmitBlock(contBB);
-}
+}
void
CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
@@ -841,7 +986,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
DestPtr = Builder.CreateBitCast(DestPtr, BP);
// Get size and alignment info for this aggregate.
- std::pair<CharUnits, CharUnits> TypeInfo =
+ std::pair<CharUnits, CharUnits> TypeInfo =
getContext().getTypeInfoInChars(Ty);
CharUnits Size = TypeInfo.first;
CharUnits Align = TypeInfo.second;
@@ -882,9 +1027,9 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty);
- llvm::GlobalVariable *NullVariable =
+ llvm::GlobalVariable *NullVariable =
new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(),
- /*isConstant=*/true,
+ /*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
NullConstant, Twine());
llvm::Value *SrcPtr =
@@ -895,12 +1040,12 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
// Get and call the appropriate llvm.memcpy overload.
Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align.getQuantity(), false);
return;
- }
-
+ }
+
// Otherwise, just memset the whole thing to zero. This is legal
// because in LLVM, all default initializers (other than the ones we just
// handled above) are guaranteed to have a bit pattern of all zeros.
- Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal,
+ Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal,
Align.getQuantity(), false);
}
@@ -908,9 +1053,9 @@ llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
// Make sure that there is a block for the indirect goto.
if (IndirectBranch == 0)
GetIndirectGotoBlock();
-
+
llvm::BasicBlock *BB = getJumpDestForLabel(L).getBlock();
-
+
// Make sure the indirect branch includes all of the address-taken blocks.
IndirectBranch->addDestination(BB);
return llvm::BlockAddress::get(CurFn, BB);
@@ -919,13 +1064,13 @@ llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
// If we already made the indirect branch for indirect goto, return its block.
if (IndirectBranch) return IndirectBranch->getParent();
-
+
CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto"));
-
+
// Create the PHI node that indirect gotos will add entries to.
llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, 0,
"indirect.goto.dest");
-
+
// Create the indirect branch instruction.
IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal);
return IndirectBranch->getParent();
@@ -1130,7 +1275,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// If the size is an expression that is not an integer constant
// expression [...] each time it is evaluated it shall have a value
// greater than zero.
- if (getLangOpts().SanitizeVLABound &&
+ if (SanOpts->VLABound &&
size->getType()->isSignedIntegerType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
llvm::Constant *StaticArgs[] = {
@@ -1138,7 +1283,8 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
EmitCheckTypeDescriptor(size->getType())
};
EmitCheck(Builder.CreateICmpSGT(Size, Zero),
- "vla_bound_not_positive", StaticArgs, Size);
+ "vla_bound_not_positive", StaticArgs, Size,
+ CRK_Recoverable);
}
// Always zexting here would be wrong if it weren't
@@ -1188,7 +1334,7 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
return EmitLValue(E).getAddress();
}
-void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
+void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
llvm::Constant *Init) {
assert (Init && "Invalid DeclRefExpr initializer!");
if (CGDebugInfo *Dbg = getDebugInfo())
@@ -1225,7 +1371,7 @@ void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) {
llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn,
llvm::Value *AnnotatedVal,
- llvm::StringRef AnnotationStr,
+ StringRef AnnotationStr,
SourceLocation Location) {
llvm::Value *Args[4] = {
AnnotatedVal,
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index f2ab226ab530..645d5ff23785 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -14,22 +14,22 @@
#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H
#define CLANG_CODEGEN_CODEGENFUNCTION_H
-#include "clang/AST/Type.h"
+#include "CGBuilder.h"
+#include "CGDebugInfo.h"
+#include "CGValue.h"
+#include "CodeGenModule.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/Debug.h"
-#include "CodeGenModule.h"
-#include "CGBuilder.h"
-#include "CGDebugInfo.h"
-#include "CGValue.h"
+#include "llvm/Support/ValueHandle.h"
namespace llvm {
class BasicBlock;
@@ -78,6 +78,17 @@ namespace CodeGen {
class BlockFlags;
class BlockFieldFlags;
+/// The kind of evaluation to perform on values of a particular
+/// type. Basically, is the code in CGExprScalar, CGExprComplex, or
+/// CGExprAgg?
+///
+/// TODO: should vectors maybe be split out into their own thing?
+enum TypeEvaluationKind {
+ TEK_Scalar,
+ TEK_Complex,
+ TEK_Aggregate
+};
+
/// A branch fixup. These are required when emitting a goto to a
/// label which hasn't been emitted yet. The goto is optimistically
/// emitted as a branch to the basic block for the label, and (if it
@@ -551,6 +562,11 @@ public:
EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; }
unsigned getDestIndex() const { return Index; }
+ // This should be used cautiously.
+ void setScopeDepth(EHScopeStack::stable_iterator depth) {
+ ScopeDepth = depth;
+ }
+
private:
llvm::BasicBlock *Block;
EHScopeStack::stable_iterator ScopeDepth;
@@ -598,6 +614,9 @@ public:
/// calls to EmitTypeCheck can be skipped.
bool SanitizePerformTypeCheck;
+ /// \brief Sanitizer options to use for this function.
+ const SanitizerOptions *SanOpts;
+
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
@@ -793,14 +812,16 @@ public:
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth;
bool OldDidCallStackSave;
+ protected:
bool PerformCleanup;
+ private:
RunCleanupsScope(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
void operator=(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
protected:
CodeGenFunction& CGF;
-
+
public:
/// \brief Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
@@ -837,7 +858,8 @@ public:
class LexicalScope: protected RunCleanupsScope {
SourceRange Range;
- bool PopDebugStack;
+ SmallVector<const LabelDecl*, 4> Labels;
+ LexicalScope *ParentScope;
LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION;
void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION;
@@ -845,29 +867,39 @@ public:
public:
/// \brief Enter a new cleanup scope.
explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range)
- : RunCleanupsScope(CGF), Range(Range), PopDebugStack(true) {
+ : RunCleanupsScope(CGF), Range(Range), ParentScope(CGF.CurLexicalScope) {
+ CGF.CurLexicalScope = this;
if (CGDebugInfo *DI = CGF.getDebugInfo())
DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin());
}
+ void addLabel(const LabelDecl *label) {
+ assert(PerformCleanup && "adding label to dead scope?");
+ Labels.push_back(label);
+ }
+
/// \brief Exit this cleanup scope, emitting any accumulated
/// cleanups.
~LexicalScope() {
- if (PopDebugStack) {
- CGDebugInfo *DI = CGF.getDebugInfo();
- if (DI) DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
- }
+ if (CGDebugInfo *DI = CGF.getDebugInfo())
+ DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
+
+ // If we should perform a cleanup, force them now. Note that
+ // this ends the cleanup scope before rescoping any labels.
+ if (PerformCleanup) ForceCleanup();
}
/// \brief Force the emission of cleanups now, instead of waiting
/// until this object is destroyed.
void ForceCleanup() {
+ CGF.CurLexicalScope = ParentScope;
RunCleanupsScope::ForceCleanup();
- if (CGDebugInfo *DI = CGF.getDebugInfo()) {
- DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
- PopDebugStack = false;
- }
+
+ if (!Labels.empty())
+ rescopeLabels();
}
+
+ void rescopeLabels();
};
@@ -1116,6 +1148,10 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
+ /// If the current function returns 'this', use the field to keep track of
+ /// the callee that returns 'this'.
+ llvm::Value *CalleeWithThisReturn;
+
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave;
@@ -1176,17 +1212,18 @@ private:
llvm::Value *CXXABIThisValue;
llvm::Value *CXXThisValue;
- /// CXXVTTDecl - When generating code for a base object constructor or
- /// base object destructor with virtual bases, this will hold the implicit
- /// VTT parameter.
- ImplicitParamDecl *CXXVTTDecl;
- llvm::Value *CXXVTTValue;
+ /// CXXStructorImplicitParamDecl - When generating code for a constructor or
+ /// destructor, this will hold the implicit argument (e.g. VTT).
+ ImplicitParamDecl *CXXStructorImplicitParamDecl;
+ llvm::Value *CXXStructorImplicitParamValue;
/// OutermostConditional - Points to the outermost active
/// conditional control. This is used so that we know if a
/// temporary should be destroyed conditionally.
ConditionalEvaluation *OutermostConditional;
+ /// The current lexical scope.
+ LexicalScope *CurLexicalScope;
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
/// type as well as the field number that contains the actual data.
@@ -1200,6 +1237,9 @@ private:
/// Add a kernel metadata node to the named metadata node 'opencl.kernels'.
/// In the kernel metadata node, reference the kernel function and metadata
/// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2):
+ /// - A node for the vec_type_hint(<type>) qualifier contains string
+ /// "vec_type_hint", an undefined value of the <type> data type,
+ /// and a Boolean that is true if the <type> is integer and signed.
/// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string
/// "work_group_size_hint", and three 32-bit integers X, Y and Z.
/// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string
@@ -1279,6 +1319,8 @@ public:
void pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type);
+ void pushEHDestroy(QualType::DestructionKind dtorKind,
+ llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
@@ -1397,6 +1439,7 @@ public:
void EmitConstructorBody(FunctionArgList &Args);
void EmitDestructorBody(FunctionArgList &Args);
+ void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args);
void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
@@ -1509,7 +1552,15 @@ public:
/// hasAggregateLLVMType - Return true if the specified AST type will map into
/// an aggregate LLVM type or is void.
- static bool hasAggregateLLVMType(QualType T);
+ static TypeEvaluationKind getEvaluationKind(QualType T);
+
+ static bool hasScalarEvaluationKind(QualType T) {
+ return getEvaluationKind(T) == TEK_Scalar;
+ }
+
+ static bool hasAggregateEvaluationKind(QualType T) {
+ return getEvaluationKind(T) == TEK_Aggregate;
+ }
/// createBasicBlock - Create an LLVM basic block.
llvm::BasicBlock *createBasicBlock(const Twine &name = "",
@@ -1662,17 +1713,27 @@ public:
void EmitExprAsInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit);
- /// EmitAggregateCopy - Emit an aggrate assignment.
+ /// hasVolatileMember - returns true if aggregate type has a volatile
+ /// member.
+ bool hasVolatileMember(QualType T) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ return RD->hasVolatileMember();
+ }
+ return false;
+ }
+ /// EmitAggregateCopy - Emit an aggregate assignment.
///
/// The difference to EmitAggregateCopy is that tail padding is not copied.
/// This is required for correctness when assigning non-POD structures in C++.
void EmitAggregateAssign(llvm::Value *DestPtr, llvm::Value *SrcPtr,
- QualType EltTy, bool isVolatile=false,
- CharUnits Alignment = CharUnits::Zero()) {
- EmitAggregateCopy(DestPtr, SrcPtr, EltTy, isVolatile, Alignment, true);
+ QualType EltTy) {
+ bool IsVolatile = hasVolatileMember(EltTy);
+ EmitAggregateCopy(DestPtr, SrcPtr, EltTy, IsVolatile, CharUnits::Zero(),
+ true);
}
- /// EmitAggregateCopy - Emit an aggrate copy.
+ /// EmitAggregateCopy - Emit an aggregate copy.
///
/// \param isVolatile - True iff either the source or the destination is
/// volatile.
@@ -1687,11 +1748,6 @@ public:
/// then reuse it.
void StartBlock(const char *N);
- /// GetAddrOfStaticLocalVar - Return the address of a static local variable.
- llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD) {
- return cast<llvm::Constant>(GetAddrOfLocalVar(BVD));
- }
-
/// GetAddrOfLocalVar - Return the address of a local variable.
llvm::Value *GetAddrOfLocalVar(const VarDecl *VD) {
llvm::Value *Res = LocalDeclMap[VD];
@@ -1767,9 +1823,19 @@ public:
/// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
/// virtual bases.
+ // FIXME: Every place that calls LoadCXXVTT is something
+ // that needs to be abstracted properly.
llvm::Value *LoadCXXVTT() {
- assert(CXXVTTValue && "no VTT value for this function");
- return CXXVTTValue;
+ assert(CXXStructorImplicitParamValue && "no VTT value for this function");
+ return CXXStructorImplicitParamValue;
+ }
+
+ /// LoadCXXStructorImplicitParam - Load the implicit parameter
+ /// for a constructor/destructor.
+ llvm::Value *LoadCXXStructorImplicitParam() {
+ assert(CXXStructorImplicitParamValue &&
+ "no implicit argument value for this function");
+ return CXXStructorImplicitParamValue;
}
/// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
@@ -1798,6 +1864,13 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl);
+ /// GetVTTParameter - Return the VTT parameter that should be passed to a
+ /// base constructor/destructor with virtual bases.
+ /// FIXME: VTTs are Itanium ABI-specific, so the definition should move
+ /// to ItaniumCXXABI.cpp together with all the references to VTT.
+ llvm::Value *GetVTTParameter(GlobalDecl GD, bool ForVirtualBase,
+ bool Delegating);
+
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
const FunctionArgList &Args);
@@ -1808,7 +1881,8 @@ public:
void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, llvm::Value *This,
+ bool ForVirtualBase, bool Delegating,
+ llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
@@ -1834,7 +1908,8 @@ public:
static Destroyer destroyCXXObject;
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
- bool ForVirtualBase, llvm::Value *This);
+ bool ForVirtualBase, bool Delegating,
+ llvm::Value *This);
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
llvm::Value *NewPtr, llvm::Value *NumElements);
@@ -1874,7 +1949,13 @@ public:
/// Must be an object within its lifetime.
TCK_MemberCall,
/// Checking the 'this' pointer for a constructor call.
- TCK_ConstructorCall
+ TCK_ConstructorCall,
+ /// Checking the operand of a static_cast to a derived pointer type. Must be
+ /// null or an object within its lifetime.
+ TCK_DowncastPointer,
+ /// Checking the operand of a static_cast to a derived reference type. Must
+ /// be an object within its lifetime.
+ TCK_DowncastReference
};
/// \brief Emit a check that \p V is the address of storage of the
@@ -1882,6 +1963,12 @@ public:
void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
QualType Type, CharUnits Alignment = CharUnits::Zero());
+ /// \brief Emit a check that \p Base points into an array object, which
+ /// we can access at index \p Index. \p Accessed should be \c false if we
+ /// this expression is used as an lvalue, for instance in "&Arr[Idx]".
+ void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index,
+ QualType IndexType, bool Accessed);
+
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
@@ -1933,18 +2020,34 @@ public:
/// initializer.
bool IsConstantAggregate;
+ /// Non-null if we should use lifetime annotations.
+ llvm::Value *SizeForLifetimeMarkers;
+
struct Invalid {};
AutoVarEmission(Invalid) : Variable(0) {}
AutoVarEmission(const VarDecl &variable)
: Variable(&variable), Address(0), NRVOFlag(0),
- IsByRef(false), IsConstantAggregate(false) {}
+ IsByRef(false), IsConstantAggregate(false),
+ SizeForLifetimeMarkers(0) {}
bool wasEmittedAsGlobal() const { return Address == 0; }
public:
static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
+ bool useLifetimeMarkers() const { return SizeForLifetimeMarkers != 0; }
+ llvm::Value *getSizeForLifetimeMarkers() const {
+ assert(useLifetimeMarkers());
+ return SizeForLifetimeMarkers;
+ }
+
+ /// Returns the raw, allocated address, which is not necessarily
+ /// the address of the object itself.
+ llvm::Value *getAllocatedAddress() const {
+ return Address;
+ }
+
/// Returns the address of the object within this declaration.
/// Note that this does not chase the forwarding pointer for
/// __block decls.
@@ -2005,6 +2108,9 @@ public:
RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
AggValueSlot AVS = AggValueSlot::ignored());
+ RValue EmitCompoundStmtWithoutScope(const CompoundStmt &S,
+ bool GetLast = false, AggValueSlot AVS =
+ AggValueSlot::ignored());
/// EmitLabel - Emit the block for the given label. It is legal to call this
/// function even if there is no current insertion point.
@@ -2083,6 +2189,15 @@ public:
/// that the address will be used to access the object.
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
+ RValue convertTempToRValue(llvm::Value *addr, QualType type);
+
+ void EmitAtomicInit(Expr *E, LValue lvalue);
+
+ RValue EmitAtomicLoad(LValue lvalue,
+ AggValueSlot slot = AggValueSlot::ignored());
+
+ void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
+
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
@@ -2096,7 +2211,9 @@ public:
/// the LLVM value representation.
llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0);
+ llvm::MDNode *TBAAInfo = 0,
+ QualType TBAABaseTy = QualType(),
+ uint64_t TBAAOffset = 0);
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
@@ -2109,7 +2226,9 @@ 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 = 0, bool isInit = false,
+ QualType TBAABaseTy = QualType(),
+ uint64_t TBAAOffset = 0);
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
@@ -2156,7 +2275,8 @@ public:
LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E);
LValue EmitPredefinedLValue(const PredefinedExpr *E);
LValue EmitUnaryOpLValue(const UnaryOperator *E);
- LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
+ bool Accessed = false);
LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);
LValue EmitMemberExpr(const MemberExpr *E);
LValue EmitObjCIsaExpr(const ObjCIsaExpr *E);
@@ -2256,11 +2376,29 @@ public:
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());
+ llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
+ const Twine &name = "");
+ llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+ llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
+ const Twine &name = "");
+ llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
ArrayRef<llvm::Value *> Args,
const Twine &Name = "");
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
const Twine &Name = "");
+ llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+ llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ const Twine &name = "");
+ void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args);
llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
llvm::Type *Ty);
@@ -2279,7 +2417,8 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
- llvm::Value *VTT,
+ llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
@@ -2350,14 +2489,14 @@ public:
llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value,
- bool ignored);
+ bool resultIgnored);
llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
- bool ignored);
+ bool resultIgnored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
- void EmitARCDestroyStrong(llvm::Value *addr, bool precise);
- void EmitARCRelease(llvm::Value *value, bool precise);
+ void EmitARCDestroyStrong(llvm::Value *addr, ARCPreciseLifetime_t precise);
+ void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
@@ -2378,6 +2517,8 @@ public:
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
+ void EmitARCIntrinsicUse(llvm::ArrayRef<llvm::Value*> values);
+
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
static Destroyer destroyARCWeak;
@@ -2439,16 +2580,15 @@ public:
bool IgnoreReal = false,
bool IgnoreImag = false);
- /// EmitComplexExprIntoAddr - Emit the computation of the specified expression
- /// of complex type, storing into the specified Value*.
- void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr,
- bool DestIsVolatile);
+ /// EmitComplexExprIntoLValue - Emit the given expression of complex
+ /// type and place its result into the specified l-value.
+ void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit);
+
+ /// EmitStoreOfComplex - Store a complex number into the specified l-value.
+ void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit);
- /// StoreComplexToAddr - Store a complex number into the specified address.
- void StoreComplexToAddr(ComplexPairTy V, llvm::Value *DestAddr,
- bool DestIsVolatile);
- /// LoadComplexFromAddr - Load a complex number from the specified address.
- ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
+ /// EmitLoadOfComplex - Load a complex number from the specified l-value.
+ ComplexPairTy EmitLoadOfComplex(LValue src);
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
/// a static local variable.
@@ -2523,7 +2663,7 @@ public:
/// Emit an annotation call (intrinsic or builtin).
llvm::Value *EmitAnnotationCall(llvm::Value *AnnotationFn,
llvm::Value *AnnotatedVal,
- llvm::StringRef AnnotationStr,
+ StringRef AnnotationStr,
SourceLocation Location);
/// Emit local annotations for the local variable V, declared by D.
@@ -2575,17 +2715,27 @@ public:
/// passing to a runtime sanitizer handler.
llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
+ /// \brief Specify under what conditions this check can be recovered
+ enum CheckRecoverableKind {
+ /// Always terminate program execution if this check fails
+ CRK_Unrecoverable,
+ /// Check supports recovering, allows user to specify which
+ CRK_Recoverable,
+ /// Runtime conditionally aborts, always need to support recovery.
+ CRK_AlwaysRecoverable
+ };
+
/// \brief Create a basic block that will call a handler function in a
/// sanitizer runtime with the provided arguments, and create a conditional
/// branch to it.
void EmitCheck(llvm::Value *Checked, StringRef CheckName,
- llvm::ArrayRef<llvm::Constant *> StaticArgs,
- llvm::ArrayRef<llvm::Value *> DynamicArgs,
- bool Recoverable = false);
+ ArrayRef<llvm::Constant *> StaticArgs,
+ ArrayRef<llvm::Value *> DynamicArgs,
+ CheckRecoverableKind Recoverable);
/// \brief Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.
- void EmitTrapvCheck(llvm::Value *Checked);
+ void EmitTrapCheck(llvm::Value *Checked);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 17972e29b65a..c518a5554e2a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -12,49 +12,57 @@
//===----------------------------------------------------------------------===//
#include "CodeGenModule.h"
-#include "CGDebugInfo.h"
-#include "CodeGenFunction.h"
-#include "CodeGenTBAA.h"
-#include "CGCall.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
+#include "CGCall.h"
+#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CGOpenCLRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenTBAA.h"
#include "TargetInfo.h"
-#include "clang/Frontend/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/ConvertUTF.h"
-#include "llvm/CallingConv.h"
-#include "llvm/Module.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/LLVMContext.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Target/Mangler.h"
-#include "llvm/DataLayout.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/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) {
- switch (CGM.getContext().getTargetInfo().getCXXABI()) {
- case CXXABI_ARM: return *CreateARMCXXABI(CGM);
- case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM);
- case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM);
+ switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ case TargetCXXABI::GenericAArch64:
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
+ case TargetCXXABI::GenericItanium:
+ return *CreateItaniumCXXABI(CGM);
+ case TargetCXXABI::Microsoft:
+ return *CreateMicrosoftCXXABI(CGM);
}
llvm_unreachable("invalid C++ ABI kind");
@@ -62,10 +70,11 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
- llvm::Module &M, const llvm::DataLayout &TD,
+ const TargetOptions &TO, llvm::Module &M,
+ const llvm::DataLayout &TD,
DiagnosticsEngine &diags)
- : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
- TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
+ : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TargetOpts(TO),
+ TheModule(M), TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
Types(*this),
TBAA(0),
@@ -76,8 +85,12 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
VMContext(M.getContext()),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
BlockObjectAssign(0), BlockObjectDispose(0),
- BlockDescriptorType(0), GenericBlockLiteralType(0) {
-
+ BlockDescriptorType(0), GenericBlockLiteralType(0),
+ LifetimeStartFn(0), LifetimeEndFn(0),
+ SanitizerBlacklist(CGO.SanitizerBlacklistFile),
+ SanOpts(SanitizerBlacklist.isIn(M) ?
+ SanitizerOptions::Disabled : LangOpts.Sanitize) {
+
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
VoidTy = llvm::Type::getVoidTy(LLVMContext);
@@ -95,6 +108,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Int8PtrTy = Int8Ty->getPointerTo(0);
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
+ RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
+
if (LangOpts.ObjC1)
createObjCRuntime();
if (LangOpts.OpenCL)
@@ -103,7 +118,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
createCUDARuntime();
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.SanitizeThread ||
+ if (SanOpts.Thread ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(),
ABI.getMangleContext());
@@ -173,6 +188,10 @@ void CodeGenModule::Release() {
EmitGlobalAnnotations();
EmitLLVMUsed();
+ if (CodeGenOpts.ModulesAutolink) {
+ EmitModuleLinkOptions();
+ }
+
SimplifyPersonality();
if (getCodeGenOpts().EmitDeclMetadata)
@@ -208,6 +227,20 @@ llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
return TBAA->getTBAAStructInfo(QTy);
}
+llvm::MDNode *CodeGenModule::getTBAAStructTypeInfo(QualType QTy) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructTypeInfo(QTy);
+}
+
+llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy,
+ llvm::MDNode *AccessN,
+ uint64_t O) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O);
+}
+
void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
@@ -260,9 +293,9 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
}
// Set visibility for definitions.
- NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.visibilityExplicit() || !GV->hasAvailableExternallyLinkage())
- GV->setVisibility(GetLLVMVisibility(LV.visibility()));
+ LinkageInfo LV = D->getLinkageAndVisibility();
+ if (LV.isVisibilityExplicit() || !GV->hasAvailableExternallyLinkage())
+ GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
}
static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(StringRef S) {
@@ -331,7 +364,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
return;
// Don't override an explicit visibility attribute.
- if (RD->getExplicitVisibility())
+ if (RD->getExplicitVisibility(NamedDecl::VisibilityForType))
return;
switch (RD->getTemplateSpecializationKind()) {
@@ -360,7 +393,9 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
// 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) {
- if (Context.getKeyFunction(RD))
+ // FIXME: what should we do if we "lose" the key function during
+ // the emission of the file?
+ if (Context.getCurrentKeyFunction(RD))
return;
}
@@ -532,8 +567,8 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
llvm::Function *F) {
unsigned CallingConv;
AttributeListType AttributeList;
- ConstructAttributeList(Info, D, AttributeList, CallingConv);
- F->setAttributes(llvm::AttrListPtr::get(getLLVMContext(), AttributeList));
+ ConstructAttributeList(Info, D, AttributeList, CallingConv, false);
+ F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -563,28 +598,29 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->setHasUWTable();
if (!hasUnwindExceptions(LangOpts))
- F->addFnAttr(llvm::Attributes::NoUnwind);
+ F->addFnAttr(llvm::Attribute::NoUnwind);
if (D->hasAttr<NakedAttr>()) {
// Naked implies noinline: we should not be inlining such functions.
- F->addFnAttr(llvm::Attributes::Naked);
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::Naked);
+ F->addFnAttr(llvm::Attribute::NoInline);
}
if (D->hasAttr<NoInlineAttr>())
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
// (noinline wins over always_inline, and we can't specify both in IR)
if ((D->hasAttr<AlwaysInlineAttr>() || D->hasAttr<ForceInlineAttr>()) &&
- !F->getFnAttributes().hasAttribute(llvm::Attributes::NoInline))
- F->addFnAttr(llvm::Attributes::AlwaysInline);
+ !F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoInline))
+ F->addFnAttr(llvm::Attribute::AlwaysInline);
// FIXME: Communicate hot and cold attributes to LLVM more directly.
if (D->hasAttr<ColdAttr>())
- F->addFnAttr(llvm::Attributes::OptimizeForSize);
+ F->addFnAttr(llvm::Attribute::OptimizeForSize);
if (D->hasAttr<MinSizeAttr>())
- F->addFnAttr(llvm::Attributes::MinSize);
+ F->addFnAttr(llvm::Attribute::MinSize);
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
@@ -594,15 +630,23 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->setUnnamedAddr(true);
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- F->addFnAttr(llvm::Attributes::StackProtect);
+ F->addFnAttr(llvm::Attribute::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- F->addFnAttr(llvm::Attributes::StackProtectReq);
-
- if (LangOpts.SanitizeAddress) {
- // When AddressSanitizer is enabled, set AddressSafety attribute
- // unless __attribute__((no_address_safety_analysis)) is used.
- if (!D->hasAttr<NoAddressSafetyAnalysisAttr>())
- F->addFnAttr(llvm::Attributes::AddressSafety);
+ F->addFnAttr(llvm::Attribute::StackProtectReq);
+
+ // Add sanitizer attributes if function is not blacklisted.
+ if (!SanitizerBlacklist.isIn(*F)) {
+ // When AddressSanitizer is enabled, set SanitizeAddress attribute
+ // unless __attribute__((no_sanitize_address)) is used.
+ if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
+ F->addFnAttr(llvm::Attribute::SanitizeAddress);
+ // Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
+ if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>()) {
+ F->addFnAttr(llvm::Attribute::SanitizeThread);
+ }
+ // Same for MemorySanitizer and __attribute__((no_sanitize_memory))
+ if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
+ F->addFnAttr(llvm::Attribute::SanitizeMemory);
}
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
@@ -627,7 +671,9 @@ void CodeGenModule::SetCommonAttributes(const Decl *D,
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GV->setSection(SA->getName());
- getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
+ // Alias cannot have attributes. Filter them here.
+ if (!isa<llvm::GlobalAlias>(GV))
+ getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
}
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
@@ -670,9 +716,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
} else {
F->setLinkage(llvm::Function::ExternalLinkage);
- NamedDecl::LinkageInfo LV = FD->getLinkageAndVisibility();
- if (LV.linkage() == ExternalLinkage && LV.visibilityExplicit()) {
- F->setVisibility(GetLLVMVisibility(LV.visibility()));
+ LinkageInfo LV = FD->getLinkageAndVisibility();
+ if (LV.getLinkage() == ExternalLinkage && LV.isVisibilityExplicit()) {
+ F->setVisibility(GetLLVMVisibility(LV.getVisibility()));
}
}
@@ -713,19 +759,130 @@ void CodeGenModule::EmitLLVMUsed() {
GV->setSection("llvm.metadata");
}
+/// \brief Add link options implied by the given module, including modules
+/// it depends on, using a postorder walk.
+static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
+ Module *Mod,
+ SmallVectorImpl<llvm::Value *> &Metadata,
+ llvm::SmallPtrSet<Module *, 16> &Visited) {
+ // Import this module's parent.
+ if (Mod->Parent && Visited.insert(Mod->Parent)) {
+ addLinkOptionsPostorder(Context, Mod->Parent, Metadata, Visited);
+ }
+
+ // Import this module's dependencies.
+ for (unsigned I = Mod->Imports.size(); I > 0; --I) {
+ if (Visited.insert(Mod->Imports[I-1]))
+ addLinkOptionsPostorder(Context, Mod->Imports[I-1], Metadata, Visited);
+ }
+
+ // Add linker options to link against the libraries/frameworks
+ // described by this module.
+ for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) {
+ // FIXME: -lfoo is Unix-centric and -framework Foo is Darwin-centric.
+ // We need to know more about the linker to know how to encode these
+ // options propertly.
+
+ // Link against a framework.
+ if (Mod->LinkLibraries[I-1].IsFramework) {
+ llvm::Value *Args[2] = {
+ llvm::MDString::get(Context, "-framework"),
+ llvm::MDString::get(Context, Mod->LinkLibraries[I-1].Library)
+ };
+
+ Metadata.push_back(llvm::MDNode::get(Context, Args));
+ continue;
+ }
+
+ // Link against a library.
+ llvm::Value *OptString
+ = llvm::MDString::get(Context,
+ "-l" + Mod->LinkLibraries[I-1].Library);
+ Metadata.push_back(llvm::MDNode::get(Context, OptString));
+ }
+}
+
+void CodeGenModule::EmitModuleLinkOptions() {
+ // Collect the set of all of the modules we want to visit to emit link
+ // options, which is essentially the imported modules and all of their
+ // non-explicit child modules.
+ llvm::SetVector<clang::Module *> LinkModules;
+ llvm::SmallPtrSet<clang::Module *, 16> Visited;
+ SmallVector<clang::Module *, 16> Stack;
+
+ // Seed the stack with imported modules.
+ for (llvm::SetVector<clang::Module *>::iterator M = ImportedModules.begin(),
+ MEnd = ImportedModules.end();
+ M != MEnd; ++M) {
+ if (Visited.insert(*M))
+ Stack.push_back(*M);
+ }
+
+ // Find all of the modules to import, making a little effort to prune
+ // non-leaf modules.
+ while (!Stack.empty()) {
+ clang::Module *Mod = Stack.back();
+ Stack.pop_back();
+
+ bool AnyChildren = false;
+
+ // Visit the submodules of this module.
+ for (clang::Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub) {
+ // Skip explicit children; they need to be explicitly imported to be
+ // linked against.
+ if ((*Sub)->IsExplicit)
+ continue;
+
+ if (Visited.insert(*Sub)) {
+ Stack.push_back(*Sub);
+ AnyChildren = true;
+ }
+ }
+
+ // We didn't find any children, so add this module to the list of
+ // modules to link against.
+ if (!AnyChildren) {
+ LinkModules.insert(Mod);
+ }
+ }
+
+ // Add link options for all of the imported modules in reverse topological
+ // order.
+ SmallVector<llvm::Value *, 16> MetadataArgs;
+ Visited.clear();
+ for (llvm::SetVector<clang::Module *>::iterator M = LinkModules.begin(),
+ MEnd = LinkModules.end();
+ M != MEnd; ++M) {
+ if (Visited.insert(*M))
+ addLinkOptionsPostorder(getLLVMContext(), *M, MetadataArgs, Visited);
+ }
+ std::reverse(MetadataArgs.begin(), MetadataArgs.end());
+
+ // Add the linker options metadata flag.
+ getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
+ llvm::MDNode::get(getLLVMContext(), MetadataArgs));
+}
+
void CodeGenModule::EmitDeferred() {
// Emit code for any potentially referenced deferred decls. Since a
// previously unused static decl may become used during the generation of code
// for a static function, iterate until no changes are made.
- while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) {
+ while (true) {
if (!DeferredVTables.empty()) {
- const CXXRecordDecl *RD = DeferredVTables.back();
- DeferredVTables.pop_back();
- getCXXABI().EmitVTables(RD);
- continue;
+ EmitDeferredVTables();
+
+ // Emitting a v-table doesn't directly cause more v-tables to
+ // become deferred, although it can cause functions to be
+ // emitted that then need those v-tables.
+ assert(DeferredVTables.empty());
}
+ // Stop if we're out of both deferred v-tables and deferred declarations.
+ if (DeferredDeclsToEmit.empty()) break;
+
GlobalDecl D = DeferredDeclsToEmit.back();
DeferredDeclsToEmit.pop_back();
@@ -767,7 +924,7 @@ void CodeGenModule::EmitGlobalAnnotations() {
gv->setSection(AnnotationSection);
}
-llvm::Constant *CodeGenModule::EmitAnnotationString(llvm::StringRef Str) {
+llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
llvm::StringMap<llvm::Constant*>::iterator i = AnnotationStrings.find(Str);
if (i != AnnotationStrings.end())
return i->second;
@@ -1106,7 +1263,7 @@ llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
llvm::Type *Ty,
GlobalDecl D, bool ForVTable,
- llvm::Attributes ExtraAttrs) {
+ llvm::AttributeSet ExtraAttrs) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
@@ -1142,8 +1299,13 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
- if (ExtraAttrs.hasAttributes())
- F->addAttribute(llvm::AttrListPtr::FunctionIndex, ExtraAttrs);
+ if (ExtraAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) {
+ llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeSet::FunctionIndex);
+ F->addAttributes(llvm::AttributeSet::FunctionIndex,
+ llvm::AttributeSet::get(VMContext,
+ llvm::AttributeSet::FunctionIndex,
+ 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
@@ -1214,9 +1376,14 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
StringRef Name,
- llvm::Attributes ExtraAttrs) {
- return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
- ExtraAttrs);
+ llvm::AttributeSet ExtraAttrs) {
+ llvm::Constant *C
+ = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+ ExtraAttrs);
+ if (llvm::Function *F = dyn_cast<llvm::Function>(C))
+ if (F->empty())
+ F->setCallingConv(getRuntimeCC());
+ return C;
}
/// isTypeConstant - Determine whether an object of this type can be emitted
@@ -1294,8 +1461,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setConstant(isTypeConstant(D->getType(), false));
// Set linkage and visibility in case we never see a definition.
- NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.linkage() != ExternalLinkage) {
+ LinkageInfo LV = D->getLinkageAndVisibility();
+ if (LV.getLinkage() != ExternalLinkage) {
// Don't set internal linkage on declarations.
} else {
if (D->hasAttr<DLLImportAttr>())
@@ -1304,8 +1471,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
// Set visibility on a declaration only if it's explicit.
- if (LV.visibilityExplicit())
- GV->setVisibility(GetLLVMVisibility(LV.visibility()));
+ if (LV.isVisibilityExplicit())
+ GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
}
if (D->isThreadSpecified())
@@ -1403,80 +1570,6 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
-void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
- if (DefinitionRequired)
- getCXXABI().EmitVTables(Class);
-}
-
-llvm::GlobalVariable::LinkageTypes
-CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (RD->getLinkage() != ExternalLinkage)
- return llvm::GlobalVariable::InternalLinkage;
-
- if (const CXXMethodDecl *KeyFunction
- = RD->getASTContext().getKeyFunction(RD)) {
- // If this class has a key function, use that to determine the linkage of
- // the vtable.
- const FunctionDecl *Def = 0;
- if (KeyFunction->hasBody(Def))
- KeyFunction = cast<CXXMethodDecl>(Def);
-
- switch (KeyFunction->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- // When compiling with optimizations turned on, we emit all vtables,
- // even if the key function is not defined in the current translation
- // unit. If this is the case, use available_externally linkage.
- if (!Def && CodeGenOpts.OptimizationLevel)
- return llvm::GlobalVariable::AvailableExternallyLinkage;
-
- if (KeyFunction->isInlined())
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
-
- return llvm::GlobalVariable::ExternalLinkage;
-
- case TSK_ImplicitInstantiation:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::WeakODRLinkage :
- llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDeclaration:
- // FIXME: Use available_externally linkage. However, this currently
- // breaks LLVM's build due to undefined symbols.
- // return llvm::GlobalVariable::AvailableExternallyLinkage;
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
- }
- }
-
- if (Context.getLangOpts().AppleKext)
- return llvm::Function::InternalLinkage;
-
- switch (RD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- case TSK_ImplicitInstantiation:
- // FIXME: Use available_externally linkage. However, this currently
- // breaks LLVM's build due to undefined symbols.
- // return llvm::GlobalVariable::AvailableExternallyLinkage;
- case TSK_ExplicitInstantiationDeclaration:
- return llvm::GlobalVariable::LinkOnceODRLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return llvm::GlobalVariable::WeakODRLinkage;
- }
-
- llvm_unreachable("Invalid TemplateSpecializationKind!");
-}
-
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
return Context.toCharUnitsFromBits(
TheDataLayout.getTypeStoreSizeInBits(Ty));
@@ -1523,7 +1616,7 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
D->getDeclContext()),
D->getLocStart(), D->getLocation(),
name, arrayType, sourceInfo,
- SC_Static, SC_Static);
+ SC_Static);
// Now clone the InitListExpr to initialize the array instead.
// Incredible hack: we want to use the existing InitListExpr here, so we need
@@ -1739,7 +1832,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If we are compiling with ASan, add metadata indicating dynamically
// initialized globals.
- if (LangOpts.SanitizeAddress && NeedsGlobalCtor) {
+ if (SanOpts.Address && NeedsGlobalCtor) {
llvm::Module &M = getModule();
llvm::NamedMDNode *DynamicInitializers =
@@ -1785,105 +1878,139 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
return llvm::GlobalVariable::ExternalLinkage;
}
-/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
-/// implement a function with no prototype, e.g. "int foo() {}". If there are
-/// existing call uses of the old function in the module, this adjusts them to
-/// call the new function directly.
-///
-/// This is not just a cleanup: the always_inline pass requires direct calls to
-/// functions to be able to inline them. If there is a bitcast in the way, it
-/// won't inline them. Instcombine normally deletes these calls, but it isn't
-/// run at -O0.
-static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
- llvm::Function *NewFn) {
- // If we're redefining a global as a function, don't transform it.
- llvm::Function *OldFn = dyn_cast<llvm::Function>(Old);
- if (OldFn == 0) return;
-
- llvm::Type *NewRetTy = NewFn->getReturnType();
- SmallVector<llvm::Value*, 4> ArgList;
-
- for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end();
- UI != E; ) {
- // TODO: Do invokes ever occur in C code? If so, we should handle them too.
- llvm::Value::use_iterator I = UI++; // Increment before the CI is erased.
- llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*I);
- if (!CI) continue; // FIXME: when we allow Invoke, just do CallSite CS(*I)
- llvm::CallSite CS(CI);
- if (!CI || !CS.isCallee(I)) continue;
-
- // If the return types don't match exactly, and if the call isn't dead, then
- // we can't transform this call.
- if (CI->getType() != NewRetTy && !CI->use_empty())
+/// 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,
+ llvm::Function *newFn) {
+ // Fast path.
+ if (old->use_empty()) return;
+
+ llvm::Type *newRetTy = newFn->getReturnType();
+ SmallVector<llvm::Value*, 4> newArgs;
+
+ 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;
+
+ // Recognize and replace uses of bitcasts. Most calls to
+ // unprototyped functions will use bitcasts.
+ if (llvm::ConstantExpr *bitcast = dyn_cast<llvm::ConstantExpr>(user)) {
+ if (bitcast->getOpcode() == llvm::Instruction::BitCast)
+ replaceUsesOfNonProtoConstant(bitcast, newFn);
+ continue;
+ }
+
+ // Recognize calls to the function.
+ llvm::CallSite callSite(user);
+ if (!callSite) 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.
+ if (callSite->getType() != newRetTy && !callSite->use_empty())
continue;
- // Get the attribute list.
- llvm::SmallVector<llvm::AttributeWithIndex, 8> AttrVec;
- llvm::AttrListPtr AttrList = CI->getAttributes();
-
- // Get any return attributes.
- llvm::Attributes RAttrs = AttrList.getRetAttributes();
-
- // Add the return attributes.
- if (RAttrs.hasAttributes())
- AttrVec.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
- RAttrs));
-
- // If the function was passed too few arguments, don't transform. If extra
- // arguments were passed, we silently drop them. If any of the types
- // mismatch, we don't transform.
- unsigned ArgNo = 0;
- bool DontTransform = false;
- for (llvm::Function::arg_iterator AI = NewFn->arg_begin(),
- E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) {
- if (CS.arg_size() == ArgNo ||
- CS.getArgument(ArgNo)->getType() != AI->getType()) {
- DontTransform = true;
+ // Get the call site's attribute list.
+ SmallVector<llvm::AttributeSet, 8> newAttrs;
+ llvm::AttributeSet oldAttrs = callSite.getAttributes();
+
+ // Collect any return attributes from the call.
+ if (oldAttrs.hasAttributes(llvm::AttributeSet::ReturnIndex))
+ newAttrs.push_back(
+ llvm::AttributeSet::get(newFn->getContext(),
+ oldAttrs.getRetAttributes()));
+
+ // If the function was passed too few arguments, don't transform.
+ unsigned newNumArgs = newFn->arg_size();
+ if (callSite.arg_size() < newNumArgs) continue;
+
+ // If extra arguments were passed, we silently drop them.
+ // If any of the types mismatch, we don't transform.
+ unsigned argNo = 0;
+ bool dontTransform = false;
+ for (llvm::Function::arg_iterator ai = newFn->arg_begin(),
+ ae = newFn->arg_end(); ai != ae; ++ai, ++argNo) {
+ if (callSite.getArgument(argNo)->getType() != ai->getType()) {
+ dontTransform = true;
break;
}
// Add any parameter attributes.
- llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1);
- if (PAttrs.hasAttributes())
- AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs));
+ if (oldAttrs.hasAttributes(argNo + 1))
+ newAttrs.
+ push_back(llvm::
+ AttributeSet::get(newFn->getContext(),
+ oldAttrs.getParamAttributes(argNo + 1)));
}
- if (DontTransform)
+ if (dontTransform)
continue;
- llvm::Attributes FnAttrs = AttrList.getFnAttributes();
- if (FnAttrs.hasAttributes())
- AttrVec.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
- FnAttrs));
+ if (oldAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex))
+ newAttrs.push_back(llvm::AttributeSet::get(newFn->getContext(),
+ oldAttrs.getFnAttributes()));
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
- ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo);
- llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList, "", CI);
- ArgList.clear();
- if (!NewCall->getType()->isVoidTy())
- NewCall->takeName(CI);
- NewCall->setAttributes(llvm::AttrListPtr::get(OldFn->getContext(), AttrVec));
- NewCall->setCallingConv(CI->getCallingConv());
+ newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo);
+
+ llvm::CallSite newCall;
+ if (callSite.isCall()) {
+ newCall = llvm::CallInst::Create(newFn, newArgs, "",
+ callSite.getInstruction());
+ } else {
+ llvm::InvokeInst *oldInvoke =
+ cast<llvm::InvokeInst>(callSite.getInstruction());
+ newCall = llvm::InvokeInst::Create(newFn,
+ oldInvoke->getNormalDest(),
+ oldInvoke->getUnwindDest(),
+ newArgs, "",
+ callSite.getInstruction());
+ }
+ newArgs.clear(); // for the next iteration
+
+ if (!newCall->getType()->isVoidTy())
+ newCall->takeName(callSite.getInstruction());
+ newCall.setAttributes(
+ llvm::AttributeSet::get(newFn->getContext(), newAttrs));
+ newCall.setCallingConv(callSite.getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
- if (!CI->use_empty())
- CI->replaceAllUsesWith(NewCall);
+ if (!callSite->use_empty())
+ callSite->replaceAllUsesWith(newCall.getInstruction());
// Copy debug location attached to CI.
- if (!CI->getDebugLoc().isUnknown())
- NewCall->setDebugLoc(CI->getDebugLoc());
- CI->eraseFromParent();
+ if (!callSite->getDebugLoc().isUnknown())
+ newCall->setDebugLoc(callSite->getDebugLoc());
+ callSite->eraseFromParent();
}
}
+/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
+/// implement a function with no prototype, e.g. "int foo() {}". If there are
+/// existing call uses of the old function in the module, this adjusts them to
+/// call the new function directly.
+///
+/// This is not just a cleanup: the always_inline pass requires direct calls to
+/// functions to be able to inline them. If there is a bitcast in the way, it
+/// won't inline them. Instcombine normally deletes these calls, but it isn't
+/// run at -O0.
+static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
+ llvm::Function *NewFn) {
+ // If we're redefining a global as a function, don't transform it.
+ if (!isa<llvm::Function>(Old)) return;
+
+ replaceUsesOfNonProtoConstant(Old, NewFn);
+}
+
void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind();
// If we have a definition, this might be a deferred decl. If the
// instantiation is explicit, make sure we emit it at the end.
if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition)
GetAddrOfGlobalVar(VD);
+
+ EmitTopLevelDecl(VD);
}
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
@@ -1921,10 +2048,14 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
OldFn->setName(StringRef());
llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
- // If this is an implementation of a function without a prototype, try to
- // replace any existing uses of the function (which may be calls) with uses
- // of the new function
- if (D->getType()->isFunctionNoProtoType()) {
+ // This might be an implementation of a function without a
+ // prototype, in which case, try to do special replacement of
+ // calls which match the new prototype. The really key thing here
+ // is that we also potentially drop arguments from the call site
+ // 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();
}
@@ -2131,7 +2262,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::Constant *C = 0;
if (isUTF16) {
ArrayRef<uint16_t> Arr =
- llvm::makeArrayRef<uint16_t>((uint16_t*)Entry.getKey().data(),
+ llvm::makeArrayRef<uint16_t>(reinterpret_cast<uint16_t*>(
+ const_cast<char *>(Entry.getKey().data())),
Entry.getKey().size() / 2);
C = llvm::ConstantDataArray::get(VMContext, Arr);
} else {
@@ -2644,7 +2776,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::TypeAliasTemplate:
case Decl::NamespaceAlias:
case Decl::Block:
- case Decl::Import:
+ case Decl::Empty:
break;
case Decl::CXXConstructor:
// Skip function templates
@@ -2691,9 +2823,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
ObjCRuntime->GenerateClass(OMD);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(OMD->getClassInterface()),
- OMD->getLocation());
-
+ if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo)
+ DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(
+ OMD->getClassInterface()), OMD->getLocation());
break;
}
case Decl::ObjCMethod: {
@@ -2725,6 +2857,20 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
+ case Decl::Import: {
+ ImportDecl *Import = cast<ImportDecl>(D);
+
+ // Ignore import declarations that come from imported modules.
+ if (clang::Module *Owner = Import->getOwningModule()) {
+ if (getLangOpts().CurrentModule.empty() ||
+ Owner->getTopLevelModule()->Name == getLangOpts().CurrentModule)
+ break;
+ }
+
+ ImportedModules.insert(Import->getImportedModule());
+ break;
+ }
+
default:
// Make sure we handled everything we should, every other kind is a
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
@@ -2828,7 +2974,7 @@ llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
const char *Uuidstr = Uuid.data();
for (int i = 0; i < 36; ++i) {
if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuidstr[i] == '-');
- else assert(isxdigit(Uuidstr[i]));
+ else assert(isHexDigit(Uuidstr[i]));
}
llvm::APInt Field0(32, StringRef(Uuidstr , 8), 16);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 1167c87ce13b..5b2153e5ff3f 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -14,20 +14,24 @@
#ifndef CLANG_CODEGEN_CODEGENMODULE_H
#define CLANG_CODEGEN_CODEGENMODULE_H
-#include "clang/Basic/ABI.h"
-#include "clang/Basic/LangOptions.h"
+#include "CGVTables.h"
+#include "CodeGenTypes.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Mangle.h"
-#include "CGVTables.h"
-#include "CodeGenTypes.h"
-#include "llvm/Module.h"
+#include "clang/Basic/ABI.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Module.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Transforms/Utils/BlackList.h"
namespace llvm {
class Module;
@@ -43,6 +47,7 @@ namespace llvm {
namespace clang {
class TargetCodeGenInfo;
class ASTContext;
+ class AtomicType;
class FunctionDecl;
class IdentifierInfo;
class ObjCMethodDecl;
@@ -62,10 +67,12 @@ namespace clang {
class VarDecl;
class LangOptions;
class CodeGenOptions;
+ class TargetOptions;
class DiagnosticsEngine;
class AnnotateAttr;
class CXXDestructorDecl;
class MangleBuffer;
+ class Module;
namespace CodeGen {
@@ -140,6 +147,11 @@ namespace CodeGen {
unsigned char PointerSizeInBytes;
unsigned char SizeSizeInBytes; // sizeof(size_t)
};
+
+ llvm::CallingConv::ID RuntimeCC;
+ llvm::CallingConv::ID getRuntimeCC() const {
+ return RuntimeCC;
+ }
};
struct RREntrypoints {
@@ -205,8 +217,11 @@ struct ARCEntrypoints {
/// A void(void) inline asm to use to mark that the return value of
/// a call will be immediately retain.
llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
+
+ /// void clang.arc.use(...);
+ llvm::Constant *clang_arc_use;
};
-
+
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public CodeGenTypeCache {
@@ -218,6 +233,7 @@ class CodeGenModule : public CodeGenTypeCache {
ASTContext &Context;
const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
+ const TargetOptions &TargetOpts;
llvm::Module &TheModule;
const llvm::DataLayout &TheDataLayout;
mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
@@ -254,6 +270,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// is done.
std::vector<GlobalDecl> DeferredDeclsToEmit;
+ /// DeferredVTables - 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
@@ -313,6 +332,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// run on termination.
std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
+ /// \brief The complete set of modules that has been imported.
+ llvm::SetVector<clang::Module *> ImportedModules;
+
/// @name Cache for Objective-C runtime types
/// @{
@@ -358,14 +380,24 @@ class CodeGenModule : public CodeGenTypeCache {
struct {
int GlobalUniqueCount;
} Block;
-
+
+ /// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>)
+ llvm::Constant *LifetimeStartFn;
+
+ /// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>)
+ llvm::Constant *LifetimeEndFn;
+
GlobalDecl initializedGlobalDecl;
+ llvm::BlackList SanitizerBlacklist;
+
+ const SanitizerOptions &SanOpts;
+
/// @}
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
- llvm::Module &M, const llvm::DataLayout &TD,
- DiagnosticsEngine &Diags);
+ const TargetOptions &TargetOpts, llvm::Module &M,
+ const llvm::DataLayout &TD, DiagnosticsEngine &Diags);
~CodeGenModule();
@@ -469,9 +501,17 @@ public:
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
llvm::MDNode *getTBAAStructInfo(QualType QTy);
+ /// Return the MDNode in the type DAG for the given struct type.
+ llvm::MDNode *getTBAAStructTypeInfo(QualType QTy);
+ /// Return the path-aware tag for given base type, access node and offset.
+ llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN,
+ uint64_t O);
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
+ bool isPaddedAtomicType(QualType type);
+ bool isPaddedAtomicType(const AtomicType *type);
+
static void DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo);
@@ -711,8 +751,8 @@ public:
/// type and name.
llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty,
StringRef Name,
- llvm::Attributes ExtraAttrs =
- llvm::Attributes());
+ llvm::AttributeSet ExtraAttrs =
+ llvm::AttributeSet());
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
@@ -728,6 +768,9 @@ public:
///@}
+ llvm::Constant *getLLVMLifetimeStartFn();
+ llvm::Constant *getLLVMLifetimeEndFn();
+
// UpdateCompleteType - Make sure that this type is translated.
void UpdateCompletedType(const TagDecl *TD);
@@ -823,7 +866,8 @@ public:
void ConstructAttributeList(const CGFunctionInfo &Info,
const Decl *TargetDecl,
AttributeListType &PAL,
- unsigned &CallingConv);
+ unsigned &CallingConv,
+ bool AttrOnCallSite);
StringRef getMangledName(GlobalDecl GD);
void getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
@@ -854,13 +898,11 @@ public:
GetLLVMLinkageVarDefinition(const VarDecl *D,
llvm::GlobalVariable *GV);
- std::vector<const CXXRecordDecl*> DeferredVTables;
-
/// Emit all the global annotations.
void EmitGlobalAnnotations();
/// Emit an annotation string.
- llvm::Constant *EmitAnnotationString(llvm::StringRef Str);
+ llvm::Constant *EmitAnnotationString(StringRef Str);
/// Emit the annotation's translation unit.
llvm::Constant *EmitAnnotationUnit(SourceLocation Loc);
@@ -883,6 +925,16 @@ public:
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
+ const llvm::BlackList &getSanitizerBlacklist() const {
+ return SanitizerBlacklist;
+ }
+
+ const SanitizerOptions &getSanOpts() const { return SanOpts; }
+
+ void addDeferredVTable(const CXXRecordDecl *RD) {
+ DeferredVTables.push_back(RD);
+ }
+
private:
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
@@ -890,8 +942,8 @@ private:
llvm::Type *Ty,
GlobalDecl D,
bool ForVTable,
- llvm::Attributes ExtraAttrs =
- llvm::Attributes());
+ llvm::AttributeSet ExtraAttrs =
+ llvm::AttributeSet());
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
const VarDecl *D,
@@ -983,11 +1035,18 @@ private:
/// EmitDeferred - Emit any needed decls for which code generation
/// was deferred.
- void EmitDeferred(void);
+ void EmitDeferred();
+
+ /// EmitDeferredVTables - 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(void);
+ void EmitLLVMUsed();
+
+ /// \brief Emit the link options introduced by imported modules.
+ void EmitModuleLinkOptions();
void EmitDeclMetadata();
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index d9004a02ae25..7e4d34ab8981 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -17,13 +17,15 @@
#include "CodeGenTBAA.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Metadata.h"
-#include "llvm/Constants.h"
-#include "llvm/Type.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Type.h"
using namespace clang;
using namespace CodeGen;
@@ -224,3 +226,87 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
// For now, handle any other kind of type conservatively.
return StructMetadataCache[Ty] = NULL;
}
+
+/// Check if the given type can be handled by path-aware TBAA.
+static bool isTBAAPathStruct(QualType QTy) {
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+ // RD can be struct, union, class, interface or enum.
+ // For now, we only handle struct.
+ if (RD->isStruct() && !RD->hasFlexibleArrayMember())
+ return true;
+ }
+ return false;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
+ const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
+ assert(isTBAAPathStruct(QTy));
+
+ if (llvm::MDNode *N = StructTypeMetadataCache[Ty])
+ return N;
+
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ SmallVector <std::pair<uint64_t, llvm::MDNode*>, 4> Fields;
+ // To reduce the size of MDNode for a given struct type, we only output
+ // once for all the fields with the same scalar types.
+ // Offsets for scalar fields in the type DAG are not used.
+ llvm::SmallSet <llvm::MDNode*, 4> ScalarFieldTypes;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i, ++idx) {
+ QualType FieldQTy = i->getType();
+ llvm::MDNode *FieldNode;
+ if (isTBAAPathStruct(FieldQTy))
+ FieldNode = getTBAAStructTypeInfo(FieldQTy);
+ else {
+ FieldNode = getTBAAInfo(FieldQTy);
+ // Ignore this field if the type already exists.
+ if (ScalarFieldTypes.count(FieldNode))
+ continue;
+ ScalarFieldTypes.insert(FieldNode);
+ }
+ if (!FieldNode)
+ return StructTypeMetadataCache[Ty] = NULL;
+ Fields.push_back(std::make_pair(
+ Layout.getFieldOffset(idx) / Context.getCharWidth(), FieldNode));
+ }
+
+ // TODO: This is using the RTTI name. Is there a better way to get
+ // a unique string for a type?
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ MContext.mangleCXXRTTIName(QualType(Ty, 0), Out);
+ Out.flush();
+ // Create the struct type node with a vector of pairs (offset, type).
+ return StructTypeMetadataCache[Ty] =
+ MDHelper.createTBAAStructTypeNode(OutName, Fields);
+ }
+
+ return StructMetadataCache[Ty] = NULL;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
+ uint64_t Offset) {
+ if (!CodeGenOpts.StructPathTBAA)
+ return AccessNode;
+
+ const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr();
+ TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset);
+ if (llvm::MDNode *N = StructTagMetadataCache[PathTag])
+ return N;
+
+ llvm::MDNode *BNode = 0;
+ if (isTBAAPathStruct(BaseQTy))
+ BNode = getTBAAStructTypeInfo(BaseQTy);
+ if (!BNode)
+ return StructTagMetadataCache[PathTag] = AccessNode;
+
+ return StructTagMetadataCache[PathTag] =
+ MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset);
+}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index eedb996f3eef..9ddc3aa97006 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -16,8 +16,8 @@
#define CLANG_CODEGEN_CODEGENTBAA_H
#include "clang/Basic/LLVM.h"
-#include "llvm/MDBuilder.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/MDBuilder.h"
namespace llvm {
class LLVMContext;
@@ -35,6 +35,14 @@ namespace clang {
namespace CodeGen {
class CGRecordLayout;
+ struct TBAAPathTag {
+ TBAAPathTag(const Type *B, const llvm::MDNode *A, uint64_t O)
+ : BaseT(B), AccessN(A), Offset(O) {}
+ const Type *BaseT;
+ const llvm::MDNode *AccessN;
+ uint64_t Offset;
+ };
+
/// CodeGenTBAA - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTBAA {
@@ -46,8 +54,13 @@ class CodeGenTBAA {
// MDHelper - Helper for creating metadata.
llvm::MDBuilder MDHelper;
- /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them.
+ /// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing
+ /// them.
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
+ /// This maps clang::Types to a struct node in the type DAG.
+ llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache;
+ /// This maps TBAAPathTags to a tag node.
+ llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache;
/// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
/// them for struct assignments.
@@ -89,9 +102,49 @@ public:
/// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
/// the given type.
llvm::MDNode *getTBAAStructInfo(QualType QTy);
+
+ /// Get the MDNode in the type DAG for given struct type QType.
+ llvm::MDNode *getTBAAStructTypeInfo(QualType QType);
+ /// Get the tag MDNode for a given base type, the actual sclar access MDNode
+ /// and offset into the base type.
+ llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType,
+ llvm::MDNode *AccessNode, uint64_t Offset);
};
} // end namespace CodeGen
} // end namespace clang
+namespace llvm {
+
+template<> struct DenseMapInfo<clang::CodeGen::TBAAPathTag> {
+ static clang::CodeGen::TBAAPathTag getEmptyKey() {
+ return clang::CodeGen::TBAAPathTag(
+ DenseMapInfo<const clang::Type *>::getEmptyKey(),
+ DenseMapInfo<const MDNode *>::getEmptyKey(),
+ DenseMapInfo<uint64_t>::getEmptyKey());
+ }
+
+ static clang::CodeGen::TBAAPathTag getTombstoneKey() {
+ return clang::CodeGen::TBAAPathTag(
+ DenseMapInfo<const clang::Type *>::getTombstoneKey(),
+ DenseMapInfo<const MDNode *>::getTombstoneKey(),
+ DenseMapInfo<uint64_t>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const clang::CodeGen::TBAAPathTag &Val) {
+ return DenseMapInfo<const clang::Type *>::getHashValue(Val.BaseT) ^
+ DenseMapInfo<const MDNode *>::getHashValue(Val.AccessN) ^
+ DenseMapInfo<uint64_t>::getHashValue(Val.Offset);
+ }
+
+ static bool isEqual(const clang::CodeGen::TBAAPathTag &LHS,
+ const clang::CodeGen::TBAAPathTag &RHS) {
+ return LHS.BaseT == RHS.BaseT &&
+ LHS.AccessN == RHS.AccessN &&
+ LHS.Offset == RHS.Offset;
+ }
+};
+
+} // end namespace llvm
+
#endif
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 3c6c5c9a2e2f..8fc78e3de628 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -12,18 +12,19 @@
//===----------------------------------------------------------------------===//
#include "CodeGenTypes.h"
-#include "CGCall.h"
#include "CGCXXABI.h"
+#include "CGCall.h"
+#include "CGOpenCLRuntime.h"
#include "CGRecordLayout.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Module.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Module.h"
using namespace clang;
using namespace CodeGen;
@@ -60,14 +61,14 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
// FIXME: We should not have to check for a null decl context here.
// Right now we do it because the implicit Obj-C decls don't have one.
if (RD->getDeclContext())
- OS << RD->getQualifiedNameAsString();
+ RD->printQualifiedName(OS);
else
RD->printName(OS);
} else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
// FIXME: We should not have to check for a null decl context here.
// Right now we do it because the implicit Obj-C decls don't have one.
if (TDD->getDeclContext())
- OS << TDD->getQualifiedNameAsString();
+ TDD->printQualifiedName(OS);
else
TDD->printName(OS);
} else
@@ -262,9 +263,14 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
}
static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
- const llvm::fltSemantics &format) {
- if (&format == &llvm::APFloat::IEEEhalf)
- return llvm::Type::getInt16Ty(VMContext);
+ const llvm::fltSemantics &format,
+ bool UseNativeHalf = false) {
+ if (&format == &llvm::APFloat::IEEEhalf) {
+ if (UseNativeHalf)
+ return llvm::Type::getHalfTy(VMContext);
+ else
+ return llvm::Type::getInt16Ty(VMContext);
+ }
if (&format == &llvm::APFloat::IEEEsingle)
return llvm::Type::getFloatTy(VMContext);
if (&format == &llvm::APFloat::IEEEdouble)
@@ -343,18 +349,17 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
case BuiltinType::Half:
- // Half is special: it might be lowered to i16 (and will be storage-only
- // type),. or can be represented as a set of native operations.
-
- // FIXME: Ask target which kind of half FP it prefers (storage only vs
- // native).
- ResultType = llvm::Type::getInt16Ty(getLLVMContext());
+ // Half FP can either be storage-only (lowered to i16) or native.
+ ResultType = getTypeForFormat(getLLVMContext(),
+ Context.getFloatTypeSemantics(T),
+ Context.getLangOpts().NativeHalfType);
break;
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
ResultType = getTypeForFormat(getLLVMContext(),
- Context.getFloatTypeSemantics(T));
+ Context.getFloatTypeSemantics(T),
+ /* UseNativeHalf = */ false);
break;
case BuiltinType::NullPtr:
@@ -366,6 +371,17 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
case BuiltinType::Int128:
ResultType = llvm::IntegerType::get(getLLVMContext(), 128);
break;
+
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
+ break;
case BuiltinType::Dependent:
#define BUILTIN_TYPE(Id, SingletonId)
@@ -453,9 +469,19 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// cannot lower the function type.
if (!isFuncTypeConvertible(FT)) {
// This function's type depends on an incomplete tag type.
+
+ // 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>())
+ 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>())
+ ConvertRecordDeclType(RT->getDecl());
+
// Return a placeholder type.
ResultType = llvm::StructType::get(getLLVMContext());
-
+
SkippedLayout = true;
break;
}
@@ -556,7 +582,21 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::Atomic: {
- ResultType = ConvertType(cast<AtomicType>(Ty)->getValueType());
+ QualType valueType = cast<AtomicType>(Ty)->getValueType();
+ ResultType = ConvertTypeForMem(valueType);
+
+ // Pad out to the inflated size if necessary.
+ uint64_t valueSize = Context.getTypeSize(valueType);
+ uint64_t atomicSize = Context.getTypeSize(Ty);
+ if (valueSize != atomicSize) {
+ assert(valueSize < atomicSize);
+ llvm::Type *elts[] = {
+ ResultType,
+ llvm::ArrayType::get(CGM.Int8Ty, (atomicSize - valueSize) / 8)
+ };
+ ResultType = llvm::StructType::get(getLLVMContext(),
+ llvm::makeArrayRef(elts));
+ }
break;
}
}
@@ -567,6 +607,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
return ResultType;
}
+bool CodeGenModule::isPaddedAtomicType(QualType type) {
+ return isPaddedAtomicType(type->castAs<AtomicType>());
+}
+
+bool CodeGenModule::isPaddedAtomicType(const AtomicType *type) {
+ return Context.getTypeSize(type) != Context.getTypeSize(type->getValueType());
+}
+
/// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// TagDecl's are not necessarily unique, instead use the (clang)
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 0519911a07ef..11fd76fb19a9 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -16,8 +16,8 @@
#include "CGCall.h"
#include "clang/AST/GlobalDecl.h"
-#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/Module.h"
#include <vector>
namespace llvm {
@@ -58,6 +58,7 @@ namespace CodeGen {
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTypes {
+public:
// Some of this stuff should probably be left on the CGM.
ASTContext &Context;
const TargetInfo &Target;
@@ -68,6 +69,7 @@ class CodeGenTypes {
const CodeGenOptions &CodeGenOpts;
CodeGenModule &CGM;
+private:
/// The opaque type map for Objective-C interfaces. All direct
/// manipulation is done by the runtime interfaces, which are
/// responsible for coercing to the appropriate type; these opaque
@@ -195,6 +197,8 @@ public:
const CallArgList &args,
FunctionType::ExtInfo info,
RequiredArgs required);
+ const CGFunctionInfo &arrangeBlockFunctionCall(const CallArgList &args,
+ const FunctionType *type);
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
const FunctionProtoType *type,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 245150c88d0a..e25d422d2367 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -25,33 +25,21 @@
#include "CodeGenModule.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
-#include "llvm/Value.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Value.h"
using namespace clang;
using namespace CodeGen;
namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {
-private:
- llvm::IntegerType *PtrDiffTy;
protected:
bool IsARM;
- // It's a little silly for us to cache this.
- llvm::IntegerType *getPtrDiffTy() {
- if (!PtrDiffTy) {
- QualType T = getContext().getPointerDiffType();
- llvm::Type *Ty = CGM.getTypes().ConvertType(T);
- PtrDiffTy = cast<llvm::IntegerType>(Ty);
- }
- return PtrDiffTy;
- }
-
public:
ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
- CGCXXABI(CGM), PtrDiffTy(0), IsARM(IsARM) { }
+ CGCXXABI(CGM), IsARM(IsARM) { }
bool isZeroInitializable(const MemberPointerType *MPT);
@@ -112,6 +100,21 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ llvm::Value *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);
+
+ RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This);
+
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
@@ -129,8 +132,6 @@ public:
llvm::GlobalVariable *DeclPtr, bool PerformInit);
void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
llvm::Constant *addr);
-
- void EmitVTables(const CXXRecordDecl *Class);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -164,11 +165,11 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
CharUnits cookieSize);
-private:
/// \brief Returns true if the given instance method is one of the
/// kinds that the ARM ABI says returns 'this'.
- static bool HasThisReturn(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ bool HasThisReturn(GlobalDecl GD) const {
+ const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());
+ if (!MD) return false;
return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
(isa<CXXConstructorDecl>(MD)));
}
@@ -176,18 +177,33 @@ private:
}
CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
- return new ItaniumCXXABI(CGM);
-}
-
-CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) {
- return new ARMCXXABI(CGM);
+ switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ // For IR-generation purposes, there's no significant difference
+ // between the ARM and iOS ABIs.
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
+ return new ARMCXXABI(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.
+ case TargetCXXABI::GenericAArch64:
+ return new ItaniumCXXABI(CGM, /*IsARM = */ true);
+
+ case TargetCXXABI::GenericItanium:
+ return new ItaniumCXXABI(CGM);
+
+ case TargetCXXABI::Microsoft:
+ llvm_unreachable("Microsoft ABI is not Itanium-based");
+ }
+ llvm_unreachable("bad ABI kind");
}
llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
- return getPtrDiffTy();
- return llvm::StructType::get(getPtrDiffTy(), getPtrDiffTy(), NULL);
+ return CGM.PtrDiffTy;
+ return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, NULL);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -226,8 +242,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
- llvm::IntegerType *ptrdiff = getPtrDiffTy();
- llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1);
+ llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual");
llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual");
@@ -300,7 +315,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
llvm::Value *Base,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
- assert(MemPtr->getType() == getPtrDiffTy());
+ assert(MemPtr->getType() == CGM.PtrDiffTy);
CGBuilderTy &Builder = CGF.Builder;
@@ -448,14 +463,12 @@ ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *
ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- llvm::Type *ptrdiff_t = getPtrDiffTy();
-
// Itanium C++ ABI 2.3:
// A NULL pointer is represented as -1.
if (MPT->isMemberDataPointer())
- return llvm::ConstantInt::get(ptrdiff_t, -1ULL, /*isSigned=*/true);
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, -1ULL, /*isSigned=*/true);
- llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0);
+ llvm::Constant *Zero = llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
llvm::Constant *Values[2] = { Zero, Zero };
return llvm::ConstantStruct::getAnon(Values);
}
@@ -466,7 +479,7 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
// Itanium C++ ABI 2.3:
// A pointer to data member is an offset from the base address of
// the class object containing it, represented as a ptrdiff_t
- return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity());
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity());
}
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
@@ -479,7 +492,6 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
MD = MD->getCanonicalDecl();
CodeGenTypes &Types = CGM.getTypes();
- llvm::Type *ptrdiff_t = getPtrDiffTy();
// Get the function pointer (or index if this is a virtual function).
llvm::Constant *MemPtr[2];
@@ -498,16 +510,16 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// least significant bit of adj then makes exactly the same
// discrimination as the least significant bit of ptr does for
// Itanium.
- MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t,
+ MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
2 * ThisAdjustment.getQuantity() + 1);
} else {
// Itanium C++ ABI 2.3:
// For a virtual function, [the pointer field] is 1 plus the
// virtual table offset (in bytes) of the function,
// represented as a ptrdiff_t.
- MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t,
+ MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset + 1);
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
ThisAdjustment.getQuantity());
}
} else {
@@ -520,12 +532,12 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
} else {
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
// function type is incomplete.
- Ty = ptrdiff_t;
+ Ty = CGM.PtrDiffTy;
}
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
- MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, (IsARM ? 2 : 1) *
+ MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, (IsARM ? 2 : 1) *
ThisAdjustment.getQuantity());
}
@@ -650,7 +662,7 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
/// For member data pointers, this is just a check against -1.
if (MPT->isMemberDataPointer()) {
- assert(MemPtr->getType() == getPtrDiffTy());
+ assert(MemPtr->getType() == CGM.PtrDiffTy);
llvm::Value *NegativeOne =
llvm::Constant::getAllOnesValue(MemPtr->getType());
return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool");
@@ -806,6 +818,41 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
+llvm::Value *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);
+ QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, VTTTy, ArgBeg, ArgEnd);
+ return Callee;
+}
+
+RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This) {
+ assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
+
+ const CGFunctionInfo *FInfo
+ = &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType);
+ llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
+ llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
+
+ return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
+ /*ImplicitParam=*/0, QualType(), 0, 0);
+}
+
void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType) {
if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
@@ -883,50 +930,46 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
}
CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
- // On ARM, the cookie is always:
+ // ARM says that the cookie is always:
// struct array_cookie {
// std::size_t element_size; // element_size != 0
// std::size_t element_count;
// };
- // TODO: what should we do if the allocated type actually wants
- // greater alignment?
- return CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes);
+ // But the base ABI doesn't give anything an alignment greater than
+ // 8, so we can dismiss this as typical ABI-author blindness to
+ // actual language complexity and round up to the element alignment.
+ return std::max(CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes),
+ CGM.getContext().getTypeAlignInChars(elementType));
}
llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
- llvm::Value *NewPtr,
- llvm::Value *NumElements,
+ llvm::Value *newPtr,
+ llvm::Value *numElements,
const CXXNewExpr *expr,
- QualType ElementType) {
+ QualType elementType) {
assert(requiresArrayCookie(expr));
- // NewPtr is a char*.
-
- unsigned AS = NewPtr->getType()->getPointerAddressSpace();
-
- ASTContext &Ctx = getContext();
- CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
- llvm::IntegerType *SizeTy =
- cast<llvm::IntegerType>(CGF.ConvertType(Ctx.getSizeType()));
+ // NewPtr is a char*, but we generalize to arbitrary addrspaces.
+ unsigned AS = newPtr->getType()->getPointerAddressSpace();
// The cookie is always at the start of the buffer.
- llvm::Value *CookiePtr = NewPtr;
+ llvm::Value *cookie = newPtr;
// The first element is the element size.
- CookiePtr = CGF.Builder.CreateBitCast(CookiePtr, SizeTy->getPointerTo(AS));
- llvm::Value *ElementSize = llvm::ConstantInt::get(SizeTy,
- Ctx.getTypeSizeInChars(ElementType).getQuantity());
- CGF.Builder.CreateStore(ElementSize, CookiePtr);
+ cookie = CGF.Builder.CreateBitCast(cookie, CGF.SizeTy->getPointerTo(AS));
+ llvm::Value *elementSize = llvm::ConstantInt::get(CGF.SizeTy,
+ getContext().getTypeSizeInChars(elementType).getQuantity());
+ CGF.Builder.CreateStore(elementSize, cookie);
// The second element is the element count.
- CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_32(CookiePtr, 1);
- CGF.Builder.CreateStore(NumElements, CookiePtr);
+ cookie = CGF.Builder.CreateConstInBoundsGEP1_32(cookie, 1);
+ CGF.Builder.CreateStore(numElements, cookie);
// Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely.
- CharUnits CookieSize = 2 * SizeSize;
- return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr,
- CookieSize.getQuantity());
+ CharUnits cookieSize = ARMCXXABI::getArrayCookieSizeImpl(elementType);
+ return CGF.Builder.CreateConstInBoundsGEP1_64(newPtr,
+ cookieSize.getQuantity());
}
llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
@@ -952,8 +995,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
@@ -962,8 +1006,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
@@ -972,8 +1017,9 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
namespace {
@@ -982,8 +1028,8 @@ namespace {
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()),
+ Guard);
}
};
}
@@ -1009,8 +1055,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (useInt8GuardVariable) {
guardTy = CGF.Int8Ty;
} else {
- // Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
- guardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty);
+ // Guard variables are 64 bits in the generic ABI and size width on ARM
+ // (i.e. 32-bit on AArch32, 64-bit on AArch64).
+ guardTy = (IsARM ? CGF.SizeTy : CGF.Int64Ty);
}
llvm::PointerType *guardPtrTy = guardTy->getPointerTo();
@@ -1053,7 +1100,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// }
if (IsARM && !useInt8GuardVariable) {
llvm::Value *V = Builder.CreateLoad(guard);
- V = Builder.CreateAnd(V, Builder.getInt32(1));
+ 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:
@@ -1100,7 +1148,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (threadsafe) {
// Call __cxa_guard_acquire.
llvm::Value *V
- = Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
+ = CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
@@ -1121,7 +1169,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
CGF.PopCleanupBlock();
// Call __cxa_guard_release. This cannot throw.
- Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
+ CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
} else {
Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard);
}
@@ -1159,7 +1207,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
handle
};
- CGF.Builder.CreateCall(atexit, args)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(atexit, args);
}
/// Register a global destructor as best as we know how.
@@ -1180,8 +1228,3 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
CGF.registerGlobalDtorWithAtExit(dtor, addr);
}
-
-/// Generate and emit virtual tables for the given class.
-void ItaniumCXXABI::EmitVTables(const CXXRecordDecl *Class) {
- CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class);
-}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 8d205c3d0f5d..00b15c9a49c4 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -42,13 +42,12 @@ public:
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
+ llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+
void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
CXXDtorType Type,
CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
- // TODO: 'for base' flag
- }
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
@@ -56,13 +55,25 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ llvm::Value *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);
+
+ RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This);
+
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
bool PerformInit);
- void EmitVTables(const CXXRecordDecl *Class);
-
-
// ==== Notes on array cookies =========
//
// MSVC seems to only use cookies when the class has a destructor; a
@@ -98,6 +109,33 @@ public:
llvm::Value *allocPtr,
CharUnits cookieSize);
static bool needThisReturn(GlobalDecl GD);
+
+private:
+ llvm::Constant *getSimpleNullMemberPointer(const MemberPointerType *MPT);
+
+ llvm::Constant *getZeroPtrDiff() {
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
+ }
+
+ llvm::Constant *getAllOnesPtrDiff() {
+ return llvm::Constant::getAllOnesValue(CGM.PtrDiffTy);
+ }
+
+public:
+ virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
+
+ virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
+ CharUnits offset);
+
+ virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT);
+
+ virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF,
+ llvm::Value *Base,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT);
+
};
}
@@ -119,9 +157,57 @@ void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place
- // TODO: 'for base' flag
+
// Ctor returns this ptr
ResTy = ArgTys[0];
+
+ const CXXRecordDecl *Class = Ctor->getParent();
+ if (Class->getNumVBases()) {
+ // Constructors of classes with virtual bases take an implicit parameter.
+ ArgTys.push_back(CGM.getContext().IntTy);
+ }
+}
+
+llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler(
+ CodeGenFunction &CGF) {
+ llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
+ assert(IsMostDerivedClass &&
+ "ctor for a class with virtual bases must have an implicit parameter");
+ llvm::Value *IsCompleteObject
+ = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
+
+ llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases");
+ llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases");
+ CGF.Builder.CreateCondBr(IsCompleteObject,
+ CallVbaseCtorsBB, SkipVbaseCtorsBB);
+
+ CGF.EmitBlock(CallVbaseCtorsBB);
+ // FIXME: emit vbtables somewhere around here.
+
+ // CGF will put the base ctor calls in this basic block for us later.
+
+ return SkipVbaseCtorsBB;
+}
+
+void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
+ CXXDtorType Type,
+ CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) {
+ // 'this' is already in place
+ // TODO: 'for base' flag
+
+ if (Type == Dtor_Deleting) {
+ // The scalar deleting destructor takes an implicit bool parameter.
+ ArgTys.push_back(CGM.getContext().BoolTy);
+ }
+}
+
+static bool IsDeletingDtor(GlobalDecl GD) {
+ const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
+ if (isa<CXXDestructorDecl>(MD)) {
+ return GD.getDtorType() == Dtor_Deleting;
+ }
+ return false;
}
void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
@@ -131,6 +217,26 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
if (needThisReturn(CGF.CurGD)) {
ResTy = Params[0]->getType();
}
+
+ ASTContext &Context = getContext();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+ if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
+ ImplicitParamDecl *IsMostDerived
+ = ImplicitParamDecl::Create(Context, 0,
+ CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("is_most_derived"),
+ Context.IntTy);
+ Params.push_back(IsMostDerived);
+ getStructorImplicitParamDecl(CGF) = IsMostDerived;
+ } else if (IsDeletingDtor(CGF.CurGD)) {
+ ImplicitParamDecl *ShouldDelete
+ = ImplicitParamDecl::Create(Context, 0,
+ CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("should_call_delete"),
+ Context.BoolTy);
+ Params.push_back(ShouldDelete);
+ getStructorImplicitParamDecl(CGF) = ShouldDelete;
+ }
}
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
@@ -138,6 +244,73 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
if (needThisReturn(CGF.CurGD)) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
+
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+ if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
+ assert(getStructorImplicitParamDecl(CGF) &&
+ "no implicit parameter for a constructor with virtual bases?");
+ getStructorImplicitParamValue(CGF)
+ = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
+ "is_most_derived");
+ }
+
+ if (IsDeletingDtor(CGF.CurGD)) {
+ assert(getStructorImplicitParamDecl(CGF) &&
+ "no implicit parameter for a deleting destructor?");
+ getStructorImplicitParamValue(CGF)
+ = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
+ "should_call_delete");
+ }
+}
+
+llvm::Value *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) {
+ 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;
+ }
+
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ ImplicitParam, ImplicitParamTy,
+ ArgBeg, ArgEnd);
+ return Callee;
+}
+
+RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This) {
+ assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
+
+ // We have only one destructor in the vftable but can get both behaviors
+ // by passing an implicit bool parameter.
+ const CGFunctionInfo *FInfo
+ = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
+ llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, This, Ty);
+
+ ASTContext &Context = CGF.getContext();
+ llvm::Value *ImplicitParam
+ = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
+ DtorType == Dtor_Deleting);
+
+ return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
+ ImplicitParam, Context.BoolTy, 0, 0);
}
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
@@ -206,8 +379,93 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
}
-void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) {
- // FIXME: implement
+// Returns true for member pointer types that we know how to represent with a
+// simple ptrdiff_t. Currently we only know how to emit, test, and load member
+// data pointers for complete single inheritance classes.
+static bool isSimpleMemberPointer(const MemberPointerType *MPT) {
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ return (MPT->isMemberDataPointer() &&
+ !MPT->getClass()->isIncompleteType() &&
+ RD->getNumVBases() == 0);
+}
+
+llvm::Constant *
+MicrosoftCXXABI::getSimpleNullMemberPointer(const MemberPointerType *MPT) {
+ if (isSimpleMemberPointer(MPT)) {
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ // A null member data pointer is represented as -1 if the class is not
+ // polymorphic, and 0 otherwise.
+ if (RD->isPolymorphic())
+ return getZeroPtrDiff();
+ return getAllOnesPtrDiff();
+ }
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
+ if (isSimpleMemberPointer(MPT))
+ return getSimpleNullMemberPointer(MPT);
+ // FIXME: Implement function member pointers.
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
+ CharUnits offset) {
+ // Member data pointers are plain offsets when no virtual bases are involved.
+ if (isSimpleMemberPointer(MPT))
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity());
+ // FIXME: Implement member pointers other inheritance models.
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
+ CGBuilderTy &Builder = CGF.Builder;
+
+ // For member data pointers, this is just a check against -1 or 0.
+ if (isSimpleMemberPointer(MPT)) {
+ llvm::Constant *Val = getSimpleNullMemberPointer(MPT);
+ return Builder.CreateICmpNE(MemPtr, Val, "memptr.tobool");
+ }
+
+ // FIXME: Implement member pointers other inheritance models.
+ ErrorUnsupportedABI(CGF, "function member pointer tests");
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
+ llvm::Value *Base,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
+ unsigned AS = Base->getType()->getPointerAddressSpace();
+ llvm::Type *PType =
+ CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
+ CGBuilderTy &Builder = CGF.Builder;
+
+ if (MPT->isMemberFunctionPointer()) {
+ ErrorUnsupportedABI(CGF, "function member pointer address");
+ return llvm::Constant::getNullValue(PType);
+ }
+
+ llvm::Value *Addr;
+ if (isSimpleMemberPointer(MPT)) {
+ // Add the offset with GEP and i8*.
+ assert(MemPtr->getType() == CGM.PtrDiffTy);
+ Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
+ Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset");
+ } else {
+ ErrorUnsupportedABI(CGF, "non-scalar member pointers");
+ return llvm::Constant::getNullValue(PType);
+ }
+
+ // Cast the address to the appropriate pointer type, adopting the address
+ // space of the base pointer.
+ return Builder.CreateBitCast(Addr, PType);
}
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 012555962f82..d6e5f0673f82 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -13,16 +13,16 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "CodeGenModule.h"
-#include "clang/Frontend/CodeGenOptions.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 "llvm/LLVMContext.h"
-#include "llvm/Module.h"
-#include "llvm/DataLayout.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
using namespace clang;
namespace {
@@ -31,13 +31,16 @@ namespace {
OwningPtr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
+ const TargetOptions TargetOpts; // Intentionally copied in.
protected:
OwningPtr<llvm::Module> M;
OwningPtr<CodeGen::CodeGenModule> Builder;
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName,
- const CodeGenOptions &CGO, llvm::LLVMContext& C)
- : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {}
+ const CodeGenOptions &CGO, const TargetOptions &TO,
+ llvm::LLVMContext& C)
+ : Diags(diags), CodeGenOpts(CGO), TargetOpts(TO),
+ M(new llvm::Module(ModuleName, C)) {}
virtual ~CodeGeneratorImpl() {}
@@ -55,7 +58,7 @@ namespace {
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
- Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
+ Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, TargetOpts,
*M, *TD, Diags));
}
@@ -122,6 +125,7 @@ void CodeGenerator::anchor() { }
CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string& ModuleName,
const CodeGenOptions &CGO,
+ const TargetOptions &TO,
llvm::LLVMContext& C) {
- return new CodeGeneratorImpl(Diags, ModuleName, CGO, C);
+ return new CodeGeneratorImpl(Diags, ModuleName, CGO, TO, C);
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index ffff0d0a1bc4..7cc63b7db15d 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -17,9 +17,9 @@
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Type.h"
-#include "llvm/DataLayout.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace CodeGen;
@@ -37,7 +37,7 @@ static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
}
static bool isAggregateTypeForABI(QualType T) {
- return CodeGenFunction::hasAggregateLLVMType(T) ||
+ return !CodeGenFunction::hasScalarEvaluationKind(T) ||
T->isMemberFunctionPointerType();
}
@@ -95,6 +95,7 @@ unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
// x86-32 FreeBSD, Linux, Darwin
// PowerPC Linux, Darwin
// ARM Darwin (*not* EABI)
+ // AArch64 Linux
return 32;
}
@@ -173,7 +174,7 @@ static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) {
if (!RD)
return false;
- return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
+ return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor();
}
/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
@@ -266,9 +267,15 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
}
static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
+ // Treat complex types as the element type.
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>())
+ Ty = CTy->getElementType();
+
+ // Check for a type which we know has a simple scalar argument-passing
+ // convention without any padding. (We're specifically looking for 32
+ // and 64-bit integer and integer-equivalents, float, and double.)
if (!Ty->getAs<BuiltinType>() && !Ty->hasPointerRepresentation() &&
- !Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
- !Ty->isBlockPointerType())
+ !Ty->isEnumeralType() && !Ty->isBlockPointerType())
return false;
uint64_t Size = Context.getTypeSize(Ty);
@@ -414,6 +421,8 @@ class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ // Obtain the initial number of registers available for passing integers
+ // from the function's regparm attribute.
unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0;
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
@@ -426,15 +435,18 @@ llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return 0;
}
+// \brief Classify argument of given type \p Ty. \p FreeRegs is the number of
+// registers available for passing arguments - it can be updated by this
+// method.
ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty,
unsigned &FreeRegs) const {
if (isAggregateTypeForABI(Ty)) {
- // Records with non trivial destructors/constructors should not be passed
- // by value.
+ // In the PNaCl ABI we always pass records/structures on the stack. The
+ // byval attribute can be used if the record doesn't have non-trivial
+ // constructors/destructors.
FreeRegs = 0;
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
return ABIArgInfo::getIndirect(0);
}
@@ -445,14 +457,17 @@ ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty,
ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- // Regparm regs hold 32 bits.
- unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- if (SizeInRegs == 0) return BaseInfo;
- if (SizeInRegs > FreeRegs) {
+ // Figure out how many of the free registers can be occupied by this type.
+ // regparm registers are 32-bit.
+ unsigned NumRegsRequired = (getContext().getTypeSize(Ty) + 31) / 32;
+ if (NumRegsRequired == 0) return BaseInfo;
+ if (NumRegsRequired > FreeRegs) {
+ // If this type needs more registers than we have available, no more
+ // passing in-registers can happen.
FreeRegs = 0;
return BaseInfo;
}
- FreeRegs -= SizeInRegs;
+ FreeRegs -= NumRegsRequired;
return BaseInfo.isDirect() ?
ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) :
ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType());
@@ -462,6 +477,7 @@ ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
+ // In the PNaCl ABI we always return records/structures on the stack.
if (isAggregateTypeForABI(RetTy))
return ABIArgInfo::getIndirect(0);
@@ -473,11 +489,9 @@ ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
-/// UseX86_MMXType - Return true if this is an MMX type that should use the
-/// special x86_mmx type.
-bool UseX86_MMXType(llvm::Type *IRType) {
- // If the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>, use the
- // special x86_mmx type.
+/// IsX86_MMXType - Return true if this is an MMX type.
+bool IsX86_MMXType(llvm::Type *IRType) {
+ // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>.
return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 &&
cast<llvm::VectorType>(IRType)->getElementType()->isIntegerTy() &&
IRType->getScalarSizeInBits() != 64;
@@ -506,7 +520,6 @@ class X86_32ABIInfo : public ABIInfo {
bool IsDarwinVectorABI;
bool IsSmallStructInRegABI;
- bool IsMMXDisabled;
bool IsWin32FloatStructABI;
unsigned DefaultNumRegisterParameters;
@@ -539,18 +552,17 @@ public:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w,
+ X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool w,
unsigned r)
: ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
- IsMMXDisabled(m), IsWin32FloatStructABI(w),
- DefaultNumRegisterParameters(r) {}
+ IsWin32FloatStructABI(w), DefaultNumRegisterParameters(r) {}
};
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
- bool d, bool p, bool m, bool w, unsigned r)
- :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w, r)) {}
+ bool d, bool p, bool w, unsigned r)
+ :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, w, r)) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const;
@@ -903,15 +915,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
Size));
}
- llvm::Type *IRType = CGT.ConvertType(Ty);
- if (UseX86_MMXType(IRType)) {
- if (IsMMXDisabled)
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- 64));
- ABIArgInfo AAI = ABIArgInfo::getDirect(IRType);
- AAI.setCoerceToType(llvm::Type::getX86_MMXTy(getVMContext()));
- return AAI;
- }
+ if (IsX86_MMXType(CGT.ConvertType(Ty)))
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64));
return ABIArgInfo::getDirect();
}
@@ -1013,8 +1018,10 @@ void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
// Now add the 'alignstack' attribute with a value of 16.
llvm::AttrBuilder B;
B.addStackAlignmentAttr(16);
- Fn->addAttribute(llvm::AttrListPtr::FunctionIndex,
- llvm::Attributes::get(CGM.getLLVMContext(), B));
+ Fn->addAttributes(llvm::AttributeSet::FunctionIndex,
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ B));
}
}
}
@@ -1381,7 +1388,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
} else if ((k == BuiltinType::Float || k == BuiltinType::Double) ||
(k == BuiltinType::LongDouble &&
getContext().getTargetInfo().getTriple().getOS() ==
- llvm::Triple::NativeClient)) {
+ llvm::Triple::NaCl)) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
Lo = X87;
@@ -1470,7 +1477,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
else if (ET == getContext().DoubleTy ||
(ET == getContext().LongDoubleTy &&
getContext().getTargetInfo().getTriple().getOS() ==
- llvm::Triple::NativeClient))
+ llvm::Triple::NaCl))
Lo = Hi = SSE;
else if (ET == getContext().LongDoubleTy)
Current = ComplexX87;
@@ -2777,6 +2784,9 @@ PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const {
ABIArgInfo
PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
+ if (Ty->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
if (isAggregateTypeForABI(Ty)) {
// Records with non trivial destructors/constructors should not be passed
// by value.
@@ -2795,6 +2805,9 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
if (isAggregateTypeForABI(RetTy))
return ABIArgInfo::getIndirect(0);
@@ -2813,14 +2826,52 @@ 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");
- // Update the va_list pointer.
+ // 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
+ // size of the object is 16 bytes; see below for further explanation.
unsigned SizeInBytes = CGF.getContext().getTypeSize(Ty) / 8;
+ QualType BaseTy;
+ unsigned CplxBaseSize = 0;
+
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
+ BaseTy = CTy->getElementType();
+ CplxBaseSize = CGF.getContext().getTypeSize(BaseTy) / 8;
+ if (CplxBaseSize < 8)
+ SizeInBytes = 16;
+ }
+
unsigned Offset = llvm::RoundUpToAlignment(SizeInBytes, 8);
llvm::Value *NextAddr =
Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int64Ty, Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+ // If we have a complex type and the base type is smaller than 8 bytes,
+ // the ABI calls for the real and imaginary parts to be right-adjusted
+ // in separate doublewords. However, Clang expects us to produce a
+ // pointer to a structure with the two parts packed tightly. So generate
+ // loads of the real and imaginary parts relative to the va_list pointer,
+ // and store them to a temporary structure.
+ 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));
+ llvm::Type *PBaseTy = llvm::PointerType::getUnqual(CGF.ConvertType(BaseTy));
+ RealAddr = Builder.CreateIntToPtr(RealAddr, PBaseTy);
+ ImagAddr = Builder.CreateIntToPtr(ImagAddr, PBaseTy);
+ llvm::Value *Real = Builder.CreateLoad(RealAddr, false, ".vareal");
+ llvm::Value *Imag = Builder.CreateLoad(ImagAddr, false, ".vaimag");
+ llvm::Value *Ptr = CGF.CreateTempAlloca(CGT.ConvertTypeForMem(Ty),
+ "vacplx");
+ llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, ".real");
+ llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, ".imag");
+ Builder.CreateStore(Real, RealPtr, false);
+ Builder.CreateStore(Imag, ImagPtr, false);
+ return Ptr;
+ }
+
// 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.
@@ -2908,7 +2959,9 @@ private:
ABIKind Kind;
public:
- ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {}
+ ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {
+ setRuntimeCC();
+ }
bool isEABI() const {
StringRef Env =
@@ -2930,6 +2983,10 @@ private:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
+
+ llvm::CallingConv::ID getLLVMDefaultCC() const;
+ llvm::CallingConv::ID getABIDefaultCC() const;
+ void setRuntimeCC();
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -2999,32 +3056,41 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getCallingConvention() != llvm::CallingConv::C)
return;
- // Calling convention as default by an ABI.
- llvm::CallingConv::ID DefaultCC;
+ llvm::CallingConv::ID cc = getRuntimeCC();
+ if (cc != llvm::CallingConv::C)
+ FI.setEffectiveCallingConvention(cc);
+}
+
+/// Return the default calling convention that LLVM will use.
+llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
+ // The default calling convention that LLVM will infer.
if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf")
- DefaultCC = llvm::CallingConv::ARM_AAPCS_VFP;
+ return llvm::CallingConv::ARM_AAPCS_VFP;
else if (isEABI())
- DefaultCC = llvm::CallingConv::ARM_AAPCS;
+ return llvm::CallingConv::ARM_AAPCS;
else
- DefaultCC = llvm::CallingConv::ARM_APCS;
+ return llvm::CallingConv::ARM_APCS;
+}
- // If user did not ask for specific calling convention explicitly (e.g. via
- // pcs attribute), set effective calling convention if it's different than ABI
- // default.
+/// Return the calling convention that our ABI would like us to use
+/// as the C calling convention.
+llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const {
switch (getABIKind()) {
- case APCS:
- if (DefaultCC != llvm::CallingConv::ARM_APCS)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
- break;
- case AAPCS:
- if (DefaultCC != llvm::CallingConv::ARM_AAPCS)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
- break;
- case AAPCS_VFP:
- if (DefaultCC != llvm::CallingConv::ARM_AAPCS_VFP)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
- break;
+ case APCS: return llvm::CallingConv::ARM_APCS;
+ case AAPCS: return llvm::CallingConv::ARM_AAPCS;
+ case AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
}
+ llvm_unreachable("bad ABI kind");
+}
+
+void ARMABIInfo::setRuntimeCC() {
+ assert(getRuntimeCC() == llvm::CallingConv::C);
+
+ // Don't muddy up the IR with a ton of explicit annotations if
+ // they'd just match what LLVM will infer from the triple.
+ llvm::CallingConv::ID abiCC = getABIDefaultCC();
+ if (abiCC != getLLVMDefaultCC())
+ RuntimeCC = abiCC;
}
/// isHomogeneousAggregate - Return true if a type is an AAPCS-VFP homogeneous
@@ -3539,6 +3605,420 @@ 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);
+ }
+
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
+ if (FreeIntRegs > 0)
+ --FreeIntRegs;
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
+
+ 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
//===----------------------------------------------------------------------===//
@@ -3563,6 +4043,8 @@ public:
virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &M) const;
+private:
+ static void addKernelMetadata(llvm::Function *F);
};
ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
@@ -3590,25 +4072,7 @@ void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getCallingConvention() != llvm::CallingConv::C)
return;
- // Calling convention as default by an ABI.
- // We're still using the PTX_Kernel/PTX_Device calling conventions here,
- // but we should switch to NVVM metadata later on.
- llvm::CallingConv::ID DefaultCC;
- const LangOptions &LangOpts = getContext().getLangOpts();
- if (LangOpts.OpenCL || LangOpts.CUDA) {
- // If we are in OpenCL or CUDA mode, then default to device functions
- DefaultCC = llvm::CallingConv::PTX_Device;
- } else {
- // If we are in standard C/C++ mode, use the triple to decide on the default
- StringRef Env =
- getContext().getTargetInfo().getTriple().getEnvironmentName();
- if (Env == "device")
- DefaultCC = llvm::CallingConv::PTX_Device;
- else
- DefaultCC = llvm::CallingConv::PTX_Kernel;
- }
- FI.setEffectiveCallingConvention(DefaultCC);
-
+ FI.setEffectiveCallingConvention(getRuntimeCC());
}
llvm::Value *NVPTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -3626,26 +4090,43 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// Perform special handling in OpenCL mode
if (M.getLangOpts().OpenCL) {
- // Use OpenCL function attributes to set proper calling conventions
+ // Use OpenCL function attributes to check for kernel functions
// By default, all functions are device functions
if (FD->hasAttr<OpenCLKernelAttr>()) {
- // OpenCL __kernel functions get a kernel calling convention
- F->setCallingConv(llvm::CallingConv::PTX_Kernel);
+ // OpenCL __kernel functions get kernel metadata
+ addKernelMetadata(F);
// And kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
}
}
// Perform special handling in CUDA mode.
if (M.getLangOpts().CUDA) {
- // CUDA __global__ functions get a kernel calling convention. Since
+ // 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>())
- F->setCallingConv(llvm::CallingConv::PTX_Kernel);
+ addKernelMetadata(F);
}
}
+void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) {
+ 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));
+
+ // Append metadata to nvvm.annotations
+ MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
+}
+
}
//===----------------------------------------------------------------------===//
@@ -3748,7 +4229,7 @@ void MBlazeTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(CC);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
}
// Step 3: Emit _interrupt_handler alias.
@@ -3786,12 +4267,12 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(llvm::CallingConv::MSP430_INTR);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
// Step 3: Emit ISR vector alias.
- unsigned Num = attr->getNumber() + 0xffe0;
+ unsigned Num = attr->getNumber() / 2;
new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
- "vector_" + Twine::utohexstr(Num),
+ "__isr_" + Twine(Num),
GV, &M.getModule());
}
}
@@ -3834,6 +4315,19 @@ public:
return 29;
}
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) return;
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ if (FD->hasAttr<Mips16Attr>()) {
+ Fn->addFnAttr("mips16");
+ }
+ else if (FD->hasAttr<NoMips16Attr>()) {
+ Fn->addFnAttr("nomips16");
+ }
+ }
+
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const;
@@ -3963,7 +4457,8 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
if (Ty->isPromotableIntegerType())
return ABIArgInfo::getExtend();
- return ABIArgInfo::getDirect(0, 0, getPaddingType(Align, OrigOffset));
+ return ABIArgInfo::getDirect(0, 0,
+ IsO32 ? 0 : getPaddingType(Align, OrigOffset));
}
llvm::Type*
@@ -4143,7 +4638,7 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
if (M.getLangOpts().OpenCL) {
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL C Kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
@@ -4337,6 +4832,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::mips64el:
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false));
+ case llvm::Triple::aarch64:
+ return *(TheTargetCodeGenInfo = new AArch64TargetCodeGenInfo(Types));
+
case llvm::Triple::arm:
case llvm::Triple::thumb:
{
@@ -4348,7 +4846,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
Kind = ARMABIInfo::AAPCS_VFP;
switch (Triple.getOS()) {
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return *(TheTargetCodeGenInfo =
new NaClARMTargetCodeGenInfo(Types, Kind));
default:
@@ -4379,11 +4877,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types));
case llvm::Triple::x86: {
- bool DisableMMX = strcmp(getContext().getTargetInfo().getABI(), "no-mmx") == 0;
-
if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX, false,
+ new X86_32TargetCodeGenInfo(Types, true, true, false,
CodeGenOpts.NumRegisterParameters));
switch (Triple.getOS()) {
@@ -4395,19 +4891,17 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::OpenBSD:
case llvm::Triple::Bitrig:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX,
- false,
+ new X86_32TargetCodeGenInfo(Types, false, true, false,
CodeGenOpts.NumRegisterParameters));
case llvm::Triple::Win32:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, true,
+ new X86_32TargetCodeGenInfo(Types, false, true, true,
CodeGenOpts.NumRegisterParameters));
default:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX,
- false,
+ new X86_32TargetCodeGenInfo(Types, false, false, false,
CodeGenOpts.NumRegisterParameters));
}
}
@@ -4420,7 +4914,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::MinGW32:
case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
default:
return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 88b4997d48cc..bb50ce69e312 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -15,8 +15,8 @@
#ifndef CLANG_CODEGEN_TARGETINFO_H
#define CLANG_CODEGEN_TARGETINFO_H
-#include "clang/Basic/LLVM.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
@@ -158,10 +158,13 @@ namespace clang {
/// - the conventions are substantively different in how they pass
/// arguments, because in this case using the variadic convention
/// will lead to C99 violations.
- /// It is not necessarily correct when arguments are passed in the
- /// same way and some out-of-band information is passed for the
- /// benefit of variadic callees, as is the case for x86-64.
- /// In this case the ABI should be consulted.
+ ///
+ /// 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.
virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
const FunctionNoProtoType *fnType) const;
};
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index d7b4bc705305..2b5bbee3db21 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -9,7 +9,6 @@
#include "clang/Driver/Action.h"
#include "llvm/Support/ErrorHandling.h"
-
#include <cassert>
using namespace clang::driver;
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index b3a43df98041..6c57b622b8d2 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -11,7 +11,6 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Option.h"
-
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
@@ -84,7 +83,6 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const {
(*it)->getOption().matches(Id1)) {
Res = *it;
Res->claim();
-
}
}
@@ -308,6 +306,14 @@ const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
return MakeArgString(LHS + RHS);
}
+void ArgList::dump() {
+ llvm::errs() << "ArgList:";
+ for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ llvm::errs() << " " << (*it)->getSpelling();
+ }
+ llvm::errs() << "\n";
+}
+
//
InputArgList::InputArgList(const char* const *ArgBegin,
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index 4f89b73a46d3..904804383670 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/CC1AsOptions.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Option.h"
using namespace clang;
using namespace clang::driver;
using namespace clang::driver::options;
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 124e50c32ea4..1bff4a3d7a72 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -8,20 +8,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Compilation.h"
-
#include "clang/Driver/Action.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
-
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Program.h"
-#include <sys/stat.h>
+#include "llvm/Support/raw_ostream.h"
#include <errno.h>
+#include <sys/stat.h>
using namespace clang::driver;
using namespace clang;
@@ -113,7 +111,7 @@ static bool skipArg(const char *Flag, bool &SkipNextArg) {
bool Res = llvm::StringSwitch<bool>(Flag)
.Cases("-I", "-MF", "-MT", "-MQ", true)
.Cases("-o", "-coverage-file", "-dependency-file", true)
- .Cases("-fdebug-compilation-dir", "-fmodule-cache-path", "-idirafter", true)
+ .Cases("-fdebug-compilation-dir", "-idirafter", true)
.Cases("-include", "-include-pch", "-internal-isystem", true)
.Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
.Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
@@ -201,39 +199,56 @@ void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const {
}
}
+bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
+ llvm::sys::Path P(File);
+ std::string Error;
+
+ // Don't try to remove files which we don't have write access to (but may be
+ // able to remove), or non-regular files. Underlying tools may have
+ // intentionally not overwritten them.
+ if (!P.canWrite() || !P.isRegularFile())
+ return true;
+
+ if (P.eraseFromDisk(false, &Error)) {
+ // Failure is only failure if the file exists and is "regular". There is
+ // a race condition here due to the limited interface of
+ // llvm::sys::Path, we want to know if the removal gave ENOENT.
+
+ // FIXME: Grumble, P.exists() is broken. PR3837.
+ struct stat buf;
+ if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG :
+ (errno != ENOENT)) {
+ if (IssueErrors)
+ getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
+ << Error;
+ return false;
+ }
+ }
+ return true;
+}
+
bool Compilation::CleanupFileList(const ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
-
for (ArgStringList::const_iterator
- it = Files.begin(), ie = Files.end(); it != ie; ++it) {
+ it = Files.begin(), ie = Files.end(); it != ie; ++it)
+ Success &= CleanupFile(*it, IssueErrors);
+ return Success;
+}
- llvm::sys::Path P(*it);
- std::string Error;
+bool Compilation::CleanupFileMap(const ArgStringMap &Files,
+ const JobAction *JA,
+ bool IssueErrors) const {
+ bool Success = true;
+ for (ArgStringMap::const_iterator
+ it = Files.begin(), ie = Files.end(); it != ie; ++it) {
- // Don't try to remove files which we don't have write access to (but may be
- // able to remove). Underlying tools may have intentionally not overwritten
- // them.
- if (!P.canWrite())
+ // If specified, only delete the files associated with the JobAction.
+ // Otherwise, delete all files in the map.
+ if (JA && it->first != JA)
continue;
-
- if (P.eraseFromDisk(false, &Error)) {
- // Failure is only failure if the file exists and is "regular". There is
- // a race condition here due to the limited interface of
- // llvm::sys::Path, we want to know if the removal gave ENOENT.
-
- // FIXME: Grumble, P.exists() is broken. PR3837.
- struct stat buf;
- if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG :
- (errno != ENOENT)) {
- if (IssueErrors)
- getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
- << Error;
- Success = false;
- }
- }
+ Success &= CleanupFile(it->second, IssueErrors);
}
-
return Success;
}
@@ -275,11 +290,12 @@ int Compilation::ExecuteCommand(const Command &C,
}
std::string Error;
+ bool ExecutionFailed;
int Res =
llvm::sys::Program::ExecuteAndWait(Prog, Argv,
/*env*/0, Redirects,
/*secondsToWait*/0, /*memoryLimit*/0,
- &Error);
+ &Error, &ExecutionFailed);
if (!Error.empty()) {
assert(Res && "Error string set with 0 result code!");
getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
@@ -289,24 +305,51 @@ int Compilation::ExecuteCommand(const Command &C,
FailingCommand = &C;
delete[] Argv;
- return Res;
+ return ExecutionFailed ? 1 : Res;
+}
+
+typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList;
+
+static bool ActionFailed(const Action *A,
+ const FailingCommandList &FailingCommands) {
+
+ if (FailingCommands.empty())
+ return false;
+
+ for (FailingCommandList::const_iterator CI = FailingCommands.begin(),
+ CE = FailingCommands.end(); CI != CE; ++CI)
+ if (A == &(CI->second->getSource()))
+ return true;
+
+ for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
+ if (ActionFailed(*AI, FailingCommands))
+ return true;
+
+ return false;
}
-int Compilation::ExecuteJob(const Job &J,
- const Command *&FailingCommand) const {
+static bool InputsOk(const Command &C,
+ const FailingCommandList &FailingCommands) {
+ return !ActionFailed(&C.getSource(), FailingCommands);
+}
+
+void Compilation::ExecuteJob(const Job &J,
+ FailingCommandList &FailingCommands) const {
if (const Command *C = dyn_cast<Command>(&J)) {
- return ExecuteCommand(*C, FailingCommand);
+ if (!InputsOk(*C, FailingCommands))
+ return;
+ const Command *FailingCommand = 0;
+ if (int Res = ExecuteCommand(*C, FailingCommand))
+ FailingCommands.push_back(std::make_pair(Res, FailingCommand));
} else {
const JobList *Jobs = cast<JobList>(&J);
- for (JobList::const_iterator
- it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
- if (int Res = ExecuteJob(**it, FailingCommand))
- return Res;
- return 0;
+ for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
+ it != ie; ++it)
+ ExecuteJob(**it, FailingCommands);
}
}
-void Compilation::initCompilationForDiagnostics(void) {
+void Compilation::initCompilationForDiagnostics() {
// Free actions and jobs.
DeleteContainerPointers(Actions);
Jobs.clear();
@@ -314,6 +357,7 @@ void Compilation::initCompilationForDiagnostics(void) {
// Clear temporary/results file lists.
TempFiles.clear();
ResultFiles.clear();
+ FailureResultFiles.clear();
// Remove any user specified output. Claim any unclaimed arguments, so as
// to avoid emitting warnings about unused args.
@@ -331,6 +375,6 @@ void Compilation::initCompilationForDiagnostics(void) {
Redirects[2] = new const llvm::sys::Path();
}
-StringRef Compilation::getSysRoot(void) const {
+StringRef Compilation::getSysRoot() const {
return getDriver().SysRoot;
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 68471ec04c6a..ad1921b838e3 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Driver.h"
-
+#include "InputInfo.h"
+#include "ToolChains.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
@@ -20,24 +22,20 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
-
-#include "clang/Basic/Version.h"
-
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
-
-#include "InputInfo.h"
-#include "ToolChains.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"
using namespace clang::driver;
@@ -46,7 +44,6 @@ using namespace clang;
Driver::Driver(StringRef ClangExecutable,
StringRef DefaultTargetTriple,
StringRef DefaultImageName,
- bool IsProduction,
DiagnosticsEngine &Diags)
: Opts(createDriverOptTable()), Diags(Diags),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
@@ -129,6 +126,7 @@ const {
// -{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_rewrite_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
@@ -242,7 +240,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (char *env = ::getenv("COMPILER_PATH")) {
StringRef CompilerPath = env;
while (!CompilerPath.empty()) {
- std::pair<StringRef, StringRef> Split = CompilerPath.split(':');
+ std::pair<StringRef, StringRef> Split
+ = CompilerPath.split(llvm::sys::PathSeparator);
PrefixDirs.push_back(Split.first);
CompilerPath = Split.second;
}
@@ -251,7 +250,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: What are we going to do with -V and -b?
// FIXME: This stuff needs to go into the Compilation, not the driver.
- bool CCCPrintOptions = false, CCCPrintActions = false;
+ bool CCCPrintOptions, CCCPrintActions;
InputArgList *Args = ParseArgStrings(ArgList.slice(1));
@@ -293,6 +292,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (Args->hasArg(options::OPT_nostdlib))
UseStdLib = false;
+ if (const Arg *A = Args->getLastArg(options::OPT_resource_dir))
+ ResourceDir = A->getValue();
+
// Perform the default argument translations.
DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args);
@@ -342,8 +344,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
- // Don't try to generate diagnostics for link jobs.
- if (FailingCommand && FailingCommand->getCreator().isLinkJob())
+ // Don't try to generate diagnostics for link or dsymutil jobs.
+ if (FailingCommand && (FailingCommand->getCreator().isLinkJob() ||
+ FailingCommand->getCreator().isDsymutilJob()))
return;
// Print the version of the compiler.
@@ -369,9 +372,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
C.PrintDiagnosticJob(OS, C.getJobs());
OS.flush();
- // Clear stale state and suppress tool output.
+ // Keep track of whether we produce any errors while trying to produce
+ // preprocessed sources.
+ DiagnosticErrorTrap Trap(Diags);
+
+ // Suppress tool output.
C.initCompilationForDiagnostics();
- Diags.Reset();
// Construct the list of inputs.
InputList Inputs;
@@ -398,6 +404,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
}
}
+ if (Inputs.empty()) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s) - no preprocessable inputs.";
+ return;
+ }
+
// Don't attempt to generate preprocessed files if multiple -arch options are
// used, unless they're all duplicates.
llvm::StringSet<> ArchNames;
@@ -416,12 +428,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
return;
}
- if (Inputs.empty()) {
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "Error generating preprocessed source(s) - no preprocessable inputs.";
- return;
- }
-
// 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();
@@ -433,18 +439,18 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
BuildJobs(C);
// If there were errors building the compilation, quit now.
- if (Diags.hasErrorOccurred()) {
+ if (Trap.hasErrorOccurred()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s).";
return;
}
// Generate preprocessed output.
- FailingCommand = 0;
- int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
+ SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
+ C.ExecuteJob(C.getJobs(), FailingCommands);
// If the command succeeded, we are done.
- if (Res == 0) {
+ if (FailingCommands.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "\n********************\n\n"
"PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
@@ -485,8 +491,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
<< "\n\n********************";
} else {
// Failure, remove preprocessed files.
- if (!C.getArgs().hasArg(options::OPT_save_temps))
+ if (!C.getArgs().hasArg(options::OPT_save_temps)) {
C.CleanupFileList(C.getTempFiles(), true);
+ }
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s).";
@@ -494,7 +501,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
}
int Driver::ExecuteCompilation(const Compilation &C,
- const Command *&FailingCommand) const {
+ SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const {
// Just print if -### was present.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
C.PrintJob(llvm::errs(), C.getJobs(), "\n", true);
@@ -505,44 +512,52 @@ int Driver::ExecuteCompilation(const Compilation &C,
if (Diags.hasErrorOccurred())
return 1;
- int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
+ C.ExecuteJob(C.getJobs(), FailingCommands);
// Remove temp files.
C.CleanupFileList(C.getTempFiles());
// If the command succeeded, we are done.
- if (Res == 0)
- return Res;
-
- // Otherwise, remove result files as well.
- if (!C.getArgs().hasArg(options::OPT_save_temps)) {
- C.CleanupFileList(C.getResultFiles(), true);
+ if (FailingCommands.empty())
+ return 0;
- // Failure result files are valid unless we crashed.
- if (Res < 0)
- C.CleanupFileList(C.getFailureResultFiles(), true);
- }
+ // Otherwise, remove result files and print extra information about abnormal
+ // failures.
+ for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it =
+ FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) {
+ int Res = it->first;
+ const Command *FailingCommand = it->second;
+
+ // Remove result files if we're not saving temps.
+ if (!C.getArgs().hasArg(options::OPT_save_temps)) {
+ const JobAction *JA = cast<JobAction>(&FailingCommand->getSource());
+ C.CleanupFileMap(C.getResultFiles(), JA, true);
+
+ // Failure result files are valid unless we crashed.
+ if (Res < 0)
+ C.CleanupFileMap(C.getFailureResultFiles(), JA, true);
+ }
- // 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 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.
- const Tool &FailingTool = FailingCommand->getCreator();
-
- if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
- // FIXME: See FIXME above regarding result code interpretation.
- if (Res < 0)
- Diag(clang::diag::err_drv_command_signalled)
- << FailingTool.getShortName();
- else
- Diag(clang::diag::err_drv_command_failed)
- << FailingTool.getShortName() << Res;
+ // 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
+ // 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.
+ const Tool &FailingTool = FailingCommand->getCreator();
+
+ if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
+ // FIXME: See FIXME above regarding result code interpretation.
+ if (Res < 0)
+ Diag(clang::diag::err_drv_command_signalled)
+ << FailingTool.getShortName();
+ else
+ Diag(clang::diag::err_drv_command_failed)
+ << FailingTool.getShortName() << Res;
+ }
}
-
- return Res;
+ return 0;
}
void Driver::PrintOptions(const ArgList &Args) const {
@@ -861,7 +876,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// Add a 'dsymutil' step if necessary, when debug info is enabled and we
// have a compile input. We need to run 'dsymutil' ourselves in such cases
- // because the debug info will refer to a temporary object file which is
+ // because the debug info will refer to a temporary object file which
// will be removed at the end of the compilation process.
if (Act->getType() == types::TY_Image) {
ActionList Inputs;
@@ -1026,17 +1041,18 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Construct the actions to perform.
ActionList LinkerInputs;
- unsigned NumSteps = 0;
+ 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;
const Arg *InputArg = Inputs[i].second;
- NumSteps = types::getNumCompilationPhases(InputType);
- assert(NumSteps && "Invalid number of steps!");
+ PL.clear();
+ types::getCompilationPhases(InputType, PL);
// If the first step comes after the final phase we are doing as part of
// this compilation, warn the user about it.
- phases::ID InitialPhase = types::getCompilationPhase(InputType, 0);
+ phases::ID InitialPhase = PL[0];
if (InitialPhase > FinalPhase) {
// Claim here to avoid the more general unused warning.
InputArg->claim();
@@ -1071,8 +1087,9 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Build the pipeline for this file.
OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
- for (unsigned i = 0; i != NumSteps; ++i) {
- phases::ID Phase = types::getCompilationPhase(InputType, i);
+ for (llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases>::iterator
+ i = PL.begin(), e = PL.end(); i != e; ++i) {
+ phases::ID Phase = *i;
// We are done if this step is past what the user requested.
if (Phase > FinalPhase)
@@ -1080,7 +1097,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Queue linker inputs.
if (Phase == phases::Link) {
- assert(i + 1 == NumSteps && "linking must be final compilation step.");
+ assert((i + 1) == e && "linking must be final compilation step.");
LinkerInputs.push_back(Current.take());
break;
}
@@ -1108,7 +1125,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// If we are linking, claim any options which are obviously only used for
// compilation.
- if (FinalPhase == phases::Link && (NumSteps == 1))
+ if (FinalPhase == phases::Link && PL.size() == 1)
Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
}
@@ -1154,6 +1171,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new MigrateJobAction(Input, types::TY_Remap);
} else if (Args.hasArg(options::OPT_emit_ast)) {
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 (IsUsingLTO(Args)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
@@ -1272,7 +1291,7 @@ void Driver::BuildJobs(Compilation &C) const {
}
}
-static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
+static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
const JobAction *JA,
const ActionList *&Inputs) {
const Tool *ToolForJob = 0;
@@ -1281,23 +1300,23 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
// bottom up, so what we are actually looking for is an assembler job with a
// compiler input.
- if (C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- TC->IsIntegratedAssemblerDefault()) &&
+ if (TC->useIntegratedAs() &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
isa<AssembleJobAction>(JA) &&
Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
- const Tool &Compiler = TC->SelectTool(
- C, cast<JobAction>(**Inputs->begin()), (*Inputs)[0]->getInputs());
- if (Compiler.hasIntegratedAssembler()) {
+ const Tool *Compiler =
+ TC->SelectTool(cast<JobAction>(**Inputs->begin()));
+ if (!Compiler)
+ return NULL;
+ if (Compiler->hasIntegratedAssembler()) {
Inputs = &(*Inputs)[0]->getInputs();
- ToolForJob = &Compiler;
+ ToolForJob = Compiler;
}
}
// Otherwise use the tool for the current job.
if (!ToolForJob)
- ToolForJob = &TC->SelectTool(C, *JA, *Inputs);
+ ToolForJob = TC->SelectTool(*JA);
// See if we should use an integrated preprocessor. We do so when we have
// exactly one input, since this is the only use case we care about
@@ -1310,7 +1329,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
ToolForJob->hasIntegratedCPP())
Inputs = &(*Inputs)[0]->getInputs();
- return *ToolForJob;
+ return ToolForJob;
}
void Driver::BuildJobsForAction(Compilation &C,
@@ -1352,23 +1371,19 @@ void Driver::BuildJobsForAction(Compilation &C,
const ActionList *Inputs = &A->getInputs();
const JobAction *JA = cast<JobAction>(A);
- const Tool &T = SelectToolForJob(C, TC, JA, Inputs);
+ const Tool *T = SelectToolForJob(C, TC, JA, Inputs);
+ if (!T)
+ return;
// Only use pipes when there is exactly one input.
InputInfoList InputInfos;
for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
it != ie; ++it) {
- // Treat dsymutil sub-jobs as being at the top-level too, they shouldn't get
- // temporary output names.
- //
+ // Treat dsymutil and verify sub-jobs as being at the top-level too, they
+ // shouldn't get temporary output names.
// FIXME: Clean this up.
bool SubJobAtTopLevel = false;
- if (AtTopLevel && isa<DsymutilJobAction>(A))
- SubJobAtTopLevel = true;
-
- // Also treat verify sub-jobs as being at the top-level. They don't
- // produce any output and so don't need temporary output names.
- if (AtTopLevel && isa<VerifyJobAction>(A))
+ if (AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)))
SubJobAtTopLevel = true;
InputInfo II;
@@ -1386,16 +1401,15 @@ void Driver::BuildJobsForAction(Compilation &C,
BaseInput = InputInfos[0].getFilename();
// Determine the place to write output to, if any.
- if (JA->getType() == types::TY_Nothing) {
+ if (JA->getType() == types::TY_Nothing)
Result = InputInfo(A->getType(), BaseInput);
- } else {
+ else
Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel),
A->getType(), BaseInput);
- }
if (CCCPrintBindings && !CCGenDiagnostics) {
- llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"'
- << " - \"" << T.getName() << "\", inputs: [";
+ llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"'
+ << " - \"" << T->getName() << "\", inputs: [";
for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) {
llvm::errs() << InputInfos[i].getAsString();
if (i + 1 != e)
@@ -1403,8 +1417,8 @@ void Driver::BuildJobsForAction(Compilation &C,
}
llvm::errs() << "], output: " << Result.getAsString() << "\n";
} else {
- T.ConstructJob(C, *JA, Result, InputInfos,
- C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
+ T->ConstructJob(C, *JA, Result, InputInfos,
+ C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
}
}
@@ -1417,11 +1431,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
if (AtTopLevel && !isa<DsymutilJobAction>(JA) &&
!isa<VerifyJobAction>(JA)) {
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- return C.addResultFile(FinalOutput->getValue());
+ return C.addResultFile(FinalOutput->getValue(), &JA);
}
// Default to writing to stdout?
- if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics)
+ if (AtTopLevel && !CCGenDiagnostics &&
+ (isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile))
return "-";
// Output to a temporary file?
@@ -1487,9 +1502,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
BasePath = NamedOutput;
else
llvm::sys::path::append(BasePath, NamedOutput);
- return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()));
+ return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA);
} else {
- return C.addResultFile(NamedOutput);
+ return C.addResultFile(NamedOutput, &JA);
}
}
@@ -1638,6 +1653,21 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
}
}
+ // 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)) {
+ 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::mipsel)
+ Target.setArch(llvm::Triple::mips);
+ else if (Target.getArch() == llvm::Triple::mips64el)
+ Target.setArch(llvm::Triple::mips64);
+ }
+ }
+
// Skip further flag support on OSes which don't support '-m32' or '-m64'.
if (Target.getArchName() == "tce" ||
Target.getOS() == llvm::Triple::AuroraUX ||
@@ -1681,7 +1711,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
Target.getArch() == llvm::Triple::x86_64 ||
Target.getArch() == llvm::Triple::arm ||
Target.getArch() == llvm::Triple::thumb)
- TC = new toolchains::DarwinClang(*this, Target);
+ TC = new toolchains::DarwinClang(*this, Target, Args);
else
TC = new toolchains::Darwin_Generic_GCC(*this, Target, Args);
break;
@@ -1705,7 +1735,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
break;
case llvm::Triple::Linux:
if (Target.getArch() == llvm::Triple::hexagon)
- TC = new toolchains::Hexagon_TC(*this, Target);
+ TC = new toolchains::Hexagon_TC(*this, Target, Args);
else
TC = new toolchains::Linux(*this, Target, Args);
break;
@@ -1713,17 +1743,21 @@ 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);
+ TC = new toolchains::Windows(*this, Target, Args);
break;
case llvm::Triple::MinGW32:
// FIXME: We need a MinGW toolchain. Fallthrough for now.
default:
// TCE is an OSless target
if (Target.getArchName() == "tce") {
- TC = new toolchains::TCEToolChain(*this, Target);
+ TC = new toolchains::TCEToolChain(*this, Target, Args);
+ break;
+ }
+ // If Hexagon is configured as an OSless target
+ if (Target.getArch() == llvm::Triple::hexagon) {
+ TC = new toolchains::Hexagon_TC(*this, Target, Args);
break;
}
-
TC = new toolchains::Generic_GCC(*this, Target, Args);
break;
}
@@ -1731,8 +1765,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
return *TC;
}
-bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
- const llvm::Triple &Triple) const {
+bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
// Check if user requested no clang, or clang doesn't understand this type (we
// only handle single inputs for now).
if (JA.size() != 1 ||
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
index 2a2f4b995d2a..a243d322ee21 100644
--- a/lib/Driver/InputInfo.h
+++ b/lib/Driver/InputInfo.h
@@ -10,8 +10,8 @@
#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
#define CLANG_LIB_DRIVER_INPUTINFO_H_
+#include "clang/Driver/Arg.h"
#include "clang/Driver/Types.h"
-
#include <cassert>
#include <string>
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 825c86a82616..8c467050d563 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -8,9 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Job.h"
-
#include "llvm/ADT/STLExtras.h"
-
#include <cassert>
using namespace clang::driver;
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index 6e7b6951fb83..20214a68d5cd 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -12,8 +12,8 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <map>
using namespace clang::driver;
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index 9a34df59036a..dbc61ea3a4f7 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -8,14 +8,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Option.h"
-
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/Twine.h"
-#include <cassert>
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <cassert>
using namespace clang::driver;
Option::Option(const OptTable::Info *info, const OptTable *owner)
diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp
index b885eeef9832..155e53b64fc1 100644
--- a/lib/Driver/Phases.cpp
+++ b/lib/Driver/Phases.cpp
@@ -9,7 +9,6 @@
#include "clang/Driver/Phases.h"
#include "llvm/Support/ErrorHandling.h"
-
#include <cassert>
using namespace clang::driver;
diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h
index ecb396ea06cf..e61f15ad624f 100644
--- a/lib/Driver/SanitizerArgs.h
+++ b/lib/Driver/SanitizerArgs.h
@@ -9,7 +9,13 @@
#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
#define CLANG_LIB_DRIVER_SANITIZERARGS_H_
+#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Path.h"
namespace clang {
namespace driver {
@@ -30,59 +36,151 @@ class SanitizerArgs {
#include "clang/Basic/Sanitizers.def"
NeedsAsanRt = Address,
NeedsTsanRt = Thread,
- NeedsUbsanRt = Undefined
+ NeedsMsanRt = Memory,
+ NeedsUbsanRt = Undefined | Integer,
+ NotAllowedWithTrap = Vptr
};
unsigned Kind;
+ std::string BlacklistFile;
+ bool MsanTrackOrigins;
+ bool AsanZeroBaseShadow;
+ bool UbsanTrapOnError;
public:
- SanitizerArgs() : Kind(0) {}
+ SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
+ AsanZeroBaseShadow(false), UbsanTrapOnError(false) {}
/// Parses the sanitizer arguments from an argument list.
SanitizerArgs(const Driver &D, const ArgList &Args);
bool needsAsanRt() const { return Kind & NeedsAsanRt; }
bool needsTsanRt() const { return Kind & NeedsTsanRt; }
- bool needsUbsanRt() const { return Kind & NeedsUbsanRt; }
+ bool needsMsanRt() const { return Kind & NeedsMsanRt; }
+ bool needsUbsanRt() const {
+ if (UbsanTrapOnError)
+ return false;
+ return Kind & NeedsUbsanRt;
+ }
bool sanitizesVptr() const { return Kind & Vptr; }
-
+ bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
+
void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
if (!Kind)
return;
- llvm::SmallString<256> SanitizeOpt("-fsanitize=");
+ SmallString<256> SanitizeOpt("-fsanitize=");
#define SANITIZER(NAME, ID) \
if (Kind & ID) \
SanitizeOpt += NAME ",";
#include "clang/Basic/Sanitizers.def"
SanitizeOpt.pop_back();
CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
+ if (!BlacklistFile.empty()) {
+ SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
+ BlacklistOpt += BlacklistFile;
+ CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
+ }
+
+ if (MsanTrackOrigins)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
+
+ if (AsanZeroBaseShadow)
+ CmdArgs.push_back(Args.MakeArgString(
+ "-fsanitize-address-zero-base-shadow"));
}
private:
/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
- /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value
- /// is not known.
+ /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
+ /// if \p Value is not known.
static unsigned parse(const char *Value) {
- return llvm::StringSwitch<SanitizeKind>(Value)
+ unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
#define SANITIZER(NAME, ID) .Case(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
#include "clang/Basic/Sanitizers.def"
.Default(SanitizeKind());
+ // Assume -fsanitize=address implies -fsanitize=init-order.
+ // FIXME: This should be either specified in Sanitizers.def, or go away when
+ // we get rid of "-fsanitize=init-order" flag at all.
+ if (ParsedKind & Address)
+ ParsedKind |= InitOrder;
+ return ParsedKind;
}
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
/// invalid components.
- static unsigned parse(const Driver &D, const Arg *A) {
+ static unsigned parse(const Driver &D, const Arg *A, bool DiagnoseErrors) {
unsigned Kind = 0;
for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
if (unsigned K = parse(A->getValue(I)))
Kind |= K;
- else
+ else if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << A->getValue(I);
}
return Kind;
}
+ /// Parse a single flag of the form -f[no]sanitize=, or
+ /// -f*-sanitizer. Sets the masks defining required change of Kind value.
+ /// Returns true if the flag was parsed successfully.
+ static bool parse(const Driver &D, const ArgList &Args, const Arg *A,
+ unsigned &Add, 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 = Bounds;
+ DeprecatedReplacement = "-fsanitize=bounds";
+ } else 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);
+ } else {
+ // 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;
+ }
+
+ /// Produce an argument string from ArgList \p Args, which shows how it
+ /// provides a sanitizer kind in \p Mask. For example, the argument list
+ /// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt
+ /// would produce "-fsanitize=vptr".
+ static std::string lastArgumentForKind(const Driver &D, const ArgList &Args,
+ unsigned Kind) {
+ for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
+ I != E; ++I) {
+ unsigned Add, Remove;
+ if (parse(D, Args, *I, Add, Remove, false) &&
+ (Add & Kind))
+ return describeSanitizeArg(Args, *I, Kind);
+ Kind &= ~Remove;
+ }
+ llvm_unreachable("arg list didn't provide expected value");
+ }
+
/// Produce an argument string from argument \p A, which shows how it provides
/// a value in \p Mask. For instance, the argument
/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
@@ -98,6 +196,18 @@ class SanitizerArgs {
llvm_unreachable("arg didn't provide expected value");
}
+
+ static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
+ std::string &BLPath) {
+ // For now, specify the default blacklist location for ASan only.
+ if (Kind & NeedsAsanRt) {
+ SmallString<64> Path(D.ResourceDir);
+ llvm::sys::path::append(Path, "asan_blacklist.txt");
+ BLPath = Path.str();
+ return true;
+ }
+ return false;
+ }
};
} // namespace driver
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index de8ed1d1c5e7..19270b2aa33f 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -7,8 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#include "Tools.h"
#include "clang/Driver/ToolChain.h"
-
+#include "clang/Basic/ObjCRuntime.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
@@ -18,12 +19,12 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
-#include "clang/Basic/ObjCRuntime.h"
using namespace clang::driver;
using namespace clang;
-ToolChain::ToolChain(const Driver &D, const llvm::Triple &T)
- : D(D), Triple(T) {
+ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
+ const ArgList &A)
+ : D(D), Triple(T), Args(A) {
}
ToolChain::~ToolChain() {
@@ -33,6 +34,12 @@ const Driver &ToolChain::getDriver() const {
return D;
}
+bool ToolChain::useIntegratedAs() const {
+ return Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIntegratedAssemblerDefault());
+}
+
std::string ToolChain::getDefaultUniversalArchName() const {
// In universal driver terms, the arch name accepted by -arch isn't exactly
// the same as the ones that appear in the triple. Roughly speaking, this is
@@ -52,6 +59,73 @@ bool ToolChain::IsUnwindTablesDefault() const {
return false;
}
+Tool *ToolChain::getClang() const {
+ if (!Clang)
+ Clang.reset(new tools::Clang(*this));
+ return Clang.get();
+}
+
+Tool *ToolChain::buildAssembler() const {
+ return new tools::ClangAs(*this);
+}
+
+Tool *ToolChain::buildLinker() const {
+ llvm_unreachable("Linking is not supported by this toolchain");
+}
+
+Tool *ToolChain::getAssemble() const {
+ if (!Assemble)
+ Assemble.reset(buildAssembler());
+ return Assemble.get();
+}
+
+Tool *ToolChain::getClangAs() const {
+ if (!Assemble)
+ Assemble.reset(new tools::ClangAs(*this));
+ return Assemble.get();
+}
+
+Tool *ToolChain::getLink() const {
+ if (!Link)
+ Link.reset(buildLinker());
+ return Link.get();
+}
+
+Tool *ToolChain::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::AssembleJobClass:
+ return getAssemble();
+
+ case Action::LinkJobClass:
+ return getLink();
+
+ case Action::InputClass:
+ case Action::BindArchClass:
+ case Action::LipoJobClass:
+ case Action::DsymutilJobClass:
+ case Action::VerifyJobClass:
+ llvm_unreachable("Invalid tool kind.");
+
+ case Action::CompileJobClass:
+ case Action::PrecompileJobClass:
+ case Action::PreprocessJobClass:
+ case Action::AnalyzeJobClass:
+ case Action::MigrateJobClass:
+ return getClang();
+ }
+
+ llvm_unreachable("Invalid tool kind.");
+}
+
+Tool *ToolChain::SelectTool(const JobAction &JA) const {
+ if (getDriver().ShouldUseClangCompiler(JA))
+ return getClang();
+ Action::ActionClass AC = JA.getKind();
+ if (AC == Action::AssembleJobClass && useIntegratedAs())
+ return getClangAs();
+ return getTool(AC);
+}
+
std::string ToolChain::GetFilePath(const char *Name) const {
return D.GetFilePath(Name, *this);
@@ -110,15 +184,17 @@ static const char *getARMTargetCPU(const ArgList &Args,
.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")
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- .Cases("armv6m", "armv6-m", "cortex-m0")
// If all else failed, return the most base CPU LLVM supports.
.Default("arm7tdmi");
}
@@ -141,10 +217,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7m")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a15", "v7")
+ .Case("cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
.Default("");
@@ -166,7 +244,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
// FIXME: Thumb should just be another -target-feaure, not in the triple.
StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
- bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin());
+ bool ThumbDefault = Suffix.startswith("v6m") ||
+ (Suffix.startswith("v7") && getTriple().isOSDarwin());
std::string ArchName = "arm";
// Assembly files should start in ARM mode.
@@ -197,7 +276,8 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Each toolchain should provide the appropriate include flags.
}
-void ToolChain::addClangTargetOptions(ArgStringList &CC1Args) const {
+void ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
}
ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 7d70cd50de39..bcfe51ef7bbb 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
-
+#include "SanitizerArgs.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
@@ -17,34 +19,31 @@
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
-#include "clang/Basic/ObjCRuntime.h"
-#include "clang/Basic/Version.h"
-
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "SanitizerArgs.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 <cstdlib> // ::getenv
-#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
-
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
/// Darwin - Darwin tool chain for i386 and x86_64.
-Darwin::Darwin(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple), TargetInitialized(false)
+Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : ToolChain(D, Triple, Args), TargetInitialized(false)
{
// Compute the initial Darwin version from the triple
unsigned Major, Minor, Micro;
@@ -100,15 +99,17 @@ bool Darwin::hasBlocksRuntime() const {
static const char *GetArmArchForMArch(StringRef Value) {
return llvm::StringSwitch<const char*>(Value)
.Case("armv6k", "armv6")
+ .Case("armv6m", "armv6m")
.Case("armv5tej", "armv5")
.Case("xscale", "xscale")
.Case("armv4t", "armv4t")
.Case("armv7", "armv7")
.Cases("armv7a", "armv7-a", "armv7")
.Cases("armv7r", "armv7-r", "armv7")
- .Cases("armv7m", "armv7-m", "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);
}
@@ -119,11 +120,12 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Cases("arm10e", "arm10tdmi", "armv5")
.Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5")
.Case("xscale", "xscale")
- .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s",
- "arm1176jzf-s", "cortex-m0", "armv6")
- .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15",
- "armv7")
+ .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6")
+ .Case("cortex-m0", "armv6m")
+ .Cases("cortex-a8", "cortex-r4", "cortex-a9", "cortex-a15", "armv7")
.Case("cortex-a9-mp", "armv7f")
+ .Case("cortex-m3", "armv7m")
+ .Case("cortex-m4", "armv7em")
.Case("swift", "armv7s")
.Default(0);
}
@@ -149,10 +151,6 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
}
Darwin::~Darwin() {
- // Free tool implementations.
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
}
std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
@@ -174,57 +172,36 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
void Generic_ELF::anchor() {}
-Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key = JA.getKind();
-
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) {
- // FIXME: This seems like a hacky way to choose clang frontend.
- Key = Action::AnalyzeJobClass;
- }
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- T = new tools::darwin::Preprocess(*this); break;
- case Action::AnalyzeJobClass:
- case Action::MigrateJobClass:
- T = new tools::Clang(*this); break;
- case Action::PrecompileJobClass:
- case Action::CompileJobClass:
- T = new tools::darwin::Compile(*this); break;
- case Action::AssembleJobClass: {
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::darwin::Assemble(*this);
- break;
- }
- case Action::LinkJobClass:
- T = new tools::darwin::Link(*this); break;
- case Action::LipoJobClass:
- T = new tools::darwin::Lipo(*this); break;
- case Action::DsymutilJobClass:
- T = new tools::darwin::Dsymutil(*this); break;
- case Action::VerifyJobClass:
- T = new tools::darwin::VerifyDebug(*this); break;
- }
+Tool *Darwin::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::LipoJobClass:
+ if (!Lipo)
+ Lipo.reset(new tools::darwin::Lipo(*this));
+ return Lipo.get();
+ case Action::DsymutilJobClass:
+ if (!Dsymutil)
+ Dsymutil.reset(new tools::darwin::Dsymutil(*this));
+ return Dsymutil.get();
+ case Action::VerifyJobClass:
+ if (!VerifyDebug)
+ VerifyDebug.reset(new tools::darwin::VerifyDebug(*this));
+ return VerifyDebug.get();
+ default:
+ return ToolChain::getTool(AC);
}
+}
- return *T;
+Tool *Darwin::buildLinker() const {
+ return new tools::darwin::Link(*this);
}
+Tool *Darwin::buildAssembler() const {
+ return new tools::darwin::Assemble(*this);
+}
-DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple)
- : Darwin(D, Triple)
+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)
@@ -261,16 +238,18 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
ArgStringList &CmdArgs,
- const char *DarwinStaticLib) const {
+ const char *DarwinStaticLib,
+ bool AlwaysLink) const {
llvm::sys::Path P(getDriver().ResourceDir);
P.appendComponent("lib");
P.appendComponent("darwin");
P.appendComponent(DarwinStaticLib);
// For now, allow missing resource libraries to support developers who may
- // not have compiler-rt checked out or integrated into their build.
+ // not have compiler-rt checked out or integrated into their build (unless
+ // we explicitly force linking with this library).
bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ if (AlwaysLink || (!llvm::sys::fs::exists(P.str(), Exists) && Exists))
CmdArgs.push_back(Args.MakeArgString(P.str()));
}
@@ -317,21 +296,35 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
SanitizerArgs Sanitize(getDriver(), Args);
+ // Add Ubsan runtime library, if required.
+ if (Sanitize.needsUbsanRt()) {
+ if (isTargetIPhoneOS()) {
+ getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
+ << "-fsanitize=undefined";
+ } else {
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ubsan_osx.a", true);
+
+ // The Ubsan runtime library requires C++.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
+ }
+
// Add ASAN runtime library, if required. Dynamic libraries and bundles
// should not be linked with the runtime library.
if (Sanitize.needsAsanRt()) {
- if (Args.hasArg(options::OPT_dynamiclib) ||
- Args.hasArg(options::OPT_bundle)) return;
- if (isTargetIPhoneOS()) {
+ if (isTargetIPhoneOS() && !isTargetIOSSimulator()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=address";
} else {
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a");
-
- // The ASAN runtime library requires C++ and CoreFoundation.
- AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-framework");
- CmdArgs.push_back("CoreFoundation");
+ if (Args.hasArg(options::OPT_dynamiclib) ||
+ Args.hasArg(options::OPT_bundle)) {
+ // Assume the binary will provide the ASan runtime.
+ } else {
+ AddLinkRuntimeLib(Args, CmdArgs,
+ "libclang_rt.asan_osx_dynamic.dylib", true);
+ // The ASAN runtime library requires C++.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
}
}
@@ -381,11 +374,17 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// Support allowing the SDKROOT environment variable used by xcrun and other
// Xcode tools to define the default sysroot, by making it the default for
// isysroot.
- if (!Args.hasArg(options::OPT_isysroot)) {
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ // Warn if the path does not exist.
+ bool Exists;
+ if (llvm::sys::fs::exists(A->getValue(), Exists) || !Exists)
+ getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue();
+ } else {
if (char *env = ::getenv("SDKROOT")) {
- // We only use this value as the default if it is an absolute path and
- // exists.
- if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env)) {
+ // We only use this value as the default if it is an absolute path,
+ // exists, and it is not the root path.
+ 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));
}
@@ -796,12 +795,18 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddJoinedArg(0, MArch, "xscale");
else if (Name == "armv6")
DAL->AddJoinedArg(0, MArch, "armv6k");
+ else if (Name == "armv6m")
+ DAL->AddJoinedArg(0, MArch, "armv6m");
else if (Name == "armv7")
DAL->AddJoinedArg(0, MArch, "armv7a");
+ else if (Name == "armv7em")
+ DAL->AddJoinedArg(0, MArch, "armv7em");
else if (Name == "armv7f")
DAL->AddJoinedArg(0, MArch, "armv7f");
else if (Name == "armv7k")
DAL->AddJoinedArg(0, MArch, "armv7k");
+ else if (Name == "armv7m")
+ DAL->AddJoinedArg(0, MArch, "armv7m");
else if (Name == "armv7s")
DAL->AddJoinedArg(0, MArch, "armv7s");
@@ -931,7 +936,7 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
// And retains any patch number it finds.
StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
if (!PatchText.empty()) {
- if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) {
+ if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
// Try to parse the number and any suffix.
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
GoodVersion.Patch < 0)
@@ -945,20 +950,33 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
- if (Major < RHS.Major) return true; if (Major > RHS.Major) return false;
- if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false;
-
- // Note that we rank versions with *no* patch specified is better than ones
- // hard-coding a patch version. Thus if the RHS has no patch, it always
- // wins, and the LHS only wins if it has no patch and the RHS does have
- // a patch.
- if (RHS.Patch == -1) return true; if (Patch == -1) return false;
- if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false;
- if (PatchSuffix == RHS.PatchSuffix) return false;
-
- // Finally, between completely tied version numbers, the version with the
- // suffix loses as we prefer full releases.
- if (RHS.PatchSuffix.empty()) return true;
+ if (Major != RHS.Major)
+ return Major < RHS.Major;
+ if (Minor != RHS.Minor)
+ return Minor < RHS.Minor;
+ if (Patch != RHS.Patch) {
+ // Note that versions without a specified patch sort higher than those with
+ // a patch.
+ if (RHS.Patch == -1)
+ return true;
+ if (Patch == -1)
+ return false;
+
+ // Otherwise just sort on the patch itself.
+ return Patch < RHS.Patch;
+ }
+ if (PatchSuffix != RHS.PatchSuffix) {
+ // Sort empty suffixes higher.
+ if (RHS.PatchSuffix.empty())
+ return true;
+ if (PatchSuffix.empty())
+ return false;
+
+ // Provide a lexicographic sort to make this a total ordering.
+ return PatchSuffix < RHS.PatchSuffix;
+ }
+
+ // The versions are equal.
return false;
}
@@ -1051,6 +1069,12 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
// 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 AArch64Triples[] = {
+ "aarch64-none-linux-gnu",
+ "aarch64-linux-gnu"
+ };
+
static const char *const ARMLibDirs[] = { "/lib" };
static const char *const ARMTriples[] = {
"arm-linux-gnueabi",
@@ -1078,6 +1102,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
"i686-pc-linux-gnu",
"i486-linux-gnu",
"i386-linux-gnu",
+ "i386-redhat-linux6E",
"i686-redhat-linux",
"i586-redhat-linux",
"i386-redhat-linux",
@@ -1103,6 +1128,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
static const char *const PPCTriples[] = {
"powerpc-linux-gnu",
"powerpc-unknown-linux-gnu",
+ "powerpc-linux-gnuspe",
"powerpc-suse-linux",
"powerpc-montavista-linuxspe"
};
@@ -1115,6 +1141,16 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
};
switch (TargetTriple.getArch()) {
+ case llvm::Triple::aarch64:
+ LibDirs.append(AArch64LibDirs, AArch64LibDirs
+ + llvm::array_lengthof(AArch64LibDirs));
+ TripleAliases.append(
+ AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ MultiarchLibDirs.append(
+ AArch64LibDirs, AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
+ MultiarchTripleAliases.append(
+ AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
@@ -1316,60 +1352,40 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
- : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) {
+ : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
}
Generic_GCC::~Generic_GCC() {
- // Free tool implementations.
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
-}
-
-Tool &Generic_GCC::SelectTool(const Compilation &C,
- const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- T = new tools::gcc::Preprocess(*this); break;
- case Action::PrecompileJobClass:
- T = new tools::gcc::Precompile(*this); break;
- case Action::AnalyzeJobClass:
- case Action::MigrateJobClass:
- T = new tools::Clang(*this); break;
- case Action::CompileJobClass:
- T = new tools::gcc::Compile(*this); break;
- case Action::AssembleJobClass:
- T = new tools::gcc::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::gcc::Link(*this); break;
-
- // This is a bit ungeneric, but the only platform using a driver
- // driver is Darwin.
- case Action::LipoJobClass:
- T = new tools::darwin::Lipo(*this); break;
- case Action::DsymutilJobClass:
- T = new tools::darwin::Dsymutil(*this); break;
- case Action::VerifyJobClass:
- T = new tools::darwin::VerifyDebug(*this); break;
- }
+}
+
+Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::PreprocessJobClass:
+ 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));
+ return Compile.get();
+ default:
+ return ToolChain::getTool(AC);
}
+}
+
+Tool *Generic_GCC::buildAssembler() const {
+ return new tools::gcc::Assemble(*this);
+}
- return *T;
+Tool *Generic_GCC::buildLinker() const {
+ return new tools::gcc::Link(*this);
}
bool Generic_GCC::IsUnwindTablesDefault() const {
@@ -1386,71 +1402,216 @@ bool Generic_GCC::isPICDefaultForced() const {
/// Hexagon Toolchain
-Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple) {
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir.c_str())
- getProgramPaths().push_back(getDriver().Dir);
+std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir) {
+
+ // Locate the rest of the toolchain ...
+ if (strlen(GCC_INSTALL_PREFIX))
+ return std::string(GCC_INSTALL_PREFIX);
+
+ std::string InstallRelDir = InstalledDir + "/../../gnu";
+ if (llvm::sys::fs::exists(InstallRelDir))
+ return InstallRelDir;
+
+ std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu";
+ if (llvm::sys::fs::exists(PrefixRelDir))
+ return PrefixRelDir;
+
+ return InstallRelDir;
+}
+
+static void GetHexagonLibraryPaths(
+ const ArgList &Args,
+ const std::string Ver,
+ const std::string MarchString,
+ const std::string &InstalledDir,
+ ToolChain::path_list *LibPaths)
+{
+ bool buildingLib = Args.hasArg(options::OPT_shared);
+
+ //----------------------------------------------------------------------------
+ // -L Args
+ //----------------------------------------------------------------------------
+ for (arg_iterator
+ it = Args.filtered_begin(options::OPT_L),
+ ie = Args.filtered_end();
+ it != ie;
+ ++it) {
+ for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
+ LibPaths->push_back((*it)->getValue(i));
+ }
+
+ //----------------------------------------------------------------------------
+ // Other standard paths
+ //----------------------------------------------------------------------------
+ const std::string MarchSuffix = "/" + MarchString;
+ const std::string G0Suffix = "/G0";
+ const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
+ const std::string RootDir = Hexagon_TC::GetGnuDir(InstalledDir) + "/";
+
+ // lib/gcc/hexagon/...
+ std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/";
+ if (buildingLib) {
+ LibPaths->push_back(LibGCCHexagonDir + Ver + MarchG0Suffix);
+ LibPaths->push_back(LibGCCHexagonDir + Ver + G0Suffix);
+ }
+ LibPaths->push_back(LibGCCHexagonDir + Ver + MarchSuffix);
+ LibPaths->push_back(LibGCCHexagonDir + Ver);
+
+ // lib/gcc/...
+ LibPaths->push_back(RootDir + "lib/gcc");
+
+ // hexagon/lib/...
+ std::string HexagonLibDir = RootDir + "hexagon/lib";
+ if (buildingLib) {
+ LibPaths->push_back(HexagonLibDir + MarchG0Suffix);
+ LibPaths->push_back(HexagonLibDir + G0Suffix);
+ }
+ LibPaths->push_back(HexagonLibDir + MarchSuffix);
+ LibPaths->push_back(HexagonLibDir);
+}
+
+Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Linux(D, Triple, Args) {
+ const std::string InstalledDir(getDriver().getInstalledDir());
+ const std::string GnuDir = Hexagon_TC::GetGnuDir(InstalledDir);
+
+ // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
+ // program paths
+ const std::string BinDir(GnuDir + "/bin");
+ if (llvm::sys::fs::exists(BinDir))
+ getProgramPaths().push_back(BinDir);
+
+ // Determine version of GCC libraries and headers to use.
+ const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon");
+ llvm::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)) {
+ GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->path()));
+ if (MaxVersion < cv)
+ MaxVersion = cv;
+ }
+ GCCLibAndIncVersion = MaxVersion;
+
+ ToolChain::path_list *LibPaths= &getFilePaths();
+
+ // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
+ // 'elf' OS type, so the Linux paths are not appropriate. When we actually
+ // support 'linux' we'll need to fix this up
+ LibPaths->clear();
+
+ GetHexagonLibraryPaths(
+ Args,
+ GetGCCLibAndIncVersion(),
+ GetTargetCPU(Args),
+ InstalledDir,
+ LibPaths);
}
Hexagon_TC::~Hexagon_TC() {
- // Free tool implementations.
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
-}
-
-Tool &Hexagon_TC::SelectTool(const Compilation &C,
- const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- // if (JA.getKind () == Action::CompileJobClass)
- // Key = JA.getKind ();
- // else
-
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
- // if ((JA.getKind () == Action::CompileJobClass)
- // && (JA.getType () != types::TY_LTO_BC)) {
- // Key = JA.getKind ();
- // }
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- assert(0 && "Invalid tool kind.");
- case Action::AnalyzeJobClass:
- T = new tools::Clang(*this); break;
- case Action::AssembleJobClass:
- T = new tools::hexagon::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::hexagon::Link(*this); break;
- default:
- assert(false && "Unsupported action for Hexagon target.");
- }
+}
+
+Tool *Hexagon_TC::buildAssembler() const {
+ return new tools::hexagon::Assemble(*this);
+}
+
+Tool *Hexagon_TC::buildLinker() const {
+ return new tools::hexagon::Link(*this);
+}
+
+void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ llvm::sys::Path InstallDir(D.InstalledDir);
+ std::string Ver(GetGCCLibAndIncVersion());
+ std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir);
+ std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver);
+ addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include");
+ addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed");
+ addExternCSystemInclude(DriverArgs, CC1Args, GnuDir + "/hexagon/include");
+}
+
+void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ const Driver &D = getDriver();
+ std::string Ver(GetGCCLibAndIncVersion());
+ llvm::sys::Path IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir));
+
+ IncludeDir.appendComponent("hexagon/include/c++/");
+ IncludeDir.appendComponent(Ver);
+ addSystemInclude(DriverArgs, CC1Args, IncludeDir.str());
+}
+
+ToolChain::CXXStdlibType
+Hexagon_TC::GetCXXStdlibType(const ArgList &Args) const {
+ Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
+ if (!A)
+ return ToolChain::CST_Libstdcxx;
+
+ StringRef Value = A->getValue();
+ if (Value != "libstdc++") {
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
}
- return *T;
+ return ToolChain::CST_Libstdcxx;
}
-bool Hexagon_TC::isPICDefault() const {
- return false;
+static Arg *GetLastHexagonArchArg(const ArgList &Args)
+{
+ Arg *A = NULL;
+
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ it != ie; ++it) {
+ if ((*it)->getOption().matches(options::OPT_march_EQ) ||
+ (*it)->getOption().matches(options::OPT_mcpu_EQ)) {
+ A = *it;
+ A->claim();
+ } else if ((*it)->getOption().matches(options::OPT_m_Joined)) {
+ StringRef Value = (*it)->getValue(0);
+ if (Value.startswith("v")) {
+ A = *it;
+ A->claim();
+ }
+ }
+ }
+ return A;
}
-bool Hexagon_TC::isPICDefaultForced() const {
- return false;
+StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args)
+{
+ // Select the default CPU (v4) if none was given or detection failed.
+ Arg *A = GetLastHexagonArchArg (Args);
+ if (A) {
+ StringRef WhichHexagon = A->getValue();
+ if (WhichHexagon.startswith("hexagon"))
+ return WhichHexagon.substr(sizeof("hexagon") - 1);
+ if (WhichHexagon != "")
+ return WhichHexagon;
+ }
+
+ return "v4";
}
+// End Hexagon
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
/// Currently does not support anything else but compilation.
-TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple) {
+TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
// Path mangling to find libexec
std::string Path(getDriver().Dir);
@@ -1459,9 +1620,6 @@ TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple)
}
TCEToolChain::~TCEToolChain() {
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
}
bool TCEToolChain::IsMathErrnoDefault() const {
@@ -1476,26 +1634,6 @@ bool TCEToolChain::isPICDefaultForced() const {
return false;
}
-Tool &TCEToolChain::SelectTool(const Compilation &C,
- const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- Key = Action::AnalyzeJobClass;
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::PreprocessJobClass:
- T = new tools::gcc::Preprocess(*this); break;
- case Action::AnalyzeJobClass:
- T = new tools::Clang(*this); break;
- default:
- llvm_unreachable("Unsupported action for TCE target.");
- }
- }
- return *T;
-}
-
/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
@@ -1504,36 +1642,12 @@ OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg
getFilePaths().push_back("/usr/lib");
}
-Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass: {
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::openbsd::Assemble(*this);
- break;
- }
- case Action::LinkJobClass:
- T = new tools::openbsd::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *OpenBSD::buildAssembler() const {
+ return new tools::openbsd::Assemble(*this);
+}
- return *T;
+Tool *OpenBSD::buildLinker() const {
+ return new tools::openbsd::Link(*this);
}
/// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly.
@@ -1544,36 +1658,12 @@ Bitrig::Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
getFilePaths().push_back("/usr/lib");
}
-Tool &Bitrig::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass: {
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::bitrig::Assemble(*this);
- break;
- }
- case Action::LinkJobClass:
- T = new tools::bitrig::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Bitrig::buildAssembler() const {
+ return new tools::bitrig::Assemble(*this);
+}
- return *T;
+Tool *Bitrig::buildLinker() const {
+ return new tools::bitrig::Link(*this);
}
void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
@@ -1636,35 +1726,25 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}
-Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::freebsd::Assemble(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::freebsd::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *FreeBSD::buildAssembler() const {
+ return new tools::freebsd::Assemble(*this);
+}
+
+Tool *FreeBSD::buildLinker() const {
+ return new tools::freebsd::Link(*this);
+}
- return *T;
+bool FreeBSD::UseSjLjExceptions() const {
+ // FreeBSD uses SjLj exceptions on ARM oabi.
+ switch (getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::EABI:
+ return false;
+
+ default:
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
+ }
}
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
@@ -1685,36 +1765,12 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
}
}
-Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::netbsd::Assemble(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::netbsd::Link(*this);
- break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *NetBSD::buildAssembler() const {
+ return new tools::netbsd::Assemble(*this);
+}
- return *T;
+Tool *NetBSD::buildLinker() const {
+ return new tools::netbsd::Link(*this);
}
/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
@@ -1725,27 +1781,12 @@ Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
getFilePaths().push_back("/usr/lib");
}
-Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::minix::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::minix::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Minix::buildAssembler() const {
+ return new tools::minix::Assemble(*this);
+}
- return *T;
+Tool *Minix::buildLinker() const {
+ return new tools::minix::Link(*this);
}
/// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly.
@@ -1766,27 +1807,12 @@ AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple,
}
-Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::auroraux::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::auroraux::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *AuroraUX::buildAssembler() const {
+ return new tools::auroraux::Assemble(*this);
+}
- return *T;
+Tool *AuroraUX::buildLinker() const {
+ return new tools::auroraux::Link(*this);
}
/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
@@ -1803,36 +1829,22 @@ Solaris::Solaris(const Driver &D, const llvm::Triple& Triple,
getFilePaths().push_back("/usr/lib");
}
-Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::solaris::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::solaris::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Solaris::buildAssembler() const {
+ return new tools::solaris::Assemble(*this);
+}
- return *T;
+Tool *Solaris::buildLinker() const {
+ return new tools::solaris::Link(*this);
}
-/// Linux toolchain (very bare-bones at the moment).
+/// Distribution (very bare-bones at the moment).
-enum LinuxDistro {
+enum Distro {
ArchLinux,
DebianLenny,
DebianSqueeze,
DebianWheezy,
+ DebianJessie,
Exherbo,
RHEL4,
RHEL5,
@@ -1860,33 +1872,33 @@ enum LinuxDistro {
UnknownDistro
};
-static bool IsRedhat(enum LinuxDistro Distro) {
+static bool IsRedhat(enum Distro Distro) {
return (Distro >= Fedora13 && Distro <= FedoraRawhide) ||
(Distro >= RHEL4 && Distro <= RHEL6);
}
-static bool IsOpenSuse(enum LinuxDistro Distro) {
+static bool IsOpenSuse(enum Distro Distro) {
return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2;
}
-static bool IsDebian(enum LinuxDistro Distro) {
- return Distro >= DebianLenny && Distro <= DebianWheezy;
+static bool IsDebian(enum Distro Distro) {
+ return Distro >= DebianLenny && Distro <= DebianJessie;
}
-static bool IsUbuntu(enum LinuxDistro Distro) {
+static bool IsUbuntu(enum Distro Distro) {
return Distro >= UbuntuHardy && Distro <= UbuntuRaring;
}
-static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
+static Distro DetectDistro(llvm::Triple::ArchType Arch) {
OwningPtr<llvm::MemoryBuffer> File;
if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) {
StringRef Data = File.get()->getBuffer();
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
- LinuxDistro Version = UnknownDistro;
+ Distro Version = UnknownDistro;
for (unsigned i = 0, s = Lines.size(); i != s; ++i)
if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME="))
- Version = llvm::StringSwitch<LinuxDistro>(Lines[i].substr(17))
+ Version = llvm::StringSwitch<Distro>(Lines[i].substr(17))
.Case("hardy", UbuntuHardy)
.Case("intrepid", UbuntuIntrepid)
.Case("jaunty", UbuntuJaunty)
@@ -1919,11 +1931,11 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
Data.find("release 6") != StringRef::npos)
return RHEL6;
else if ((Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS")) &&
+ Data.startswith("CentOS")) &&
Data.find("release 5") != StringRef::npos)
return RHEL5;
else if ((Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS")) &&
+ Data.startswith("CentOS")) &&
Data.find("release 4") != StringRef::npos)
return RHEL4;
return UnknownDistro;
@@ -1937,11 +1949,13 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return DebianSqueeze;
else if (Data.startswith("wheezy/sid") || Data[0] == '7')
return DebianWheezy;
+ else if (Data.startswith("jessie/sid") || Data[0] == '8')
+ return DebianJessie;
return UnknownDistro;
}
if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File))
- return llvm::StringSwitch<LinuxDistro>(File.get()->getBuffer())
+ return llvm::StringSwitch<Distro>(File.get()->getBuffer())
.StartsWith("openSUSE 11.3", OpenSuse11_3)
.StartsWith("openSUSE 11.4", OpenSuse11_4)
.StartsWith("openSUSE 12.1", OpenSuse12_1)
@@ -1994,6 +2008,9 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu"))
return "x86_64-linux-gnu";
return TargetTriple.str();
+ case llvm::Triple::aarch64:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu"))
+ return "aarch64-linux-gnu";
case llvm::Triple::mips:
if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu"))
return "mips-linux-gnu";
@@ -2003,6 +2020,8 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
return "mipsel-linux-gnu";
return TargetTriple.str();
case llvm::Triple::ppc:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
+ return "powerpc-linux-gnuspe";
if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu"))
return "powerpc-linux-gnu";
return TargetTriple.str();
@@ -2070,7 +2089,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
Linker = GetProgramPath("ld");
- LinuxDistro Distro = DetectLinuxDistro(Arch);
+ Distro Distro = DetectDistro(Arch);
if (IsOpenSuse(Distro) || IsUbuntu(Distro)) {
ExtraOpts.push_back("-z");
@@ -2101,7 +2120,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
ExtraOpts.push_back("--no-add-needed");
if (Distro == DebianSqueeze || Distro == DebianWheezy ||
- IsOpenSuse(Distro) ||
+ Distro == DebianJessie || IsOpenSuse(Distro) ||
(IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
(IsUbuntu(Distro) && Distro >= UbuntuKarmic))
ExtraOpts.push_back("--build-id");
@@ -2184,40 +2203,24 @@ bool Linux::HasNativeLLVMSupport() const {
return true;
}
-Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::linuxtools::Assemble(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::linuxtools::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Linux::buildLinker() const {
+ return new tools::gnutools::Link(*this);
+}
- return *T;
+Tool *Linux::buildAssembler() const {
+ return new tools::gnutools::Assemble(*this);
}
-void Linux::addClangTargetOptions(ArgStringList &CC1Args) const {
+void Linux::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
- if (V >= Generic_GCC::GCCVersion::Parse("4.7.0"))
+ bool UseInitArrayDefault
+ = V >= Generic_GCC::GCCVersion::Parse("4.7.0") ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getEnvironment() == llvm::Triple::Android;
+ if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array,
+ UseInitArrayDefault))
CC1Args.push_back("-fuse-init-array");
}
@@ -2276,6 +2279,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
"/usr/include/i686-linux-gnu",
"/usr/include/i486-linux-gnu"
};
+ const StringRef AArch64MultiarchIncludeDirs[] = {
+ "/usr/include/aarch64-linux-gnu"
+ };
const StringRef ARMMultiarchIncludeDirs[] = {
"/usr/include/arm-linux-gnueabi"
};
@@ -2299,6 +2305,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::x86) {
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::aarch64) {
+ MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::arm) {
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs;
@@ -2333,7 +2341,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
}
-/// \brief Helper to add the thre variant paths for a libstdc++ installation.
+/// \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) {
@@ -2345,6 +2353,22 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return true;
}
+/// \brief Helper to add an extra variant path for an (Ubuntu) multilib
+/// libstdc++ installation.
+/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+ Twine TargetArchDir,
+ Twine MultiLibSuffix,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args) {
+ if (!addLibStdCXXIncludePaths(Base+Suffix, TargetArchDir + MultiLibSuffix,
+ DriverArgs, CC1Args))
+ return false;
+
+ addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix
+ + MultiLibSuffix);
+ return true;
+}
+
void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
@@ -2372,8 +2396,14 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef Version = GCCInstallation.getVersion().Text;
StringRef TripleStr = GCCInstallation.getTriple().str();
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
+ "/c++/" + Version.str(),
+ TripleStr,
+ GCCInstallation.getMultiarchSuffix(),
+ DriverArgs, CC1Args))
+ return;
+
const std::string IncludePathCandidates[] = {
- LibDir.str() + "/../include/c++/" + Version.str(),
// Gentoo is weird and places its headers inside the GCC install, so if the
// first attempt to find the headers fails, try this pattern.
InstallDir.str() + "/include/g++-v4",
@@ -2407,25 +2437,10 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList
getFilePaths().push_back("/usr/lib/gcc41");
}
-Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::dragonfly::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::dragonfly::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *DragonFly::buildAssembler() const {
+ return new tools::dragonfly::Assemble(*this);
+}
- return *T;
+Tool *DragonFly::buildLinker() const {
+ return new tools::dragonfly::Link(*this);
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 4c267e8a8bfc..3421c53eb236 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -10,15 +10,13 @@
#ifndef CLANG_LIB_DRIVER_TOOLCHAINS_H_
#define CLANG_LIB_DRIVER_TOOLCHAINS_H_
+#include "Tools.h"
+#include "clang/Basic/VersionTuple.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/ToolChain.h"
-
-#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Compiler.h"
-#include "Tools.h"
-
namespace clang {
namespace driver {
namespace toolchains {
@@ -119,20 +117,19 @@ protected:
GCCInstallationDetector GCCInstallation;
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
public:
Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
~Generic_GCC();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual bool IsUnwindTablesDefault() const;
virtual bool isPICDefault() const;
virtual bool isPICDefaultForced() const;
protected:
+ virtual Tool *getTool(Action::ActionClass AC) const;
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
/// \name ToolChain Implementation Helper Functions
/// @{
@@ -143,21 +140,11 @@ protected:
bool isTarget32Bit() const { return getTriple().isArch32Bit(); }
/// @}
-};
-
-class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public ToolChain {
-protected:
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
-public:
- Hexagon_TC(const Driver &D, const llvm::Triple& Triple);
- ~Hexagon_TC();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
- virtual bool isPICDefault() const;
- virtual bool isPICDefaultForced() const;
+private:
+ mutable OwningPtr<tools::gcc::Preprocess> Preprocess;
+ mutable OwningPtr<tools::gcc::Precompile> Precompile;
+ mutable OwningPtr<tools::gcc::Compile> Compile;
};
/// Darwin - The base Darwin tool chain.
@@ -166,8 +153,15 @@ 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 llvm::DenseMap<unsigned, Tool*> Tools;
+ 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.
//
@@ -198,7 +192,7 @@ private:
void AddDeploymentTarget(DerivedArgList &Args) const;
public:
- Darwin(const Driver &D, const llvm::Triple& Triple);
+ Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
~Darwin();
std::string ComputeEffectiveClangTriple(const ArgList &Args,
@@ -286,9 +280,6 @@ public:
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual bool IsBlocksDefault() const {
// Always allow blocks on Darwin; users interested in versioning are
// expected to use /usr/include/Blocks.h.
@@ -314,10 +305,6 @@ public:
return false;
}
- virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return true;
- }
-
virtual bool IsEncodeExtendedBlockSignatureDefault() const {
return true;
}
@@ -363,16 +350,17 @@ public:
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
public:
- DarwinClang(const Driver &D, const llvm::Triple& Triple);
+ DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
/// @name Darwin ToolChain Implementation
/// {
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
- void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
- const char *DarwinStaticLib) const;
-
+ void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
+ const char *DarwinStaticLib,
+ bool AlwaysLink = false) const;
+
virtual void AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
@@ -393,7 +381,7 @@ public:
std::string ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const;
- virtual bool isPICDefault() const { return false; };
+ virtual bool isPICDefault() const { return false; }
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
@@ -404,7 +392,8 @@ public:
virtual bool IsIntegratedAssemblerDefault() const {
// Default integrated assembler to on for x86.
- return (getTriple().getArch() == llvm::Triple::x86 ||
+ return (getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64);
}
};
@@ -413,18 +402,20 @@ class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
public:
AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
public:
Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual bool IsIntegratedAssemblerDefault() const { return true; }
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
};
@@ -435,8 +426,9 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
@@ -447,9 +439,6 @@ public:
virtual bool IsObjCNonFragileABIDefault() const { return true; }
virtual bool IsObjCLegacyDispatchDefault() const { return false; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
virtual void AddCXXStdlibLibArgs(const ArgList &Args,
@@ -457,6 +446,10 @@ public:
virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
return 1;
}
+
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
@@ -466,8 +459,10 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+ virtual bool UseSjLjExceptions() const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
@@ -477,16 +472,18 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
public:
Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
@@ -495,8 +492,9 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
@@ -505,55 +503,71 @@ public:
virtual bool HasNativeLLVMSupport() const;
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
- virtual void addClangTargetOptions(ArgStringList &CC1Args) const;
+ virtual void addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
std::string Linker;
std::vector<std::string> ExtraOpts;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
private:
+ static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+ Twine TargetArchDir,
+ Twine MultiLibSuffix,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args);
static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
const ArgList &DriverArgs,
ArgStringList &CC1Args);
};
+class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux {
+protected:
+ GCCVersion GCCLibAndIncVersion;
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
+public:
+ Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args);
+ ~Hexagon_TC();
+
+ virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
+ virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
+ virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
+
+ StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
+
+ static std::string GetGnuDir(const std::string &InstalledDir);
+
+ static StringRef GetTargetCPU(const ArgList &Args);
+};
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
public:
- TCEToolChain(const Driver &D, const llvm::Triple& Triple);
+ TCEToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args);
~TCEToolChain();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
bool IsMathErrnoDefault() const;
bool isPICDefault() const;
bool isPICDefaultForced() const;
-
-private:
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
};
class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
public:
- Windows(const Driver &D, const llvm::Triple& Triple);
-
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
- virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return true;
- }
+ Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
@@ -564,7 +578,9 @@ public:
ArgStringList &CC1Args) const;
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
-
+protected:
+ virtual Tool *buildLinker() const;
+ virtual Tool *buildAssembler() const;
};
} // end namespace toolchains
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index e37959be4efa..77a72ba33a5e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -8,33 +8,31 @@
//===----------------------------------------------------------------------===//
#include "Tools.h"
-
+#include "InputInfo.h"
+#include "SanitizerArgs.h"
+#include "ToolChains.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Compilation.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "clang/Basic/ObjCRuntime.h"
-
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Process.h"
-#include "llvm/Support/ErrorHandling.h"
-
-#include "InputInfo.h"
-#include "SanitizerArgs.h"
-#include "ToolChains.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -230,6 +228,7 @@ static bool forwardToGCC(const Option &O) {
}
void Clang::AddPreprocessingOptions(Compilation &C,
+ const JobAction &JA,
const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -250,15 +249,15 @@ void Clang::AddPreprocessingOptions(Compilation &C,
const char *DepFile;
if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
DepFile = MF->getValue();
- C.addFailureResultFile(DepFile);
+ C.addFailureResultFile(DepFile, &JA);
} else if (Output.getType() == types::TY_Dependencies) {
DepFile = Output.getFilename();
} else if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MM)) {
DepFile = "-";
} else {
- DepFile = darwin::CC1::getDependencyFileName(Args, Inputs);
- C.addFailureResultFile(DepFile);
+ DepFile = getDependencyFileName(Args, Inputs);
+ C.addFailureResultFile(DepFile, &JA);
}
CmdArgs.push_back("-dependency-file");
CmdArgs.push_back(DepFile);
@@ -415,21 +414,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
}
}
-
- // If a module path was provided, pass it along. Otherwise, use a temporary
- // directory.
- if (Arg *A = Args.getLastArg(options::OPT_fmodule_cache_path)) {
- A->claim();
- A->render(Args, CmdArgs);
- } else {
- SmallString<128> DefaultModuleCache;
- llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
- DefaultModuleCache);
- llvm::sys::path::append(DefaultModuleCache, "clang-module-cache");
- CmdArgs.push_back("-fmodule-cache-path");
- CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache));
- }
-
+
// Parse additional include paths from environment variables.
// FIXME: We should probably sink the logic for handling these from the
// frontend into the driver. It will allow deleting 4 otherwise unused flags.
@@ -471,10 +456,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7m")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a15", "v7")
+ .Case("cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
.Default("");
@@ -530,7 +517,9 @@ static std::string getARMTargetCPU(const ArgList &Args,
.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")
@@ -538,7 +527,6 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- .Cases("armv6m", "armv6-m", "cortex-m0")
// If all else failed, return the most base CPU LLVM supports.
.Default("arm7tdmi");
}
@@ -549,6 +537,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
default:
return true;
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
@@ -609,8 +598,9 @@ static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+neonfp");
- if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp" &&
- CPU != "cortex-a15")
+ if (CPU != "cortex-a5" && CPU != "cortex-a7" &&
+ CPU != "cortex-a8" && CPU != "cortex-a9" &&
+ CPU != "cortex-a9-mp" && CPU != "cortex-a15")
D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
} else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
@@ -665,6 +655,11 @@ static StringRef getARMFloatABI(const Driver &D,
break;
}
+ case llvm::Triple::FreeBSD:
+ // FreeBSD defaults to soft float
+ FloatABI = "soft";
+ break;
+
default:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
@@ -878,8 +873,8 @@ static void getMipsCPUAndABI(const ArgList &Args,
if (!ABIName.empty()) {
// Deduce CPU name from ABI name.
CPUName = llvm::StringSwitch<const char *>(ABIName)
- .Cases("o32", "eabi", DefMips32CPU)
- .Cases("n32", "n64", DefMips64CPU)
+ .Cases("32", "o32", "eabi", DefMips32CPU)
+ .Cases("n32", "n64", "64", DefMips64CPU)
.Default("");
}
else if (!CPUName.empty()) {
@@ -893,6 +888,14 @@ static void getMipsCPUAndABI(const ArgList &Args,
// FIXME: Warn on inconsistent cpu and abi usage.
}
+// Convert ABI name to the GNU tools acceptable variant.
+static StringRef getGnuCompatibleMipsABIName(StringRef ABI) {
+ return llvm::StringSwitch<llvm::StringRef>(ABI)
+ .Case("o32", "32")
+ .Case("n64", "64")
+ .Default(ABI);
+}
+
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
// and -mfloat-abi=.
static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) {
@@ -955,7 +958,9 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
StringRef FloatABI = getMipsFloatABI(D, Args);
- if (FloatABI == "soft") {
+ bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL;
+
+ if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
@@ -966,6 +971,11 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
// Now it is the only method.
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+soft-float");
+
+ if (FloatABI == "hard" && IsMips16) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mips16-hard-float");
+ }
}
else if (FloatABI == "single") {
// Restrict the use of hardware floating-point
@@ -990,6 +1000,13 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
options::OPT_mdspr2, options::OPT_mno_dspr2,
"dspr2");
+ if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
+ if (A->getOption().matches(options::OPT_mxgot)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mxgot");
+ }
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_G)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
@@ -1024,6 +1041,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("604", "604")
.Case("604e", "604e")
.Case("620", "620")
+ .Case("630", "pwr3")
.Case("G3", "g3")
.Case("7400", "7400")
.Case("G4", "g4")
@@ -1033,10 +1051,23 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("970", "970")
.Case("G5", "g5")
.Case("a2", "a2")
+ .Case("a2q", "a2q")
.Case("e500mc", "e500mc")
.Case("e5500", "e5500")
+ .Case("power3", "pwr3")
+ .Case("power4", "pwr4")
+ .Case("power5", "pwr5")
+ .Case("power5x", "pwr5x")
.Case("power6", "pwr6")
+ .Case("power6x", "pwr6x")
.Case("power7", "pwr7")
+ .Case("pwr3", "pwr3")
+ .Case("pwr4", "pwr4")
+ .Case("pwr5", "pwr5")
+ .Case("pwr5x", "pwr5x")
+ .Case("pwr6", "pwr6")
+ .Case("pwr6x", "pwr6x")
+ .Case("pwr7", "pwr7")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Default("");
@@ -1064,6 +1095,55 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(TargetCPUName.c_str()));
}
+
+ // Allow override of the Altivec feature.
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_faltivec, options::OPT_fno_altivec,
+ "altivec");
+
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_mfprnd, options::OPT_mno_fprnd,
+ "fprnd");
+
+ // Note that gcc calls this mfcrf and LLVM calls this mfocrf.
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_mmfcrf, options::OPT_mno_mfcrf,
+ "mfocrf");
+
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_mpopcntd, options::OPT_mno_popcntd,
+ "popcntd");
+
+ // It is really only possible to turn qpx off because turning qpx on is tied
+ // to using the a2q CPU.
+ if (Args.hasFlag(options::OPT_mno_qpx, options::OPT_mqpx, false)) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-qpx");
+ }
+}
+
+/// Get the (LLVM) name of the R600 gpu we are targeting.
+static std::string getR600TargetGPU(const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ std::string GPUName = A->getValue();
+ return llvm::StringSwitch<const char *>(GPUName)
+ .Cases("rv610", "rv620", "rv630", "r600")
+ .Cases("rv635", "rs780", "rs880", "r600")
+ .Case("rv740", "rv770")
+ .Case("palm", "cedar")
+ .Cases("sumo", "sumo2", "redwood")
+ .Case("hemlock", "cypress")
+ .Case("aruba", "cayman")
+ .Default(GPUName.c_str());
+ }
+ return "";
+}
+
+void Clang::AddR600TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ std::string TargetGPUName = getR600TargetGPU(Args);
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(TargetGPUName.c_str()));
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
@@ -1109,10 +1189,59 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
}
}
+static const char *getX86TargetCPU(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ if (StringRef(A->getValue()) != "native")
+ return A->getValue();
+
+ // FIXME: Reject attempts to use -march=native unless the target matches
+ // the host.
+ //
+ // FIXME: We should also incorporate the detected target features for use
+ // with -native.
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty() && CPU != "generic")
+ return Args.MakeArgString(CPU);
+ }
+
+ // Select the default CPU if none was given (or detection failed).
+
+ if (Triple.getArch() != llvm::Triple::x86_64 &&
+ Triple.getArch() != llvm::Triple::x86)
+ return 0; // This routine is only handling x86 targets.
+
+ bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
+
+ // FIXME: Need target hooks.
+ if (Triple.isOSDarwin())
+ return Is64Bit ? "core2" : "yonah";
+
+ // Everything else goes to x86-64 in 64-bit mode.
+ if (Is64Bit)
+ return "x86-64";
+
+ if (Triple.getOSName().startswith("haiku"))
+ return "i586";
+ if (Triple.getOSName().startswith("openbsd"))
+ return "i486";
+ if (Triple.getOSName().startswith("bitrig"))
+ return "i686";
+ if (Triple.getOSName().startswith("freebsd"))
+ return "i486";
+ if (Triple.getOSName().startswith("netbsd"))
+ return "i486";
+ // All x86 devices running Android have core2 as their common
+ // denominator. This makes a better choice than pentium4.
+ if (Triple.getEnvironment() == llvm::Triple::Android)
+ return "core2";
+
+ // Fallback to p4.
+ return "pentium4";
+}
+
void Clang::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- const bool isAndroid =
- getToolChain().getTriple().getEnvironment() == llvm::Triple::Android;
if (!Args.hasFlag(options::OPT_mred_zone,
options::OPT_mno_red_zone,
true) ||
@@ -1120,70 +1249,21 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
Args.hasArg(options::OPT_fapple_kext))
CmdArgs.push_back("-disable-red-zone");
- if (Args.hasFlag(options::OPT_msoft_float,
- options::OPT_mno_soft_float,
- false))
- CmdArgs.push_back("-no-implicit-float");
-
- const char *CPUName = 0;
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue()) == "native") {
- // FIXME: Reject attempts to use -march=native unless the target matches
- // the host.
- //
- // FIXME: We should also incorporate the detected target features for use
- // with -native.
- std::string CPU = llvm::sys::getHostCPUName();
- if (!CPU.empty() && CPU != "generic")
- CPUName = Args.MakeArgString(CPU);
- } else
- CPUName = A->getValue();
- }
-
- // Select the default CPU if none was given (or detection failed).
- if (!CPUName) {
- // FIXME: Need target hooks.
- if (getToolChain().getTriple().isOSDarwin()) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "core2";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "yonah";
- } else if (getToolChain().getOS().startswith("haiku")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i586";
- } else if (getToolChain().getOS().startswith("openbsd")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i486";
- } else if (getToolChain().getOS().startswith("bitrig")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i686";
- } else if (getToolChain().getOS().startswith("freebsd")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i486";
- } else if (getToolChain().getOS().startswith("netbsd")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i486";
- } else {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- // All x86 devices running Android have core2 as their common
- // denominator. This makes a better choice than pentium4.
- CPUName = isAndroid ? "core2" : "pentium4";
- }
+ // Default to avoid implicit floating-point for kernel/kext code, but allow
+ // that to be overridden with -mno-soft-float.
+ bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext));
+ if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
+ options::OPT_mno_soft_float,
+ options::OPT_mno_implicit_float)) {
+ const Option &O = A->getOption();
+ NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) ||
+ O.matches(options::OPT_msoft_float));
}
+ if (NoImplicitFloat)
+ CmdArgs.push_back("-no-implicit-float");
- if (CPUName) {
+ if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) {
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(CPUName);
}
@@ -1223,43 +1303,26 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
}
-static Arg* getLastHexagonArchArg (const ArgList &Args)
-{
- Arg * A = NULL;
-
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it) {
- if ((*it)->getOption().matches(options::OPT_march_EQ) ||
- (*it)->getOption().matches(options::OPT_mcpu_EQ)) {
- A = *it;
- A->claim();
- }
- else if ((*it)->getOption().matches(options::OPT_m_Joined)){
- StringRef Value = (*it)->getValue(0);
- if (Value.startswith("v")) {
- A = *it;
- A->claim();
- }
- }
- }
- return A;
+static inline bool HasPICArg(const ArgList &Args) {
+ return Args.hasArg(options::OPT_fPIC)
+ || Args.hasArg(options::OPT_fpic);
}
-static StringRef getHexagonTargetCPU(const ArgList &Args)
-{
- Arg *A;
- llvm::StringRef WhichHexagon;
+static Arg *GetLastSmallDataThresholdArg(const ArgList &Args) {
+ return Args.getLastArg(options::OPT_G,
+ options::OPT_G_EQ,
+ options::OPT_msmall_data_threshold_EQ);
+}
- // Select the default CPU (v4) if none was given or detection failed.
- if ((A = getLastHexagonArchArg (Args))) {
- WhichHexagon = A->getValue();
- if (WhichHexagon == "")
- return "v4";
- else
- return WhichHexagon;
+static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) {
+ std::string value;
+ if (HasPICArg(Args))
+ value = "0";
+ else if (Arg *A = GetLastSmallDataThresholdArg(Args)) {
+ value = A->getValue();
+ A->claim();
}
- else
- return "v4";
+ return value;
}
void Clang::AddHexagonTargetArgs(const ArgList &Args,
@@ -1267,20 +1330,18 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
llvm::Triple Triple = getToolChain().getTriple();
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString("hexagon" + getHexagonTargetCPU(Args)));
+ CmdArgs.push_back(Args.MakeArgString(
+ "hexagon"
+ + toolchains::Hexagon_TC::GetTargetCPU(Args)));
CmdArgs.push_back("-fno-signed-char");
- CmdArgs.push_back("-nobuiltininc");
-
- if (Args.hasArg(options::OPT_mqdsp6_compat))
- CmdArgs.push_back("-mqdsp6-compat");
+ CmdArgs.push_back("-mqdsp6-compat");
+ CmdArgs.push_back("-Wreturn-type");
- if (Arg *A = Args.getLastArg(options::OPT_G,
- options::OPT_msmall_data_threshold_EQ)) {
- std::string SmallDataThreshold="-small-data-threshold=";
- SmallDataThreshold += A->getValue();
+ std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
+ if (!SmallDataThreshold.empty()) {
CmdArgs.push_back ("-mllvm");
- CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
- A->claim();
+ CmdArgs.push_back(Args.MakeArgString(
+ "-hexagon-small-data-threshold=" + SmallDataThreshold));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -1397,24 +1458,18 @@ static bool ShouldDisableCFI(const ArgList &Args,
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 = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- TC.IsIntegratedAssemblerDefault());
+ Default = TC.useIntegratedAs();
}
return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
- options::OPT_fno_dwarf2_cfi_asm,
- Default);
+ options::OPT_fno_dwarf2_cfi_asm,
+ Default);
}
static bool ShouldDisableDwarfDirectory(const ArgList &Args,
const ToolChain &TC) {
- bool IsIADefault = TC.IsIntegratedAssemblerDefault();
- bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIADefault);
bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm,
options::OPT_fno_dwarf_directory_asm,
- UseIntegratedAs);
+ TC.useIntegratedAs());
return !UseDwarfDirectory;
}
@@ -1453,63 +1508,147 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
-SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
- Kind = 0;
-
- const Arg *AsanArg, *TsanArg, *UbsanArg;
+SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args)
+ : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
+ AsanZeroBaseShadow(false) {
+ unsigned AllKinds = 0; // All kinds of sanitizers that were turned on
+ // at least once (possibly, disabled further).
for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
- unsigned Add = 0, Remove = 0;
- const char *DeprecatedReplacement = 0;
- if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) {
- Add = Address;
- DeprecatedReplacement = "-fsanitize=address";
- } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) {
- Remove = Address;
- DeprecatedReplacement = "-fno-sanitize=address";
- } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) {
- Add = Thread;
- DeprecatedReplacement = "-fsanitize=thread";
- } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) {
- Remove = Thread;
- DeprecatedReplacement = "-fno-sanitize=thread";
- } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
- Add = Undefined;
- DeprecatedReplacement = "-fsanitize=undefined";
- } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) {
- Add = parse(D, *I);
- } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) {
- Remove = parse(D, *I);
- } else {
+ unsigned Add, Remove;
+ if (!parse(D, Args, *I, Add, Remove, true))
continue;
- }
-
(*I)->claim();
-
Kind |= Add;
Kind &= ~Remove;
+ AllKinds |= Add;
+ }
+
+ 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 (Add & NeedsAsanRt) AsanArg = *I;
- if (Add & NeedsTsanRt) TsanArg = *I;
- if (Add & NeedsUbsanRt) UbsanArg = *I;
+ 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";
+ }
- // If this is a deprecated synonym, produce a warning directing users
- // towards the new spelling.
- if (DeprecatedReplacement)
- D.Diag(diag::warn_drv_deprecated_arg)
- << (*I)->getAsString(Args) << DeprecatedReplacement;
+ // 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";
}
// Only one runtime library can be used at once.
- // FIXME: Allow Ubsan to be combined with the other two.
bool NeedsAsan = needsAsanRt();
bool NeedsTsan = needsTsanRt();
- bool NeedsUbsan = needsUbsanRt();
- if (NeedsAsan + NeedsTsan + NeedsUbsan > 1)
+ bool NeedsMsan = needsMsanRt();
+ if (NeedsAsan && NeedsTsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsAsanRt)
+ << lastArgumentForKind(D, Args, NeedsTsanRt);
+ if (NeedsAsan && NeedsMsan)
D.Diag(diag::err_drv_argument_not_allowed_with)
- << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg,
- NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
- << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg,
- NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
+ << lastArgumentForKind(D, Args, NeedsAsanRt)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+ if (NeedsTsan && NeedsMsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsTsanRt)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+
+ // 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 && (AllKinds & 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)) {
+ if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
+ std::string BLPath = BLArg->getValue();
+ bool BLExists = false;
+ if (!llvm::sys::fs::exists(BLPath, BLExists) && BLExists)
+ BlacklistFile = BLPath;
+ else
+ D.Diag(diag::err_drv_no_such_file) << BLPath;
+ }
+ } else {
+ // If no -fsanitize-blacklist option is specified, try to look up for
+ // blacklist in the resource directory.
+ std::string BLPath;
+ bool BLExists = false;
+ if (getDefaultBlacklistForKind(D, Kind, BLPath) &&
+ !llvm::sys::fs::exists(BLPath, BLExists) && BLExists)
+ 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-address-zero-base-shadow options.
+ if (NeedsAsan)
+ AsanZeroBaseShadow =
+ Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow,
+ options::OPT_fno_sanitize_address_zero_base_shadow,
+ /* Default */false);
+}
+
+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"));
+
+ // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
+ // etc.) so that the linker picks custom versions of the global 'operator
+ // new' and 'operator delete' symbols. We take the extreme (but simple)
+ // strategy of inserting it at the front of the link command. It also
+ // needs to be forced to end up in the executable, so wrap it in
+ // whole-archive.
+ SmallVector<const char *, 3> LibSanitizerArgs;
+ LibSanitizerArgs.push_back("-whole-archive");
+ LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer));
+ LibSanitizerArgs.push_back("-no-whole-archive");
+
+ CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
+ LibSanitizerArgs.begin(), LibSanitizerArgs.end());
+
+ CmdArgs.push_back("-lpthread");
+ 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
+ // all symbols from the binary.
+ if (ExportSymbols) {
+ if (llvm::sys::fs::exists(LibSanitizer + ".syms"))
+ CmdArgs.push_back(
+ Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms"));
+ else
+ CmdArgs.push_back("-export-dynamic");
+ }
}
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
@@ -1526,19 +1665,17 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
llvm::sys::path::append(LibAsan, "lib", "linux",
(Twine("libclang_rt.asan-") +
TC.getArchName() + "-android.so"));
- CmdArgs.push_back(Args.MakeArgString(LibAsan));
+ CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan));
} else {
if (!Args.hasArg(options::OPT_shared)) {
- // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library
- // resource directory.
- SmallString<128> LibAsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibAsan, "lib", "linux",
- (Twine("libclang_rt.asan-") +
- TC.getArchName() + ".a"));
- CmdArgs.push_back(Args.MakeArgString(LibAsan));
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-ldl");
- CmdArgs.push_back("-export-dynamic");
+ bool ZeroBaseShadow = Args.hasFlag(
+ options::OPT_fsanitize_address_zero_base_shadow,
+ options::OPT_fno_sanitize_address_zero_base_shadow, false);
+ if (ZeroBaseShadow && !Args.hasArg(options::OPT_pie)) {
+ TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) <<
+ "-fsanitize-address-zero-base-shadow" << "-pie";
+ }
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true);
}
}
}
@@ -1548,33 +1685,44 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared)) {
- // LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library
- // resource directory.
- SmallString<128> LibTsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibTsan, "lib", "linux",
- (Twine("libclang_rt.tsan-") +
- TC.getArchName() + ".a"));
- CmdArgs.push_back(Args.MakeArgString(LibTsan));
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-ldl");
- CmdArgs.push_back("-export-dynamic");
+ if (!Args.hasArg(options::OPT_pie))
+ TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) <<
+ "-fsanitize=thread" << "-pie";
+ addSanitizerRTLinkFlagsLinux(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) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_pie))
+ TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) <<
+ "-fsanitize=memory" << "-pie";
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true);
}
}
/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
/// (Linux).
static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared)) {
- // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library
- // resource directory.
- SmallString<128> LibUbsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibUbsan, "lib", "linux",
- (Twine("libclang_rt.ubsan-") +
- TC.getArchName() + ".a"));
- CmdArgs.push_back(Args.MakeArgString(LibUbsan));
- CmdArgs.push_back("-lpthread");
- }
+ ArgStringList &CmdArgs, bool IsCXX,
+ bool HasOtherSanitizerRt) {
+ 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);
+
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false);
+
+ // 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);
}
static bool shouldUseFramePointer(const ArgList &Args,
@@ -1595,6 +1743,80 @@ static bool shouldUseFramePointer(const ArgList &Args,
return true;
}
+static bool shouldUseLeafFramePointer(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
+ options::OPT_momit_leaf_frame_pointer))
+ return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
+
+ // Don't use a leaf frame pointer on linux x86 and x86_64 if optimizing.
+ if ((Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::x86) &&
+ Triple.getOS() == llvm::Triple::Linux) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ if (!A->getOption().matches(options::OPT_O0))
+ return false;
+ }
+
+ return true;
+}
+
+/// If the PWD environment variable is set, add a CC1 option to specify the
+/// debug compilation directory.
+static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) {
+ if (const char *pwd = ::getenv("PWD")) {
+ // GCC also verifies that stat(pwd) and stat(".") have the same inode
+ // number. Not doing those because stats are slow, but we could.
+ if (llvm::sys::path::is_absolute(pwd)) {
+ std::string CompDir = pwd;
+ CmdArgs.push_back("-fdebug-compilation-dir");
+ CmdArgs.push_back(Args.MakeArgString(CompDir));
+ }
+ }
+}
+
+static const char *SplitDebugName(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ Arg *FinalOutput = Args.getLastArg(options::OPT_o);
+ if (FinalOutput && Args.hasArg(options::OPT_c)) {
+ SmallString<128> T(FinalOutput->getValue());
+ llvm::sys::path::replace_extension(T, "dwo");
+ return Args.MakeArgString(T);
+ } else {
+ // Use the 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;
+ return Args.MakeArgString(F);
+ }
+}
+
+static void SplitDebugInfo(const ToolChain &TC, Compilation &C,
+ const Tool &T, const JobAction &JA,
+ const ArgList &Args, const InputInfo &Output,
+ const char *OutFile) {
+ ArgStringList ExtractArgs;
+ ExtractArgs.push_back("--extract-dwo");
+
+ ArgStringList StripArgs;
+ StripArgs.push_back("--strip-dwo");
+
+ // Grabbing the output of the earlier compile step.
+ StripArgs.push_back(Output.getFilename());
+ ExtractArgs.push_back(Output.getFilename());
+ ExtractArgs.push_back(OutFile);
+
+ const char *Exec =
+ Args.MakeArgString(TC.GetProgramPath("objcopy"));
+
+ // First extract the dwo sections.
+ C.addCommand(new Command(JA, T, Exec, ExtractArgs));
+
+ // Then remove them from the original .o file.
+ C.addCommand(new Command(JA, T, Exec, StripArgs));
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -1628,8 +1850,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (isa<PreprocessJobAction>(JA)) {
if (Output.getType() == types::TY_Dependencies)
CmdArgs.push_back("-Eonly");
- else
+ else {
CmdArgs.push_back("-E");
+ if (Args.hasArg(options::OPT_rewrite_objc) &&
+ !Args.hasArg(options::OPT_g_Group))
+ CmdArgs.push_back("-P");
+ }
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
@@ -1690,6 +1916,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
CmdArgs.push_back("-emit-pch");
+ } else if (JA.getType() == types::TY_ModuleFile) {
+ CmdArgs.push_back("-module-file-info");
} else if (JA.getType() == types::TY_RewrittenObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_NonFragile;
@@ -1713,10 +1941,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Set the main file name, so that debug info works even with
// -save-temps.
CmdArgs.push_back("-main-file-name");
- CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
+ CmdArgs.push_back(getBaseInputName(Args, Inputs));
// Some flags which affect the language (via preprocessor
- // defines). See darwin::CC1::AddCPPArgs.
+ // defines).
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("-static-define");
@@ -1812,8 +2040,7 @@ 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 ((Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext)) &&
+ if (KernelOrKext &&
(Triple.getOS() != llvm::Triple::IOS ||
Triple.isOSVersionLT(6)))
PIC = PIE = false;
@@ -1878,6 +2105,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_strict_aliasing,
getToolChain().IsStrictAliasingDefault()))
CmdArgs.push_back("-relaxed-aliasing");
+ if (Args.hasArg(options::OPT_fstruct_path_tbaa))
+ CmdArgs.push_back("-struct-path-tbaa");
if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
false))
CmdArgs.push_back("-fstrict-enums");
@@ -1885,6 +2114,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
+ // Handle segmented stacks.
+ if (Args.hasArg(options::OPT_fsplit_stack))
+ CmdArgs.push_back("-split-stacks");
+
// Handle various floating point optimization flags, mapping them to the
// appropriate LLVM code generation flags. The pattern for all of these is to
// default off the codegen optimizations, and if any flag enables them and no
@@ -2047,7 +2280,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
- getToolChain().addClangTargetOptions(CmdArgs);
+ getToolChain().addClangTargetOptions(Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2084,6 +2317,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AddPPCTargetArgs(Args, CmdArgs);
break;
+ case llvm::Triple::r600:
+ AddR600TargetArgs(Args, CmdArgs);
+ break;
+
case llvm::Triple::sparc:
AddSparcTargetArgs(Args, CmdArgs);
break;
@@ -2106,10 +2343,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
- // -mno-omit-leaf-frame-pointer is the default on Darwin.
- if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer,
- !getToolChain().getTriple().isOSDarwin()))
+ if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple()))
CmdArgs.push_back("-momit-leaf-frame-pointer");
// Explicitly error on some things we know we don't support and can't just
@@ -2143,16 +2377,15 @@ 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"
+ // is 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))
CmdArgs.push_back("-gline-tables-only");
- } else if (!A->getOption().matches(options::OPT_g0) &&
- !A->getOption().matches(options::OPT_ggdb0)) {
+ else if (!A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_ggdb0))
CmdArgs.push_back("-g");
- }
}
// We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
@@ -2160,6 +2393,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_gcolumn_info))
CmdArgs.push_back("-dwarf-column-info");
+ // -gsplit-dwarf should turn on -g and enable the backend dwarf
+ // splitting and extraction.
+ // FIXME: Currently only works on Linux.
+ if (getToolChain().getTriple().getOS() == llvm::Triple::Linux &&
+ Args.hasArg(options::OPT_gsplit_dwarf)) {
+ CmdArgs.push_back("-g");
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-split-dwarf=Enable");
+ }
+
Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
@@ -2176,9 +2419,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
C.getArgs().hasArg(options::OPT_S)) {
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-file");
- SmallString<128> absFilename(Output.getFilename());
- llvm::sys::fs::make_absolute(absFilename);
- CmdArgs.push_back(Args.MakeArgString(absFilename));
+ SmallString<128> CoverageFilename(Output.getFilename());
+ if (llvm::sys::path::is_relative(CoverageFilename.str())) {
+ if (const char *pwd = ::getenv("PWD")) {
+ if (llvm::sys::path::is_absolute(pwd)) {
+ SmallString<128> Pwd(pwd);
+ llvm::sys::path::append(Pwd, CoverageFilename.str());
+ CoverageFilename.swap(Pwd);
+ }
+ }
+ }
+ CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
}
}
@@ -2250,7 +2501,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: Support -fpreprocessed
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(C, D, Args, CmdArgs, Output, Inputs);
+ AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
// Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
// that "The compiler can only warn and ignore the option if not recognized".
@@ -2270,6 +2521,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
}
+ // 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_W_Group);
if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
CmdArgs.push_back("-pedantic");
@@ -2342,15 +2597,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (ShouldDisableDwarfDirectory(Args, getToolChain()))
CmdArgs.push_back("-fno-dwarf-directory-asm");
- if (const char *pwd = ::getenv("PWD")) {
- // GCC also verifies that stat(pwd) and stat(".") have the same inode
- // number. Not doing those because stats are slow, but we could.
- if (llvm::sys::path::is_absolute(pwd)) {
- std::string CompDir = pwd;
- CmdArgs.push_back("-fdebug-compilation-dir");
- CmdArgs.push_back(Args.MakeArgString(CompDir));
- }
- }
+ // Add in -fdebug-compilation-dir if necessary.
+ addDebugCompDirArg(Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
options::OPT_ftemplate_depth_EQ)) {
@@ -2363,6 +2611,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
+ CmdArgs.push_back("-fbracket-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
options::OPT_Wlarge_by_value_copy_def)) {
if (A->getNumValues()) {
@@ -2372,14 +2625,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
}
- if (Arg *A = Args.getLastArg(options::OPT_fbounds_checking,
- options::OPT_fbounds_checking_EQ)) {
- if (A->getNumValues()) {
- StringRef val = A->getValue();
- CmdArgs.push_back(Args.MakeArgString("-fbounds-checking=" + val));
- } else
- CmdArgs.push_back("-fbounds-checking=1");
- }
if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
@@ -2426,9 +2671,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Twine(N)));
}
- if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue());
+ // -fvisibility= and -fvisibility-ms-compat are of a piece.
+ if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
+ options::OPT_fvisibility_ms_compat)) {
+ if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back(A->getValue());
+ } else {
+ assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("hidden");
+ CmdArgs.push_back("-ftype-visibility");
+ CmdArgs.push_back("default");
+ }
}
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
@@ -2453,7 +2708,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
SanitizerArgs Sanitize(D, Args);
Sanitize.addArgs(Args, CmdArgs);
- // Report and error for -faltivec on anything other then PowerPC.
+ if (!Args.hasFlag(options::OPT_fsanitize_recover,
+ options::OPT_fno_sanitize_recover,
+ true))
+ CmdArgs.push_back("-fno-sanitize-recover");
+
+ 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, false))
+ CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
+
+ // Report an error for -faltivec on anything other than PowerPC.
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
getToolChain().getTriple().getArch() == llvm::Triple::ppc64))
@@ -2552,7 +2817,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
- if (Args.hasArg(options::OPT_mstrict_align)) {
+ // -mkernel implies -mstrict-align; don't add the redundant option.
+ if (Args.hasArg(options::OPT_mstrict_align) && !KernelOrKext) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-strict-align");
}
@@ -2591,12 +2857,49 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fmodules enables modules (off by default). However, for C++/Objective-C++,
// users must also pass -fcxx-modules. The latter flag will disappear once the
// modules implementation is solid for C++/Objective-C++ programs as well.
+ bool HaveModules = false;
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules,
false);
- if (AllowedInCXX || !types::isCXX(InputType))
+ if (AllowedInCXX || !types::isCXX(InputType)) {
CmdArgs.push_back("-fmodules");
+ HaveModules = true;
+ }
+ }
+
+ // 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);
+ }
+ } 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));
+ }
+
+ // 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);
+
+ // -fmodules-autolink (on by default when modules is enabled) automatically
+ // links against libraries for imported modules. This requires the
+ // integrated assembler.
+ if (HaveModules && getToolChain().useIntegratedAs() &&
+ Args.hasFlag(options::OPT_fmodules_autolink,
+ options::OPT_fno_modules_autolink,
+ true)) {
+ CmdArgs.push_back("-fmodules-autolink");
}
// -faccess-control is default.
@@ -2658,10 +2961,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fms-extensions");
- // -fms-inline-asm.
- if (Args.hasArg(options::OPT_fenable_experimental_ms_inline_asm))
- CmdArgs.push_back("-fenable-experimental-ms-inline-asm");
-
// -fms-compatibility=0 is default.
if (Args.hasFlag(options::OPT_fms_compatibility,
options::OPT_fno_ms_compatibility,
@@ -2683,7 +2982,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
- // -fborland-extensions=0 is default.
+ // -fno-borland-extensions is default.
if (Args.hasFlag(options::OPT_fborland_extensions,
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
@@ -2837,8 +3136,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fpack-struct=1");
}
- if (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext)) {
+ if (KernelOrKext) {
if (!Args.hasArg(options::OPT_fcommon))
CmdArgs.push_back("-fno-common");
Args.ClaimAllArgs(options::OPT_fno_common);
@@ -2919,9 +3217,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-spell-checking");
- // Silently ignore -fasm-blocks for now.
- (void) Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
- false);
+ // -fno-asm-blocks is default.
+ if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
+ false))
+ CmdArgs.push_back("-fasm-blocks");
+
+ // -fvectorize is default.
+ if (Args.hasFlag(options::OPT_fvectorize,
+ options::OPT_fno_vectorize, true)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-vectorize-loops");
+ }
+
+ // -fno-slp-vectorize is default.
+ if (Args.hasFlag(options::OPT_fslp_vectorize,
+ options::OPT_fno_slp_vectorize, false)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-vectorize");
+ }
if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ))
A->render(Args, CmdArgs);
@@ -2983,6 +3296,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
CmdArgs.push_back("-fretain-comments-from-system-headers");
+ // Forward -fcomment-block-commands to -cc1.
+ Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
+
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
@@ -3043,8 +3359,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Flags.str()));
}
+ // Add the split debug info name to the command lines here so we
+ // can propagate it to the backend.
+ bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) &&
+ (getToolChain().getTriple().getOS() == llvm::Triple::Linux) &&
+ (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA));
+ const char *SplitDwarfOut;
+ if (SplitDwarf) {
+ CmdArgs.push_back("-split-dwarf-file");
+ SplitDwarfOut = SplitDebugName(Args, Inputs);
+ CmdArgs.push_back(SplitDwarfOut);
+ }
+
+ // Finally add the compile command to the compilation.
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ // Handle the debug info splitting at object creation time if we're
+ // creating an object.
+ // TODO: Currently only works on linux with newer objcopy.
+ if (SplitDwarf && !isa<CompileJobAction>(JA))
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut);
+
if (Arg *A = Args.getLastArg(options::OPT_pg))
if (Args.hasArg(options::OPT_fomit_frame_pointer))
D.Diag(diag::err_drv_argument_not_allowed_with)
@@ -3085,6 +3420,15 @@ void ClangAs::AddARMTargetArgs(const ArgList &Args,
addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple));
}
+void ClangAs::AddX86TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Set the CPU based on -march=.
+ if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(CPUName);
+ }
+}
+
/// Add options related to the Objective-C runtime/ABI.
///
/// Returns true if the runtime is non-fragile.
@@ -3243,6 +3587,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-filetype");
CmdArgs.push_back("obj");
+ // Set the main file name, so that debug info works even with
+ // -save-temps or preprocessed assembly.
+ CmdArgs.push_back("-main-file-name");
+ CmdArgs.push_back(Clang::getBaseInputName(Args, Inputs));
+
if (UseRelaxAll(C, Args))
CmdArgs.push_back("-relax-all");
@@ -3255,6 +3604,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::thumb:
AddARMTargetArgs(Args, CmdArgs);
break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ AddX86TargetArgs(Args, CmdArgs);
+ break;
}
// Ignore explicit -force_cpusubtype_ALL option.
@@ -3267,13 +3621,22 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
SourceAction = SourceAction->getInputs()[0];
}
- // Forward -g, assuming we are dealing with an actual assembly file.
+ // Forward -g and handle debug info related flags, assuming we are dealing
+ // with an actual assembly file.
if (SourceAction->getType() == types::TY_Asm ||
SourceAction->getType() == types::TY_PP_Asm) {
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group))
if (!A->getOption().matches(options::OPT_g0))
CmdArgs.push_back("-g");
+
+ // Add the -fdebug-compilation-dir flag if needed.
+ addDebugCompDirArg(Args, CmdArgs);
+
+ // Set the AT_producer to the clang version when using the integrated
+ // assembler on assembly source files.
+ CmdArgs.push_back("-dwarf-debug-producer");
+ CmdArgs.push_back(Args.MakeArgString(getClangFullVersion()));
}
// Optionally embed the -cc1as level arguments into the debug info, for build
@@ -3361,7 +3724,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
// here.
if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
CmdArgs.push_back("-m32");
- else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86_64)
+ else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64)
CmdArgs.push_back("-m64");
if (Output.isFilename()) {
@@ -3395,6 +3758,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
else if (II.getType() == types::TY_AST)
D.Diag(diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
+ else if (II.getType() == types::TY_ModuleFile)
+ D.Diag(diag::err_drv_no_module_support)
+ << getToolChain().getTripleString();
if (types::canTypeBeUserSpecified(II.getType())) {
CmdArgs.push_back("-x");
@@ -3483,7 +3849,7 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
ArgStringList CmdArgs;
std::string MarchString = "-march=";
- MarchString += getHexagonTargetCPU(Args);
+ MarchString += toolchains::Hexagon_TC::GetTargetCPU(Args);
CmdArgs.push_back(Args.MakeArgString(MarchString));
RenderExtraToolArgs(JA, CmdArgs);
@@ -3496,6 +3862,14 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fsyntax-only");
}
+ std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
+ if (!SmallDataThreshold.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-G") + SmallDataThreshold));
+
+ Args.AddAllArgs(CmdArgs, options::OPT_g_Group);
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
// Only pass -x if gcc will understand it; otherwise hope gcc
// understands the suffix correctly. The main use case this would go
@@ -3517,6 +3891,9 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
else if (II.getType() == types::TY_AST)
D.Diag(clang::diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
+ else if (II.getType() == types::TY_ModuleFile)
+ D.Diag(diag::err_drv_no_module_support)
+ << getToolChain().getTripleString();
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
@@ -3542,77 +3919,168 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
+ const toolchains::Hexagon_TC& ToolChain =
+ static_cast<const toolchains::Hexagon_TC&>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+
ArgStringList CmdArgs;
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- Arg *A = *it;
- if (forwardToGCC(A->getOption())) {
- // Don't forward any -g arguments to assembly steps.
- if (isa<AssembleJobAction>(JA) &&
- A->getOption().matches(options::OPT_g_Group))
- continue;
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ bool hasStaticArg = Args.hasArg(options::OPT_static);
+ bool buildingLib = Args.hasArg(options::OPT_shared);
+ bool buildPIE = Args.hasArg(options::OPT_pie);
+ bool incStdLib = !Args.hasArg(options::OPT_nostdlib);
+ bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+ bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+ bool useShared = buildingLib && !hasStaticArg;
+
+ //----------------------------------------------------------------------------
+ // Silence warnings for various options
+ //----------------------------------------------------------------------------
- // It is unfortunate that we have to claim here, as this means
- // we will basically never report anything interesting for
- // platforms using a generic gcc, even if we are just using gcc
- // to get to the assembler.
- A->claim();
- A->render(Args, CmdArgs);
- }
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_static_libgcc);
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ for (std::vector<std::string>::const_iterator i = ToolChain.ExtraOpts.begin(),
+ e = ToolChain.ExtraOpts.end();
+ i != e; ++i)
+ CmdArgs.push_back(i->c_str());
+
+ std::string MarchString = toolchains::Hexagon_TC::GetTargetCPU(Args);
+ CmdArgs.push_back(Args.MakeArgString("-m" + MarchString));
+
+ if (buildingLib) {
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("-call_shared"); // should be the default, but doing as
+ // hexagon-gcc does
}
- RenderExtraToolArgs(JA, CmdArgs);
+ if (hasStaticArg)
+ CmdArgs.push_back("-static");
- // Add Arch Information
- Arg *A;
- if ((A = getLastHexagonArchArg(Args))) {
- if (A->getOption().matches(options::OPT_m_Joined))
- A->render(Args, CmdArgs);
- else
- CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+ if (buildPIE && !buildingLib)
+ CmdArgs.push_back("-pie");
+
+ std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
+ if (!SmallDataThreshold.empty()) {
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-G") + SmallDataThreshold));
}
- else {
- CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ const std::string MarchSuffix = "/" + MarchString;
+ const std::string G0Suffix = "/G0";
+ const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
+ const std::string RootDir = toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir)
+ + "/";
+ const std::string StartFilesDir = RootDir
+ + "hexagon/lib"
+ + (buildingLib
+ ? MarchG0Suffix : MarchSuffix);
+
+ //----------------------------------------------------------------------------
+ // moslib
+ //----------------------------------------------------------------------------
+ std::vector<std::string> oslibs;
+ bool hasStandalone= false;
+
+ for (arg_iterator it = Args.filtered_begin(options::OPT_moslib_EQ),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ (*it)->claim();
+ oslibs.push_back((*it)->getValue());
+ hasStandalone = hasStandalone || (oslibs.back() == "standalone");
+ }
+ if (oslibs.empty()) {
+ oslibs.push_back("standalone");
+ hasStandalone = true;
}
- CmdArgs.push_back("-mqdsp6-compat");
+ //----------------------------------------------------------------------------
+ // Start Files
+ //----------------------------------------------------------------------------
+ if (incStdLib && incStartFiles) {
- const char *GCCName;
- if (C.getDriver().CCCIsCXX)
- GCCName = "hexagon-g++";
- else
- GCCName = "hexagon-gcc";
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+ if (!buildingLib) {
+ if (hasStandalone) {
+ CmdArgs.push_back(
+ Args.MakeArgString(StartFilesDir + "/crt0_standalone.o"));
+ }
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o"));
+ }
+ std::string initObj = useShared ? "/initS.o" : "/init.o";
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj));
+ }
+
+ //----------------------------------------------------------------------------
+ // 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));
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- }
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- // 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)
- D.Diag(clang::diag::err_drv_no_linker_llvm_support)
- << getToolChain().getTripleString();
- else if (II.getType() == types::TY_AST)
- D.Diag(clang::diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
+ //----------------------------------------------------------------------------
+ // Libraries
+ //----------------------------------------------------------------------------
+ if (incStdLib && incDefLibs) {
+ if (D.CCCIsCXX) {
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
- else
- // Don't render as input, we need gcc to do the translations. FIXME: Pranav: What is this ?
- II.getInputArg().render(Args, CmdArgs);
+ CmdArgs.push_back("--start-group");
+
+ if (!buildingLib) {
+ for(std::vector<std::string>::iterator i = oslibs.begin(),
+ e = oslibs.end(); i != e; ++i)
+ CmdArgs.push_back(Args.MakeArgString("-l" + *i));
+ CmdArgs.push_back("-lc");
+ }
+ CmdArgs.push_back("-lgcc");
+
+ CmdArgs.push_back("--end-group");
}
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ //----------------------------------------------------------------------------
+ // End files
+ //----------------------------------------------------------------------------
+ if (incStdLib && incStartFiles) {
+ std::string finiObj = useShared ? "/finiS.o" : "/fini.o";
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj));
+ }
+
+ std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
+ C.addCommand(
+ new Command(
+ JA, *this,
+ Args.MakeArgString(Linker), CmdArgs));
}
// Hexagon tools end.
@@ -3638,8 +4106,9 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
llvm::Triple::x86)
.Case("x86_64", llvm::Triple::x86_64)
// This is derived from the driver driver.
- .Cases("arm", "armv4t", "armv5", "armv6", llvm::Triple::arm)
- .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", llvm::Triple::arm)
+ .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
+ .Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm)
+ .Cases("armv7s", "xscale", llvm::Triple::arm)
.Case("r600", llvm::Triple::r600)
.Case("nvptx", llvm::Triple::nvptx)
.Case("nvptx64", llvm::Triple::nvptx64)
@@ -3648,38 +4117,14 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
.Default(llvm::Triple::UnknownArch);
}
-const char *darwin::CC1::getCC1Name(types::ID Type) const {
- switch (Type) {
- default:
- llvm_unreachable("Unexpected type for Darwin CC1 tool.");
- case types::TY_Asm:
- case types::TY_C: case types::TY_CHeader:
- case types::TY_PP_C: case types::TY_PP_CHeader:
- return "cc1";
- case types::TY_ObjC: case types::TY_ObjCHeader:
- case types::TY_PP_ObjC: case types::TY_PP_ObjC_Alias:
- case types::TY_PP_ObjCHeader:
- return "cc1obj";
- case types::TY_CXX: case types::TY_CXXHeader:
- case types::TY_PP_CXX: case types::TY_PP_CXXHeader:
- return "cc1plus";
- case types::TY_ObjCXX: case types::TY_ObjCXXHeader:
- case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias:
- case types::TY_PP_ObjCXXHeader:
- return "cc1objplus";
- }
-}
-
-void darwin::CC1::anchor() {}
-
-const char *darwin::CC1::getBaseInputName(const ArgList &Args,
- const InputInfoList &Inputs) {
+const char *Clang::getBaseInputName(const ArgList &Args,
+ const InputInfoList &Inputs) {
return Args.MakeArgString(
llvm::sys::path::filename(Inputs[0].getBaseInput()));
}
-const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
- const InputInfoList &Inputs) {
+const char *Clang::getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Inputs) {
const char *Str = getBaseInputName(Args, Inputs);
if (const char *End = strrchr(Str, '.'))
@@ -3688,9 +4133,8 @@ const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
return Str;
}
-const char *
-darwin::CC1::getDependencyFileName(const ArgList &Args,
- const InputInfoList &Inputs) {
+const char *Clang::getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs) {
// FIXME: Think about this more.
std::string Res;
@@ -3698,588 +4142,11 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
std::string Str(OutputOpt->getValue());
Res = Str.substr(0, Str.rfind('.'));
} else {
- Res = darwin::CC1::getBaseInputStem(Args, Inputs);
+ Res = getBaseInputStem(Args, Inputs);
}
return Args.MakeArgString(Res + ".d");
}
-void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
- for (ArgStringList::iterator it = CmdArgs.begin(), ie = CmdArgs.end();
- it != ie;) {
-
- StringRef Option = *it;
- bool RemoveOption = false;
-
- // Erase both -fmodule-cache-path and its argument.
- if (Option.equals("-fmodule-cache-path") && it+2 != ie) {
- it = CmdArgs.erase(it, it+2);
- ie = CmdArgs.end();
- continue;
- }
-
- // Remove unsupported -f options.
- if (Option.startswith("-f")) {
- // Remove -f/-fno- to reduce the number of cases.
- if (Option.startswith("-fno-"))
- Option = Option.substr(5);
- else
- Option = Option.substr(2);
- RemoveOption = llvm::StringSwitch<bool>(Option)
- .Case("altivec", true)
- .Case("modules", true)
- .Case("diagnostics-show-note-include-stack", true)
- .Default(false);
- }
-
- // Handle machine specific options.
- if (Option.startswith("-m")) {
- RemoveOption = llvm::StringSwitch<bool>(Option)
- .Case("-mthumb", true)
- .Case("-mno-thumb", true)
- .Case("-mno-fused-madd", true)
- .Case("-mlong-branch", true)
- .Case("-mlongcall", true)
- .Case("-mcpu=G4", true)
- .Case("-mcpu=G5", true)
- .Default(false);
- }
-
- // Handle warning options.
- if (Option.startswith("-W")) {
- // Remove -W/-Wno- to reduce the number of cases.
- if (Option.startswith("-Wno-"))
- Option = Option.substr(5);
- else
- Option = Option.substr(2);
-
- RemoveOption = llvm::StringSwitch<bool>(Option)
- .Case("address-of-temporary", true)
- .Case("ambiguous-member-template", true)
- .Case("analyzer-incompatible-plugin", true)
- .Case("array-bounds", true)
- .Case("array-bounds-pointer-arithmetic", true)
- .Case("bind-to-temporary-copy", true)
- .Case("bitwise-op-parentheses", true)
- .Case("bool-conversions", true)
- .Case("builtin-macro-redefined", true)
- .Case("c++-hex-floats", true)
- .Case("c++0x-compat", true)
- .Case("c++0x-extensions", true)
- .Case("c++0x-narrowing", true)
- .Case("c++11-compat", true)
- .Case("c++11-extensions", true)
- .Case("c++11-narrowing", true)
- .Case("conditional-uninitialized", true)
- .Case("constant-conversion", true)
- .Case("conversion-null", true)
- .Case("CFString-literal", true)
- .Case("constant-logical-operand", true)
- .Case("custom-atomic-properties", true)
- .Case("default-arg-special-member", true)
- .Case("delegating-ctor-cycles", true)
- .Case("delete-non-virtual-dtor", true)
- .Case("deprecated-implementations", true)
- .Case("deprecated-writable-strings", true)
- .Case("distributed-object-modifiers", true)
- .Case("duplicate-method-arg", true)
- .Case("dynamic-class-memaccess", true)
- .Case("enum-compare", true)
- .Case("enum-conversion", true)
- .Case("exit-time-destructors", true)
- .Case("gnu", true)
- .Case("gnu-designator", true)
- .Case("header-hygiene", true)
- .Case("idiomatic-parentheses", true)
- .Case("ignored-qualifiers", true)
- .Case("implicit-atomic-properties", true)
- .Case("incompatible-pointer-types", true)
- .Case("incomplete-implementation", true)
- .Case("int-conversion", true)
- .Case("initializer-overrides", true)
- .Case("invalid-noreturn", true)
- .Case("invalid-token-paste", true)
- .Case("language-extension-token", true)
- .Case("literal-conversion", true)
- .Case("literal-range", true)
- .Case("local-type-template-args", true)
- .Case("logical-op-parentheses", true)
- .Case("method-signatures", true)
- .Case("microsoft", true)
- .Case("mismatched-tags", true)
- .Case("missing-method-return-type", true)
- .Case("non-pod-varargs", true)
- .Case("nonfragile-abi2", true)
- .Case("null-arithmetic", true)
- .Case("null-dereference", true)
- .Case("out-of-line-declaration", true)
- .Case("overriding-method-mismatch", true)
- .Case("readonly-setter-attrs", true)
- .Case("return-stack-address", true)
- .Case("self-assign", true)
- .Case("semicolon-before-method-body", true)
- .Case("sentinel", true)
- .Case("shift-overflow", true)
- .Case("shift-sign-overflow", true)
- .Case("sign-conversion", true)
- .Case("sizeof-array-argument", true)
- .Case("sizeof-pointer-memaccess", true)
- .Case("string-compare", true)
- .Case("super-class-method-mismatch", true)
- .Case("tautological-compare", true)
- .Case("typedef-redefinition", true)
- .Case("typename-missing", true)
- .Case("undefined-reinterpret-cast", true)
- .Case("unknown-warning-option", true)
- .Case("unnamed-type-template-args", true)
- .Case("unneeded-internal-declaration", true)
- .Case("unneeded-member-function", true)
- .Case("unused-comparison", true)
- .Case("unused-exception-parameter", true)
- .Case("unused-member-function", true)
- .Case("unused-result", true)
- .Case("vector-conversions", true)
- .Case("vla", true)
- .Case("used-but-marked-unused", true)
- .Case("weak-vtables", true)
- .Default(false);
- } // if (Option.startswith("-W"))
- if (RemoveOption) {
- it = CmdArgs.erase(it);
- ie = CmdArgs.end();
- } else {
- ++it;
- }
- }
-}
-
-void darwin::CC1::AddCC1Args(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getDriver();
-
- CheckCodeGenerationOptions(D, Args);
-
- // Derived from cc1 spec.
- if ((!Args.hasArg(options::OPT_mkernel) ||
- (getDarwinToolChain().isTargetIPhoneOS() &&
- !getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) &&
- !Args.hasArg(options::OPT_static) &&
- !Args.hasArg(options::OPT_mdynamic_no_pic))
- CmdArgs.push_back("-fPIC");
-
- if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
- getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
- if (!Args.hasArg(options::OPT_fbuiltin_strcat))
- CmdArgs.push_back("-fno-builtin-strcat");
- if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
- CmdArgs.push_back("-fno-builtin-strcpy");
- }
-
- if (Args.hasArg(options::OPT_g_Flag) &&
- !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols))
- CmdArgs.push_back("-feliminate-unused-debug-symbols");
-}
-
-void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const {
- const Driver &D = getToolChain().getDriver();
-
- // Derived from cc1_options spec.
- if (Args.hasArg(options::OPT_fast) ||
- Args.hasArg(options::OPT_fastf) ||
- Args.hasArg(options::OPT_fastcp))
- CmdArgs.push_back("-O3");
-
- if (Arg *A = Args.getLastArg(options::OPT_pg))
- if (Args.hasArg(options::OPT_fomit_frame_pointer))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "-fomit-frame-pointer";
-
- AddCC1Args(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_Q))
- CmdArgs.push_back("-quiet");
-
- CmdArgs.push_back("-dumpbase");
- CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
-
- Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_a_Group);
-
- // FIXME: The goal is to use the user provided -o if that is our
- // final output, otherwise to drive from the original input
- // name. Find a clean way to go about this.
- if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
- Args.hasArg(options::OPT_o)) {
- Arg *OutputOpt = Args.getLastArg(options::OPT_o);
- CmdArgs.push_back("-auxbase-strip");
- CmdArgs.push_back(OutputOpt->getValue());
- } else {
- CmdArgs.push_back("-auxbase");
- CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_g_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_O);
- // FIXME: -Wall is getting some special treatment. Investigate.
- Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
- Args.AddLastArg(CmdArgs, options::OPT_w);
- Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
- options::OPT_trigraphs);
- if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
- // Honor -std-default.
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
- }
-
- if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("-version");
- if (Args.hasArg(options::OPT_pg) &&
- getToolChain().SupportsProfiling())
- CmdArgs.push_back("-p");
- Args.AddLastArg(CmdArgs, options::OPT_p);
-
- // The driver treats -fsyntax-only specially.
- if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
- getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
- // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are
- // used to inhibit the default -fno-builtin-str{cat,cpy}.
- //
- // FIXME: Should we grow a better way to deal with "removing" args?
- for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group,
- options::OPT_fsyntax_only),
- ie = Args.filtered_end(); it != ie; ++it) {
- if (!(*it)->getOption().matches(options::OPT_fbuiltin_strcat) &&
- !(*it)->getOption().matches(options::OPT_fbuiltin_strcpy)) {
- (*it)->claim();
- (*it)->render(Args, CmdArgs);
- }
- }
- } else
- Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
-
- // Claim Clang only -f options, they aren't worth warning about.
- Args.ClaimAllArgs(options::OPT_f_clang_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_undef);
- if (Args.hasArg(options::OPT_Qn))
- CmdArgs.push_back("-fno-ident");
-
- // FIXME: This isn't correct.
- //Args.AddLastArg(CmdArgs, options::OPT__help)
- //Args.AddLastArg(CmdArgs, options::OPT__targetHelp)
-
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
-
- // FIXME: Still don't get what is happening here. Investigate.
- Args.AddAllArgs(CmdArgs, options::OPT__param);
-
- if (Args.hasArg(options::OPT_fmudflap) ||
- Args.hasArg(options::OPT_fmudflapth)) {
- CmdArgs.push_back("-fno-builtin");
- CmdArgs.push_back("-fno-merge-constants");
- }
-
- if (Args.hasArg(options::OPT_coverage)) {
- CmdArgs.push_back("-fprofile-arcs");
- CmdArgs.push_back("-ftest-coverage");
- }
-
- if (types::isCXX(Inputs[0].getType()))
- CmdArgs.push_back("-D__private_extern__=extern");
-}
-
-void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const {
- // Derived from cpp_options
- AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
-
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
-
- AddCC1Args(Args, CmdArgs);
-
- // NOTE: The code below has some commonality with cpp_options, but
- // in classic gcc style ends up sending things in different
- // orders. This may be a good merge candidate once we drop pedantic
- // compatibility.
-
- Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
- options::OPT_trigraphs);
- if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
- // Honor -std-default.
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
- }
- Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
- Args.AddLastArg(CmdArgs, options::OPT_w);
-
- // The driver treats -fsyntax-only specially.
- Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
-
- // Claim Clang only -f options, they aren't worth warning about.
- Args.ClaimAllArgs(options::OPT_f_clang_Group);
-
- if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) &&
- !Args.hasArg(options::OPT_fno_working_directory))
- CmdArgs.push_back("-fworking-directory");
-
- Args.AddAllArgs(CmdArgs, options::OPT_O);
- Args.AddAllArgs(CmdArgs, options::OPT_undef);
- if (Args.hasArg(options::OPT_save_temps))
- CmdArgs.push_back("-fpch-preprocess");
-}
-
-void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
- ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const {
- const Driver &D = getToolChain().getDriver();
-
- CheckPreprocessingOptions(D, Args);
-
- // Derived from cpp_unique_options.
- // -{C,CC} only with -E is checked in CheckPreprocessingOptions().
- Args.AddLastArg(CmdArgs, options::OPT_C);
- Args.AddLastArg(CmdArgs, options::OPT_CC);
- if (!Args.hasArg(options::OPT_Q))
- CmdArgs.push_back("-quiet");
- Args.AddAllArgs(CmdArgs, options::OPT_nostdinc);
- Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx);
- Args.AddLastArg(CmdArgs, options::OPT_v);
- Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
- Args.AddLastArg(CmdArgs, options::OPT_P);
-
- // FIXME: Handle %I properly.
- if (getToolChain().getArch() == llvm::Triple::x86_64) {
- CmdArgs.push_back("-imultilib");
- CmdArgs.push_back("x86_64");
- }
-
- if (Args.hasArg(options::OPT_MD)) {
- CmdArgs.push_back("-MD");
- CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
- }
-
- if (Args.hasArg(options::OPT_MMD)) {
- CmdArgs.push_back("-MMD");
- CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_M);
- Args.AddLastArg(CmdArgs, options::OPT_MM);
- Args.AddAllArgs(CmdArgs, options::OPT_MF);
- Args.AddLastArg(CmdArgs, options::OPT_MG);
- Args.AddLastArg(CmdArgs, options::OPT_MP);
- Args.AddAllArgs(CmdArgs, options::OPT_MQ);
- Args.AddAllArgs(CmdArgs, options::OPT_MT);
- if (!Args.hasArg(options::OPT_M) && !Args.hasArg(options::OPT_MM) &&
- (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) {
- if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
- CmdArgs.push_back("-MQ");
- CmdArgs.push_back(OutputOpt->getValue());
- }
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_remap);
- if (Args.hasArg(options::OPT_g3))
- CmdArgs.push_back("-dD");
- Args.AddLastArg(CmdArgs, options::OPT_H);
-
- AddCPPArgs(Args, CmdArgs);
-
- Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U, options::OPT_A);
- Args.AddAllArgs(CmdArgs, options::OPT_i_Group);
-
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
- CmdArgs.push_back(II.getFilename());
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
- options::OPT_Xpreprocessor);
-
- if (Args.hasArg(options::OPT_fmudflap)) {
- CmdArgs.push_back("-D_MUDFLAP");
- CmdArgs.push_back("-include");
- CmdArgs.push_back("mf-runtime.h");
- }
-
- if (Args.hasArg(options::OPT_fmudflapth)) {
- CmdArgs.push_back("-D_MUDFLAP");
- CmdArgs.push_back("-D_MUDFLAPTH");
- CmdArgs.push_back("-include");
- CmdArgs.push_back("mf-runtime.h");
- }
-}
-
-void darwin::CC1::AddCPPArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Derived from cpp spec.
-
- if (Args.hasArg(options::OPT_static)) {
- // The gcc spec is broken here, it refers to dynamic but
- // that has been translated. Start by being bug compatible.
-
- // if (!Args.hasArg(arglist.parser.dynamicOption))
- CmdArgs.push_back("-D__STATIC__");
- } else
- CmdArgs.push_back("-D__DYNAMIC__");
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-D_REENTRANT");
-}
-
-void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs!");
-
- CmdArgs.push_back("-E");
-
- if (Args.hasArg(options::OPT_traditional) ||
- Args.hasArg(options::OPT_traditional_cpp))
- CmdArgs.push_back("-traditional-cpp");
-
- ArgStringList OutputArgs;
- assert(Output.isFilename() && "Unexpected CC1 output.");
- OutputArgs.push_back("-o");
- OutputArgs.push_back(Output.getFilename());
-
- if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) {
- AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
- } else {
- AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
-
- RemoveCC1UnsupportedArgs(CmdArgs);
-
- const char *CC1Name = getCC1Name(Inputs[0].getType());
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
-
-void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs!");
-
- // Silence warning about unused --serialize-diagnostics
- Args.ClaimAllArgs(options::OPT__serialize_diags);
-
- types::ID InputType = Inputs[0].getType();
- if (const Arg *A = Args.getLastArg(options::OPT_traditional))
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << A->getAsString(Args) << "-E";
-
- if (JA.getType() == types::TY_LLVM_IR ||
- JA.getType() == types::TY_LTO_IR)
- CmdArgs.push_back("-emit-llvm");
- else if (JA.getType() == types::TY_LLVM_BC ||
- JA.getType() == types::TY_LTO_BC)
- CmdArgs.push_back("-emit-llvm-bc");
- else if (Output.getType() == types::TY_AST)
- D.Diag(diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
- else if (JA.getType() != types::TY_PP_Asm &&
- JA.getType() != types::TY_PCH)
- D.Diag(diag::err_drv_invalid_gcc_output_type)
- << getTypeName(JA.getType());
-
- ArgStringList OutputArgs;
- if (Output.getType() != types::TY_PCH) {
- OutputArgs.push_back("-o");
- if (Output.isNothing())
- OutputArgs.push_back("/dev/null");
- else
- OutputArgs.push_back(Output.getFilename());
- }
-
- // There is no need for this level of compatibility, but it makes
- // diffing easier.
- bool OutputArgsEarly = (Args.hasArg(options::OPT_fsyntax_only) ||
- Args.hasArg(options::OPT_S));
-
- if (types::getPreprocessedType(InputType) != types::TY_INVALID) {
- AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
- if (OutputArgsEarly) {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
- } else {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
- }
- } else {
- CmdArgs.push_back("-fpreprocessed");
-
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
- // Reject AST inputs.
- if (II.getType() == types::TY_AST) {
- D.Diag(diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
- return;
- }
-
- CmdArgs.push_back(II.getFilename());
- }
-
- if (OutputArgsEarly) {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
- } else {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
- }
- }
-
- if (Output.getType() == types::TY_PCH) {
- assert(Output.isFilename() && "Invalid PCH output.");
-
- CmdArgs.push_back("-o");
- // NOTE: gcc uses a temp .s file for this, but there doesn't seem
- // to be a good reason.
- const char *TmpPath = C.getArgs().MakeArgString(
- D.GetTemporaryPath("cc", "s"));
- C.addTempFile(TmpPath);
- CmdArgs.push_back(TmpPath);
-
- // If we're emitting a pch file with the last 4 characters of ".pth"
- // and falling back to llvm-gcc we want to use ".gch" instead.
- std::string OutputFile(Output.getFilename());
- size_t loc = OutputFile.rfind(".pth");
- if (loc != std::string::npos)
- OutputFile.replace(loc, 4, ".gch");
- const char *Tmp = C.getArgs().MakeArgString("--output-pch="+OutputFile);
- CmdArgs.push_back(Tmp);
- }
-
- RemoveCC1UnsupportedArgs(CmdArgs);
-
- const char *CC1Name = getCC1Name(Inputs[0].getType());
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
-
void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -4613,6 +4480,9 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX))
CmdArgs.push_back("-ObjC");
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export_dynamic");
+
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -4710,11 +4580,11 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
SanitizerArgs Sanitize(getToolChain().getDriver(), Args);
- // If we're building a dynamic lib with -fsanitize=address, or
- // -fsanitize=undefined, unresolved symbols may appear. Mark all
+ // If we're building a dynamic lib with -fsanitize=address,
+ // unresolved symbols may appear. Mark all
// of them as dynamic_lookup. Linking executables is handled in
// lib/Driver/ToolChains.cpp.
- if (Sanitize.needsAsanRt() || Sanitize.needsUbsanRt()) {
+ if (Sanitize.needsAsanRt()) {
if (Args.hasArg(options::OPT_dynamiclib) ||
Args.hasArg(options::OPT_bundle)) {
CmdArgs.push_back("-undefined");
@@ -4828,10 +4698,10 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
}
void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
CmdArgs.push_back("--verify");
CmdArgs.push_back("--debug-info");
@@ -5125,6 +4995,14 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
if ((!Args.hasArg(options::OPT_nostdlib)) &&
(!Args.hasArg(options::OPT_shared))) {
CmdArgs.push_back("-e");
@@ -5179,6 +5057,10 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
@@ -5395,14 +5277,8 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
- // Convert ABI name to the GNU tools acceptable variant.
- if (ABIName == "o32")
- ABIName = "32";
- else if (ABIName == "n64")
- ABIName = "64";
-
CmdArgs.push_back("-mabi");
- CmdArgs.push_back(ABIName.data());
+ CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mips64)
@@ -5421,6 +5297,18 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
LastPICArg->getOption().matches(options::OPT_fpie))) {
CmdArgs.push_back("-KPIC");
}
+ } else if (getToolChain().getArch() == llvm::Triple::arm ||
+ getToolChain().getArch() == llvm::Triple::thumb) {
+ CmdArgs.push_back("-mfpu=softvfp");
+ switch(getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::EABI:
+ CmdArgs.push_back("-meabi=5");
+ break;
+
+ default:
+ CmdArgs.push_back("-matpcs");
+ }
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5765,11 +5653,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
-void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
// Add --32/--64 to make sure we get the format we want.
@@ -5809,14 +5697,8 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
- // Convert ABI name to the GNU tools acceptable variant.
- if (ABIName == "o32")
- ABIName = "32";
- else if (ABIName == "n64")
- ABIName = "64";
-
CmdArgs.push_back("-mabi");
- CmdArgs.push_back(ABIName.data());
+ CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mips64)
@@ -5857,12 +5739,12 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
static void AddLibgcc(llvm::Triple Triple, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
- bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_static_libgcc);
+ bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
+ Args.hasArg(options::OPT_static);
if (!D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
- if (StaticLibgcc) {
+ if (StaticLibgcc || isAndroid) {
if (D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
} else {
@@ -5877,6 +5759,14 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
CmdArgs.push_back("-lgcc_eh");
else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
+
+ // According to Android ABI, we have to link with libdl if we are
+ // linking with non-static libgcc.
+ //
+ // NOTE: This fixes a link error on Android MIPS as well. The non-static
+ // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl.
+ if (isAndroid && !StaticLibgcc)
+ CmdArgs.push_back("-ldl");
}
static bool hasMipsN32ABIArg(const ArgList &Args) {
@@ -5884,11 +5774,11 @@ static bool hasMipsN32ABIArg(const ArgList &Args) {
return A && (A->getValue() == StringRef("n32"));
}
-void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
const toolchains::Linux& ToolChain =
static_cast<const toolchains::Linux&>(getToolChain());
const Driver &D = ToolChain.getDriver();
@@ -5908,7 +5798,7 @@ void linuxtools::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 (Args.hasArg(options::OPT_pie) && !Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-pie");
if (Args.hasArg(options::OPT_rdynamic))
@@ -5929,6 +5819,8 @@ void linuxtools::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)
+ CmdArgs.push_back("aarch64linux");
else if (ToolChain.getArch() == llvm::Triple::arm
|| ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("armelf_linux_eabi");
@@ -5977,6 +5869,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("/system/bin/linker");
else if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("/lib/ld-linux.so.2");
+ else if (ToolChain.getArch() == llvm::Triple::aarch64)
+ CmdArgs.push_back("/lib/ld-linux-aarch64.so.1");
else if (ToolChain.getArch() == llvm::Triple::arm ||
ToolChain.getArch() == llvm::Triple::thumb) {
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
@@ -6051,8 +5945,27 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
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 architecture-specific flags for selecting CPU variants.
+ if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::x86_64)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
+ getX86TargetCPU(Args, ToolChain.getTriple())));
+ else if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::thumb)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
+ getARMTargetCPU(Args, ToolChain.getTriple())));
+
+ // FIXME: Factor out logic for MIPS, PPC, and other targets to support this
+ // as well.
}
+
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
@@ -6060,9 +5973,17 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
SanitizerArgs Sanitize(D, Args);
- // Call this before we add the C++ ABI library.
+ // Call these before we add the C++ ABI library.
if (Sanitize.needsUbsanRt())
- addUbsanRTLinux(getToolChain(), Args, CmdArgs);
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX,
+ Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
+ Sanitize.needsMsanRt());
+ if (Sanitize.needsAsanRt())
+ addAsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsTsanRt())
+ addTsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsMsanRt())
+ addMsanRTLinux(getToolChain(), Args, CmdArgs);
if (D.CCCIsCXX &&
!Args.hasArg(options::OPT_nostdlib) &&
@@ -6077,21 +5998,24 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- // Call this before we add the C run-time.
- if (Sanitize.needsAsanRt())
- addAsanRTLinux(getToolChain(), Args, CmdArgs);
- if (Sanitize.needsTsanRt())
- addTsanRTLinux(getToolChain(), Args, CmdArgs);
-
if (!Args.hasArg(options::OPT_nostdlib)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--start-group");
+ bool OpenMP = Args.hasArg(options::OPT_fopenmp);
+ if (OpenMP) {
+ 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.
+ CmdArgs.push_back("-lrt");
+ }
+
AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args);
if (Args.hasArg(options::OPT_pthread) ||
- Args.hasArg(options::OPT_pthreads))
+ Args.hasArg(options::OPT_pthreads) || OpenMP)
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
@@ -6193,7 +6117,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lCompilerRT-Generic");
CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib");
CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
}
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 5898c660a499..d6471716e660 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -13,7 +13,6 @@
#include "clang/Driver/Tool.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
-
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
@@ -31,7 +30,17 @@ namespace tools {
/// \brief Clang compiler tool.
class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
+ public:
+ static const char *getBaseInputName(const ArgList &Args,
+ const InputInfoList &Inputs);
+ static const char *getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Inputs);
+ static const char *getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs);
+
+ private:
void AddPreprocessingOptions(Compilation &C,
+ const JobAction &JA,
const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -42,6 +51,7 @@ namespace tools {
bool KernelOrKext) const;
void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddR600TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const;
@@ -68,6 +78,7 @@ namespace tools {
/// \brief Clang integrated assembler tool.
class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
ClangAs(const ToolChain &TC) : Tool("clang::as",
"clang integrated assembler", TC) {}
@@ -218,63 +229,6 @@ namespace darwin {
const ToolChain &TC) : Tool(Name, ShortName, TC) {}
};
- class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool {
- virtual void anchor();
- public:
- static const char *getBaseInputName(const ArgList &Args,
- const InputInfoList &Input);
- static const char *getBaseInputStem(const ArgList &Args,
- const InputInfoList &Input);
- static const char *getDependencyFileName(const ArgList &Args,
- const InputInfoList &Inputs);
-
- protected:
- const char *getCC1Name(types::ID Type) const;
-
- void AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const;
- void RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const;
- void AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const;
- void AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const;
- void AddCPPUniqueOptionsArgs(const ArgList &Args,
- ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const;
- void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
-
- public:
- CC1(const char *Name, const char *ShortName,
- const ToolChain &TC) : DarwinTool(Name, ShortName, TC) {}
-
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedCPP() const { return true; }
- };
-
- class LLVM_LIBRARY_VISIBILITY Preprocess : public CC1 {
- public:
- Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess",
- "gcc preprocessor", TC) {}
-
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
- const char *LinkingOutput) const;
- };
-
- class LLVM_LIBRARY_VISIBILITY Compile : public CC1 {
- public:
- Compile(const ToolChain &TC) : CC1("darwin::Compile", "gcc frontend", TC) {}
-
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
- const char *LinkingOutput) const;
- };
-
class LLVM_LIBRARY_VISIBILITY Assemble : public DarwinTool {
public:
Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble",
@@ -326,6 +280,7 @@ namespace darwin {
"dsymutil", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isDsymutilJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -337,15 +292,15 @@ namespace darwin {
class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool {
public:
VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug",
- "dwarfdump", TC) {}
+ "dwarfdump", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
- const char *LinkingOutput) const;
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
};
}
@@ -473,12 +428,11 @@ namespace netbsd {
};
} // end namespace netbsd
- /// linux -- Directly call GNU Binutils assembler and linker
-namespace linuxtools {
+ /// Directly call GNU Binutils' assembler and linker.
+namespace gnutools {
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("linux::Assemble", "assembler",
- TC) {}
+ Assemble(const ToolChain &TC) : Tool("GNU::Assemble", "assembler", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
@@ -490,7 +444,7 @@ namespace linuxtools {
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("linux::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
virtual bool isLinkJob() const { return true; }
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 862025ed9a1a..7d22596a17ef 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -8,10 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Types.h"
-
#include "llvm/ADT/StringSwitch.h"
-#include <string.h>
#include <cassert>
+#include <string.h>
using namespace clang::driver;
using namespace clang::driver::types;
@@ -88,7 +87,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
- case TY_AST:
+ case TY_AST: case TY_ModuleFile:
case TY_LLVM_IR: case TY_LLVM_BC:
return true;
}
@@ -113,7 +112,7 @@ bool types::isCXX(ID Id) {
return false;
case TY_CXX: case TY_PP_CXX:
- case TY_ObjCXX: case TY_PP_ObjCXX:
+ case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
case TY_CUDA:
@@ -165,16 +164,15 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("F90", TY_Fortran)
.Case("F95", TY_Fortran)
.Case("mii", TY_PP_ObjCXX)
+ .Case("pcm", TY_ModuleFile)
.Default(TY_INVALID);
}
types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
- unsigned N = strlen(Name);
-
for (unsigned i=0; i<numTypes; ++i) {
types::ID Id = (types::ID) (i + 1);
if (canTypeBeUserSpecified(Id) &&
- memcmp(Name, getInfo(Id).Name, N + 1) == 0)
+ strcmp(Name, getInfo(Id).Name) == 0)
return Id;
}
@@ -182,54 +180,36 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
}
// FIXME: Why don't we just put this list in the defs file, eh.
-
-unsigned types::getNumCompilationPhases(ID Id) {
- if (Id == TY_Object)
- return 1;
-
- unsigned N = 0;
- if (getPreprocessedType(Id) != TY_INVALID)
- N += 1;
-
- if (onlyAssembleType(Id))
- return N + 2; // assemble, link
- if (onlyPrecompileType(Id))
- return N + 1; // precompile
-
- return N + 3; // compile, assemble, link
-}
-
-phases::ID types::getCompilationPhase(ID Id, unsigned N) {
- assert(N < getNumCompilationPhases(Id) && "Invalid index.");
-
- if (Id == TY_Object)
- return phases::Link;
-
- if (getPreprocessedType(Id) != TY_INVALID) {
- if (N == 0)
- return phases::Preprocess;
- --N;
+void types::getCompilationPhases(
+ ID Id,
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &P) {
+ if (Id != TY_Object) {
+ if (getPreprocessedType(Id) != TY_INVALID) {
+ P.push_back(phases::Preprocess);
+ }
+
+ if (onlyPrecompileType(Id)) {
+ P.push_back(phases::Precompile);
+ } else {
+ if (!onlyAssembleType(Id)) {
+ P.push_back(phases::Compile);
+ }
+ P.push_back(phases::Assemble);
+ }
}
-
- if (onlyAssembleType(Id))
- return N == 0 ? phases::Assemble : phases::Link;
-
- if (onlyPrecompileType(Id))
- return phases::Precompile;
-
- if (N == 0)
- return phases::Compile;
- if (N == 1)
- return phases::Assemble;
-
- return phases::Link;
+ if (!onlyPrecompileType(Id)) {
+ P.push_back(phases::Link);
+ }
+ assert(0 < P.size() && "Not enough phases in list");
+ assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list");
+ return;
}
ID types::lookupCXXTypeForCType(ID Id) {
switch (Id) {
default:
return Id;
-
+
case types::TY_C:
return types::TY_CXX;
case types::TY_PP_C:
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index de2d5352b716..dac7e77d608e 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -8,13 +8,14 @@
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
-
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "clang/Basic/Version.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
@@ -31,49 +32,20 @@ using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
-Windows::Windows(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple) {
+Windows::Windows(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
}
-Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- case Action::LipoJobClass:
- case Action::DsymutilJobClass:
- case Action::VerifyJobClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- case Action::PrecompileJobClass:
- case Action::AnalyzeJobClass:
- case Action::MigrateJobClass:
- case Action::CompileJobClass:
- T = new tools::Clang(*this); break;
- case Action::AssembleJobClass:
- if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO)
- T = new tools::darwin::Assemble(*this);
- else
- T = new tools::ClangAs(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::visualstudio::Link(*this); break;
- }
- }
+Tool *Windows::buildLinker() const {
+ return new tools::visualstudio::Link(*this);
+}
- return *T;
+Tool *Windows::buildAssembler() const {
+ if (getTriple().getEnvironment() == llvm::Triple::MachO)
+ return new tools::darwin::Assemble(*this);
+ getDriver().Diag(clang::diag::err_no_external_windows_assembler);
+ return NULL;
}
bool Windows::IsIntegratedAssemblerDefault() const {
@@ -158,12 +130,12 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
const char *sp = keyName;
- while (*sp && !isdigit(*sp))
+ while (*sp && !isDigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
- while (*ep && (isdigit(*ep) || (*ep == '.')))
+ while (*ep && (isDigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
index 41c72e42e6a5..0b4ea3e0cdad 100644
--- a/lib/Edit/Commit.cpp
+++ b/lib/Edit/Commit.cpp
@@ -8,10 +8,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Edit/Commit.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Edit/EditedSource.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
using namespace clang;
using namespace edit;
@@ -37,7 +37,7 @@ CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
Commit::Commit(EditedSource &Editor)
: SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
- PPRec(Editor.getPreprocessingRecord()),
+ PPRec(Editor.getPPCondDirectiveRecord()),
Editor(&Editor), IsCommitable(true) { }
bool Commit::insert(SourceLocation loc, StringRef text,
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index b2a16635d050..dd99ca928019 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -8,10 +8,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Edit/EditedSource.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
@@ -23,7 +24,7 @@ void EditsReceiver::remove(CharSourceRange range) {
}
StringRef EditedSource::copyString(const Twine &twine) {
- llvm::SmallString<128> Data;
+ SmallString<128> Data;
return copyString(twine.toStringRef(Data));
}
@@ -88,7 +89,7 @@ bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
if (Len == 0)
return true;
- llvm::SmallString<128> StrVec;
+ SmallString<128> StrVec;
FileOffset BeginOffs = InsertFromRangeOffs;
FileOffset EndOffs = BeginOffs.getWithOffset(Len);
FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
@@ -239,13 +240,78 @@ bool EditedSource::commit(const Commit &commit) {
return true;
}
+// \brief Returns true if it is ok to make the two given characters adjacent.
+static bool canBeJoined(char left, char right, const LangOptions &LangOpts) {
+ // FIXME: Should use TokenConcatenation to make sure we don't allow stuff like
+ // making two '<' adjacent.
+ return !(Lexer::isIdentifierBodyChar(left, LangOpts) &&
+ Lexer::isIdentifierBodyChar(right, LangOpts));
+}
+
+/// \brief Returns true if it is ok to eliminate the trailing whitespace between
+/// the given characters.
+static bool canRemoveWhitespace(char left, char beforeWSpace, char right,
+ const LangOptions &LangOpts) {
+ if (!canBeJoined(left, right, LangOpts))
+ return false;
+ if (isWhitespace(left) || isWhitespace(right))
+ return true;
+ if (canBeJoined(beforeWSpace, right, LangOpts))
+ return false; // the whitespace was intentional, keep it.
+ return true;
+}
+
+/// \brief Check the range that we are going to remove and:
+/// -Remove any trailing whitespace if possible.
+/// -Insert a space if removing the range is going to mess up the source tokens.
+static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
+ SourceLocation Loc, FileOffset offs,
+ unsigned &len, StringRef &text) {
+ assert(len && text.empty());
+ SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
+ if (BeginTokLoc != Loc)
+ return; // the range is not at the beginning of a token, keep the range.
+
+ bool Invalid = false;
+ StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid);
+ if (Invalid)
+ return;
+
+ unsigned begin = offs.getOffset();
+ unsigned end = begin + len;
+
+ // FIXME: Remove newline.
+
+ if (begin == 0) {
+ if (buffer[end] == ' ')
+ ++len;
+ return;
+ }
+
+ if (buffer[end] == ' ') {
+ if (canRemoveWhitespace(/*left=*/buffer[begin-1],
+ /*beforeWSpace=*/buffer[end-1],
+ /*right=*/buffer[end+1],
+ LangOpts))
+ ++len;
+ return;
+ }
+
+ if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts))
+ text = " ";
+}
+
static void applyRewrite(EditsReceiver &receiver,
StringRef text, FileOffset offs, unsigned len,
- const SourceManager &SM) {
+ const SourceManager &SM, const LangOptions &LangOpts) {
assert(!offs.getFID().isInvalid());
SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
Loc = Loc.getLocWithOffset(offs.getOffset());
assert(Loc.isFileID());
+
+ if (text.empty())
+ adjustRemoval(SM, LangOpts, Loc, offs, len, text);
+
CharSourceRange range = CharSourceRange::getCharRange(Loc,
Loc.getLocWithOffset(len));
@@ -262,7 +328,7 @@ static void applyRewrite(EditsReceiver &receiver,
}
void EditedSource::applyRewrites(EditsReceiver &receiver) {
- llvm::SmallString<128> StrVec;
+ SmallString<128> StrVec;
FileOffset CurOffs, CurEnd;
unsigned CurLen;
@@ -288,14 +354,14 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) {
continue;
}
- applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+ applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
CurOffs = offs;
StrVec = act.Text;
CurLen = act.RemoveLen;
CurEnd = CurOffs.getWithOffset(CurLen);
}
- applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+ applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
}
void EditedSource::clearRewrites() {
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index de96fee41618..f4206fbd8f4f 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -12,12 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Edit/Rewriters.h"
-#include "clang/Edit/Commit.h"
-#include "clang/Lex/Lexer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/NSAPI.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Lex/Lexer.h"
using namespace clang;
using namespace edit;
@@ -295,9 +296,8 @@ bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
if (!Method)
return false;
- const ObjCInterfaceDecl *
- IFace = NS.getASTContext().getObjContainingInterface(
- const_cast<ObjCMethodDecl *>(Method));
+ const ObjCInterfaceDecl *IFace =
+ NS.getASTContext().getObjContainingInterface(Method);
if (!IFace)
return false;
Selector Sel = Msg->getSelector();
@@ -325,7 +325,8 @@ bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
//===----------------------------------------------------------------------===//
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap);
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
@@ -336,13 +337,14 @@ static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap) {
IdentifierInfo *II = 0;
if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
return false;
if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
- return rewriteToArrayLiteral(Msg, NS, commit);
+ return rewriteToArrayLiteral(Msg, NS, commit, PMap);
if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
return rewriteToDictionaryLiteral(Msg, NS, commit);
if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
@@ -353,6 +355,19 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
return false;
}
+/// \brief Returns true if the immediate message arguments of \c Msg should not
+/// be rewritten because it will interfere with the rewrite of the parent
+/// message expression. e.g.
+/// \code
+/// [NSDictionary dictionaryWithObjects:
+/// [NSArray arrayWithObjects:@"1", @"2", nil]
+/// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
+/// \endcode
+/// It will return true for this because we are going to rewrite this directly
+/// to a dictionary literal without any array literals.
+static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
+ const NSAPI &NS);
+
//===----------------------------------------------------------------------===//
// rewriteToArrayLiteral.
//===----------------------------------------------------------------------===//
@@ -361,7 +376,15 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
static void objectifyExpr(const Expr *E, Commit &commit);
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap) {
+ if (PMap) {
+ const ObjCMessageExpr *ParentMsg =
+ dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
+ if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
+ return false;
+ }
+
Selector Sel = Msg->getSelector();
SourceRange MsgRange = Msg->getSourceRange();
@@ -411,6 +434,59 @@ static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
// rewriteToDictionaryLiteral.
//===----------------------------------------------------------------------===//
+/// \brief If \c Msg is an NSArray creation message or literal, this gets the
+/// objects that were used to create it.
+/// \returns true if it is an NSArray and we got objects, or false otherwise.
+static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
+ SmallVectorImpl<const Expr *> &Objs) {
+ if (!E)
+ return false;
+
+ E = E->IgnoreParenCasts();
+ if (!E)
+ return false;
+
+ if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
+ IdentifierInfo *Cls = 0;
+ if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
+ return false;
+
+ if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
+ return false;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
+ return true; // empty array.
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+ Objs.push_back(Msg->getArg(0));
+ return true;
+ }
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
+ Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
+ if (Msg->getNumArgs() == 0)
+ return false;
+ const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
+ if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+ return false;
+
+ for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
+ Objs.push_back(Msg->getArg(i));
+ return true;
+ }
+
+ } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
+ for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
+ Objs.push_back(ArrLit->getElement(i));
+ return true;
+ }
+
+ return false;
+}
+
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit) {
Selector Sel = Msg->getSelector();
@@ -481,6 +557,83 @@ static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
return true;
}
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ SmallVector<const Expr *, 8> Vals;
+ if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
+ return false;
+
+ SmallVector<const Expr *, 8> Keys;
+ if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
+ return false;
+
+ if (Vals.size() != Keys.size())
+ return false;
+
+ if (Vals.empty()) {
+ commit.replace(MsgRange, "@{}");
+ return true;
+ }
+
+ for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
+ objectifyExpr(Vals[i], commit);
+ objectifyExpr(Keys[i], commit);
+
+ SourceRange ValRange = Vals[i]->getSourceRange();
+ SourceRange KeyRange = Keys[i]->getSourceRange();
+ // Insert value after key.
+ commit.insertAfterToken(KeyRange.getEnd(), ": ");
+ commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
+ }
+ // Range of arguments up until and including the last key.
+ // The first value is cut off, the value will move after the key.
+ SourceRange ArgRange(Keys.front()->getLocStart(),
+ Keys.back()->getLocEnd());
+ commit.insertWrap("@{", ArgRange, "}");
+ commit.replaceWithInner(MsgRange, ArgRange);
+ return true;
+ }
+
+ return false;
+}
+
+static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
+ const NSAPI &NS) {
+ if (!Msg)
+ return false;
+
+ IdentifierInfo *II = 0;
+ if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
+ return false;
+
+ if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
+ return false;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ SmallVector<const Expr *, 8> Vals;
+ if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
+ return false;
+
+ SmallVector<const Expr *, 8> Keys;
+ if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
+ return false;
+
+ if (Vals.size() != Keys.size())
+ return false;
+
+ return true;
+ }
+
return false;
}
@@ -540,7 +693,7 @@ static bool getLiteralInfo(SourceRange literalRange,
if (text.empty())
return false;
- llvm::Optional<bool> UpperU, UpperL;
+ Optional<bool> UpperU, UpperL;
bool UpperF = false;
struct Suff {
@@ -624,7 +777,7 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
- llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+ Optional<NSAPI::NSNumberLiteralMethodKind>
MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
if (!MKOpt)
return false;
@@ -828,7 +981,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
- llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+ Optional<NSAPI::NSNumberLiteralMethodKind>
MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
if (!MKOpt)
return false;
@@ -921,6 +1074,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_NonAtomicToAtomic:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
return false;
}
}
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
new file mode 100644
index 000000000000..d8630eeeead3
--- /dev/null
+++ b/lib/Format/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangFormat
+ TokenAnnotator.cpp
+ UnwrappedLineParser.cpp
+ Format.cpp
+ )
+
+add_dependencies(clangFormat
+ ClangAttrClasses
+ ClangAttrList
+ ClangDeclNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangFormat
+ clangBasic
+ clangFrontend
+ clangAST
+ clangASTMatchers
+ clangRewriteCore
+ clangRewriteFrontend
+ clangTooling
+ )
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
new file mode 100644
index 000000000000..101b16f1a18c
--- /dev/null
+++ b/lib/Format/Format.cpp
@@ -0,0 +1,1763 @@
+//===--- Format.cpp - Format C++ code -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements functions declared in Format.h. This will be
+/// split into separate files as we go.
+///
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-formatter"
+
+#include "TokenAnnotator.h"
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include <queue>
+#include <string>
+
+namespace clang {
+namespace format {
+
+FormatStyle getLLVMStyle() {
+ FormatStyle LLVMStyle;
+ LLVMStyle.ColumnLimit = 80;
+ LLVMStyle.MaxEmptyLinesToKeep = 1;
+ LLVMStyle.PointerBindsToType = false;
+ LLVMStyle.DerivePointerBinding = false;
+ LLVMStyle.AccessModifierOffset = -2;
+ LLVMStyle.Standard = FormatStyle::LS_Cpp03;
+ LLVMStyle.IndentCaseLabels = false;
+ LLVMStyle.SpacesBeforeTrailingComments = 1;
+ LLVMStyle.BinPackParameters = true;
+ LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+ LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
+ LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
+ LLVMStyle.ObjCSpaceBeforeProtocolList = true;
+ LLVMStyle.PenaltyExcessCharacter = 1000000;
+ LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 5;
+ return LLVMStyle;
+}
+
+FormatStyle getGoogleStyle() {
+ FormatStyle GoogleStyle;
+ GoogleStyle.ColumnLimit = 80;
+ GoogleStyle.MaxEmptyLinesToKeep = 1;
+ GoogleStyle.PointerBindsToType = true;
+ GoogleStyle.DerivePointerBinding = true;
+ GoogleStyle.AccessModifierOffset = -1;
+ GoogleStyle.Standard = FormatStyle::LS_Auto;
+ GoogleStyle.IndentCaseLabels = true;
+ GoogleStyle.SpacesBeforeTrailingComments = 2;
+ GoogleStyle.BinPackParameters = true;
+ GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+ GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
+ GoogleStyle.ObjCSpaceBeforeProtocolList = false;
+ GoogleStyle.PenaltyExcessCharacter = 1000000;
+ GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 100;
+ return GoogleStyle;
+}
+
+FormatStyle getChromiumStyle() {
+ FormatStyle ChromiumStyle = getGoogleStyle();
+ ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ ChromiumStyle.BinPackParameters = false;
+ ChromiumStyle.Standard = FormatStyle::LS_Cpp03;
+ ChromiumStyle.DerivePointerBinding = false;
+ return ChromiumStyle;
+}
+
+static bool isTrailingComment(const AnnotatedToken &Tok) {
+ return Tok.is(tok::comment) &&
+ (Tok.Children.empty() || Tok.Children[0].MustBreakBefore);
+}
+
+static bool isComparison(const AnnotatedToken &Tok) {
+ prec::Level Precedence = getPrecedence(Tok);
+ return Tok.Type == TT_BinaryOperator &&
+ (Precedence == prec::Equality || Precedence == prec::Relational);
+}
+
+// Returns the length of everything up to the first possible line break after
+// the ), ], } or > matching \c Tok.
+static unsigned getLengthToMatchingParen(const AnnotatedToken &Tok) {
+ if (Tok.MatchingParen == NULL)
+ return 0;
+ AnnotatedToken *End = Tok.MatchingParen;
+ while (!End->Children.empty() && !End->Children[0].CanBreakBefore) {
+ End = &End->Children[0];
+ }
+ return End->TotalLength - Tok.TotalLength + 1;
+}
+
+static size_t
+calculateColumnLimit(const FormatStyle &Style, bool InPPDirective) {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (InPPDirective ? 2 : 0);
+}
+
+/// \brief Manages the whitespaces around tokens and their replacements.
+///
+/// This includes special handling for certain constructs, e.g. the alignment of
+/// trailing line comments.
+class WhitespaceManager {
+public:
+ WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style)
+ : SourceMgr(SourceMgr), Style(Style) {}
+
+ /// \brief Replaces the whitespace in front of \p Tok. Only call once for
+ /// each \c AnnotatedToken.
+ void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
+ unsigned Spaces, unsigned WhitespaceStartColumn) {
+ // 2+ newlines mean an empty line separating logic scopes.
+ if (NewLines >= 2)
+ alignComments();
+
+ SourceLocation TokenLoc = Tok.FormatTok.Tok.getLocation();
+ bool LineExceedsColumnLimit = Spaces + WhitespaceStartColumn +
+ Tok.FormatTok.TokenLength > Style.ColumnLimit;
+
+ // Align line comments if they are trailing or if they continue other
+ // trailing comments.
+ if (isTrailingComment(Tok)) {
+ // Remove the comment's trailing whitespace.
+ if (Tok.FormatTok.Tok.getLength() != Tok.FormatTok.TokenLength)
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, TokenLoc.getLocWithOffset(Tok.FormatTok.TokenLength),
+ Tok.FormatTok.Tok.getLength() - Tok.FormatTok.TokenLength, ""));
+
+ // Align comment with other comments.
+ if ((Tok.Parent != NULL || !Comments.empty()) &&
+ !LineExceedsColumnLimit) {
+ StoredComment Comment;
+ Comment.Tok = Tok.FormatTok;
+ Comment.Spaces = Spaces;
+ Comment.NewLines = NewLines;
+ Comment.MinColumn =
+ NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces;
+ Comment.MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength;
+ Comment.Untouchable = false;
+ Comments.push_back(Comment);
+ return;
+ }
+ }
+
+ // If this line does not have a trailing comment, align the stored comments.
+ if (Tok.Children.empty() && !isTrailingComment(Tok))
+ alignComments();
+
+ if (Tok.Type == TT_BlockComment) {
+ indentBlockComment(Tok, Spaces, WhitespaceStartColumn, NewLines, false);
+ } else if (Tok.Type == TT_LineComment && LineExceedsColumnLimit) {
+ StringRef Line(SourceMgr.getCharacterData(TokenLoc),
+ Tok.FormatTok.TokenLength);
+ int StartColumn = Spaces + (NewLines == 0 ? WhitespaceStartColumn : 0);
+ StringRef Prefix = getLineCommentPrefix(Line);
+ std::string NewPrefix = std::string(StartColumn, ' ') + Prefix.str();
+ splitLineInComment(Tok.FormatTok, Line.substr(Prefix.size()),
+ StartColumn + Prefix.size(), NewPrefix,
+ /*InPPDirective=*/ false,
+ /*CommentHasMoreLines=*/ false);
+ }
+
+ storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces));
+ }
+
+ /// \brief Like \c replaceWhitespace, but additionally adds right-aligned
+ /// backslashes to escape newlines inside a preprocessor directive.
+ ///
+ /// This function and \c replaceWhitespace have the same behavior if
+ /// \c Newlines == 0.
+ void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
+ unsigned Spaces, unsigned WhitespaceStartColumn) {
+ if (Tok.Type == TT_BlockComment)
+ indentBlockComment(Tok, Spaces, WhitespaceStartColumn, NewLines, true);
+
+ storeReplacement(Tok.FormatTok,
+ getNewLineText(NewLines, Spaces, WhitespaceStartColumn));
+ }
+
+ /// \brief Inserts a line break into the middle of a token.
+ ///
+ /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line
+ /// break and \p Postfix before the rest of the token starts in the next line.
+ ///
+ /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are
+ /// used to generate the correct line break.
+ void breakToken(const FormatToken &Tok, unsigned Offset,
+ unsigned ReplaceChars, StringRef Prefix, StringRef Postfix,
+ bool InPPDirective, unsigned Spaces,
+ unsigned WhitespaceStartColumn) {
+ std::string NewLineText;
+ if (!InPPDirective)
+ NewLineText = getNewLineText(1, Spaces);
+ else
+ NewLineText = getNewLineText(1, Spaces, WhitespaceStartColumn);
+ std::string ReplacementText = (Prefix + NewLineText + Postfix).str();
+ SourceLocation Location = Tok.Tok.getLocation().getLocWithOffset(Offset);
+ Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars,
+ ReplacementText));
+ }
+
+ /// \brief Returns all the \c Replacements created during formatting.
+ const tooling::Replacements &generateReplacements() {
+ alignComments();
+ return Replaces;
+ }
+
+ void addUntouchableComment(unsigned Column) {
+ StoredComment Comment;
+ Comment.MinColumn = Column;
+ Comment.MaxColumn = Column;
+ Comment.Untouchable = true;
+ Comments.push_back(Comment);
+ }
+
+private:
+ static StringRef getLineCommentPrefix(StringRef Comment) {
+ const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" };
+ for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i)
+ if (Comment.startswith(KnownPrefixes[i]))
+ return KnownPrefixes[i];
+ return "";
+ }
+
+ /// \brief Finds a common prefix of lines of a block comment to properly
+ /// indent (and possibly decorate with '*'s) added lines.
+ ///
+ /// The first line is ignored (it's special and starts with /*). The number of
+ /// lines should be more than one.
+ static StringRef findCommentLinesPrefix(ArrayRef<StringRef> Lines,
+ const char *PrefixChars = " *") {
+ assert(Lines.size() > 1);
+ StringRef Prefix(Lines[1].data(), Lines[1].find_first_not_of(PrefixChars));
+ for (size_t i = 2; i < Lines.size(); ++i) {
+ for (size_t j = 0; j < Prefix.size() && j < Lines[i].size(); ++j) {
+ if (Prefix[j] != Lines[i][j]) {
+ Prefix = Prefix.substr(0, j);
+ break;
+ }
+ }
+ }
+ return Prefix;
+ }
+
+ /// \brief Splits one line in a line or block comment, if it doesn't fit to
+ /// provided column limit. Removes trailing whitespace in each line.
+ ///
+ /// \param Line points to the line contents without leading // or /*.
+ ///
+ /// \param StartColumn is the column where the first character of Line will be
+ /// located after formatting.
+ ///
+ /// \param LinePrefix is inserted after each line break.
+ ///
+ /// When \param InPPDirective is true, each line break will be preceded by a
+ /// backslash in the last column to make line breaks inside the comment
+ /// visually consistent with line breaks outside the comment. This only makes
+ /// sense for block comments.
+ ///
+ /// When \param CommentHasMoreLines is false, no line breaks/trailing
+ /// backslashes will be inserted after it.
+ void splitLineInComment(const FormatToken &Tok, StringRef Line,
+ size_t StartColumn, StringRef LinePrefix,
+ bool InPPDirective, bool CommentHasMoreLines,
+ const char *WhiteSpaceChars = " ") {
+ size_t ColumnLimit = calculateColumnLimit(Style, InPPDirective);
+ const char *TokenStart = SourceMgr.getCharacterData(Tok.Tok.getLocation());
+
+ StringRef TrimmedLine = Line.rtrim();
+ int TrailingSpaceLength = Line.size() - TrimmedLine.size();
+
+ // Don't touch leading whitespace.
+ Line = TrimmedLine.ltrim();
+ StartColumn += TrimmedLine.size() - Line.size();
+
+ while (Line.size() + StartColumn > ColumnLimit) {
+ // Try to break at the last whitespace before the column limit.
+ size_t SpacePos =
+ Line.find_last_of(WhiteSpaceChars, ColumnLimit - StartColumn + 1);
+ if (SpacePos == StringRef::npos) {
+ // Try to find any whitespace in the line.
+ SpacePos = Line.find_first_of(WhiteSpaceChars);
+ if (SpacePos == StringRef::npos) // No whitespace found, give up.
+ break;
+ }
+
+ StringRef NextCut = Line.substr(0, SpacePos).rtrim();
+ StringRef RemainingLine = Line.substr(SpacePos).ltrim();
+ if (RemainingLine.empty())
+ break;
+
+ if (RemainingLine == "*/" && LinePrefix.endswith("* "))
+ LinePrefix = LinePrefix.substr(0, LinePrefix.size() - 2);
+
+ Line = RemainingLine;
+
+ size_t ReplaceChars = Line.begin() - NextCut.end();
+ breakToken(Tok, NextCut.end() - TokenStart, ReplaceChars, "", LinePrefix,
+ InPPDirective, 0, NextCut.size() + StartColumn);
+ StartColumn = LinePrefix.size();
+ }
+
+ if (TrailingSpaceLength > 0 || (InPPDirective && CommentHasMoreLines)) {
+ // Remove trailing whitespace/insert backslash. + 1 is for \n
+ breakToken(Tok, Line.end() - TokenStart, TrailingSpaceLength + 1, "", "",
+ InPPDirective, 0, Line.size() + StartColumn);
+ }
+ }
+
+ /// \brief Changes indentation of all lines in a block comment by Indent,
+ /// removes trailing whitespace from each line, splits lines that end up
+ /// exceeding the column limit.
+ void indentBlockComment(const AnnotatedToken &Tok, int Indent,
+ int WhitespaceStartColumn, int NewLines,
+ bool InPPDirective) {
+ assert(Tok.Type == TT_BlockComment);
+ int StartColumn = Indent + (NewLines == 0 ? WhitespaceStartColumn : 0);
+ const SourceLocation TokenLoc = Tok.FormatTok.Tok.getLocation();
+ const int CurrentIndent = SourceMgr.getSpellingColumnNumber(TokenLoc) - 1;
+ const int IndentDelta = Indent - CurrentIndent;
+ const StringRef Text(SourceMgr.getCharacterData(TokenLoc),
+ Tok.FormatTok.TokenLength);
+ assert(Text.startswith("/*") && Text.endswith("*/"));
+
+ SmallVector<StringRef, 16> Lines;
+ Text.split(Lines, "\n");
+
+ if (IndentDelta > 0) {
+ std::string WhiteSpace(IndentDelta, ' ');
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()),
+ 0, WhiteSpace));
+ }
+ } else if (IndentDelta < 0) {
+ std::string WhiteSpace(-IndentDelta, ' ');
+ // Check that the line is indented enough.
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ if (!Lines[i].startswith(WhiteSpace))
+ return;
+ }
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()),
+ -IndentDelta, ""));
+ }
+ }
+
+ // Split long lines in comments.
+ size_t OldPrefixSize = 0;
+ std::string NewPrefix;
+ if (Lines.size() > 1) {
+ StringRef CurrentPrefix = findCommentLinesPrefix(Lines);
+ OldPrefixSize = CurrentPrefix.size();
+ NewPrefix = (IndentDelta < 0)
+ ? CurrentPrefix.substr(-IndentDelta).str()
+ : std::string(IndentDelta, ' ') + CurrentPrefix.str();
+ if (CurrentPrefix.endswith("*")) {
+ NewPrefix += " ";
+ ++OldPrefixSize;
+ }
+ } else if (Tok.Parent == 0) {
+ NewPrefix = std::string(StartColumn, ' ') + " * ";
+ }
+
+ StartColumn += 2;
+ for (size_t i = 0; i < Lines.size(); ++i) {
+ StringRef Line = Lines[i].substr(i == 0 ? 2 : OldPrefixSize);
+ splitLineInComment(Tok.FormatTok, Line, StartColumn, NewPrefix,
+ InPPDirective, i != Lines.size() - 1);
+ StartColumn = NewPrefix.size();
+ }
+ }
+
+ std::string getNewLineText(unsigned NewLines, unsigned Spaces) {
+ return std::string(NewLines, '\n') + std::string(Spaces, ' ');
+ }
+
+ std::string getNewLineText(unsigned NewLines, unsigned Spaces,
+ unsigned WhitespaceStartColumn) {
+ std::string NewLineText;
+ if (NewLines > 0) {
+ unsigned Offset =
+ std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn);
+ for (unsigned i = 0; i < NewLines; ++i) {
+ NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' ');
+ NewLineText += "\\\n";
+ Offset = 0;
+ }
+ }
+ return NewLineText + std::string(Spaces, ' ');
+ }
+
+ /// \brief Structure to store a comment for later layout and alignment.
+ struct StoredComment {
+ FormatToken Tok;
+ unsigned MinColumn;
+ unsigned MaxColumn;
+ unsigned NewLines;
+ unsigned Spaces;
+ bool Untouchable;
+ };
+ SmallVector<StoredComment, 16> Comments;
+ typedef SmallVector<StoredComment, 16>::iterator comment_iterator;
+
+ /// \brief Try to align all stashed comments.
+ void alignComments() {
+ unsigned MinColumn = 0;
+ unsigned MaxColumn = UINT_MAX;
+ comment_iterator Start = Comments.begin();
+ for (comment_iterator I = Start, E = Comments.end(); I != E; ++I) {
+ if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) {
+ alignComments(Start, I, MinColumn);
+ MinColumn = I->MinColumn;
+ MaxColumn = I->MaxColumn;
+ Start = I;
+ } else {
+ MinColumn = std::max(MinColumn, I->MinColumn);
+ MaxColumn = std::min(MaxColumn, I->MaxColumn);
+ }
+ }
+ alignComments(Start, Comments.end(), MinColumn);
+ Comments.clear();
+ }
+
+ /// \brief Put all the comments between \p I and \p E into \p Column.
+ void alignComments(comment_iterator I, comment_iterator E, unsigned Column) {
+ while (I != E) {
+ if (!I->Untouchable) {
+ unsigned Spaces = I->Spaces + Column - I->MinColumn;
+ storeReplacement(I->Tok, getNewLineText(I->NewLines, Spaces));
+ }
+ ++I;
+ }
+ }
+
+ /// \brief Stores \p Text as the replacement for the whitespace in front of
+ /// \p Tok.
+ void storeReplacement(const FormatToken &Tok, const std::string Text) {
+ // Don't create a replacement, if it does not change anything.
+ if (StringRef(SourceMgr.getCharacterData(Tok.WhiteSpaceStart),
+ Tok.WhiteSpaceLength) == Text)
+ return;
+
+ Replaces.insert(tooling::Replacement(SourceMgr, Tok.WhiteSpaceStart,
+ Tok.WhiteSpaceLength, Text));
+ }
+
+ SourceManager &SourceMgr;
+ tooling::Replacements Replaces;
+ const FormatStyle &Style;
+};
+
+class UnwrappedLineFormatter {
+public:
+ UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
+ const AnnotatedLine &Line, unsigned FirstIndent,
+ const AnnotatedToken &RootToken,
+ WhitespaceManager &Whitespaces, bool StructuralError)
+ : Style(Style), SourceMgr(SourceMgr), Line(Line),
+ FirstIndent(FirstIndent), RootToken(RootToken),
+ Whitespaces(Whitespaces), Count(0) {}
+
+ /// \brief Formats an \c UnwrappedLine.
+ ///
+ /// \returns The column after the last token in the last line of the
+ /// \c UnwrappedLine.
+ unsigned format(const AnnotatedLine *NextLine) {
+ // Initialize state dependent on indent.
+ LineState State;
+ State.Column = FirstIndent;
+ State.NextToken = &RootToken;
+ State.Stack.push_back(
+ ParenState(FirstIndent, FirstIndent, !Style.BinPackParameters,
+ /*HasMultiParameterLine=*/ false));
+ State.LineContainsContinuedForLoopSection = false;
+ State.ParenLevel = 0;
+ State.StartOfStringLiteral = 0;
+ State.StartOfLineLevel = State.ParenLevel;
+
+ DEBUG({
+ DebugTokenState(*State.NextToken);
+ });
+
+ // The first token has already been indented and thus consumed.
+ moveStateToNextToken(State, /*DryRun=*/ false);
+
+ // If everything fits on a single line, just put it there.
+ unsigned ColumnLimit = Style.ColumnLimit;
+ if (NextLine && NextLine->InPPDirective &&
+ !NextLine->First.FormatTok.HasUnescapedNewline)
+ ColumnLimit = getColumnLimit();
+ if (Line.Last->TotalLength <= ColumnLimit - FirstIndent) {
+ while (State.NextToken != NULL) {
+ addTokenToState(false, false, State);
+ }
+ return State.Column;
+ }
+
+ // If the ObjC method declaration does not fit on a line, we should format
+ // it with one arg per line.
+ if (Line.Type == LT_ObjCMethodDecl)
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // Find best solution in solution space.
+ return analyzeSolutionSpace(State);
+ }
+
+private:
+ void DebugTokenState(const AnnotatedToken &AnnotatedTok) {
+ const Token &Tok = AnnotatedTok.FormatTok.Tok;
+ llvm::errs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
+ Tok.getLength());
+ llvm::errs();
+ }
+
+ struct ParenState {
+ ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
+ bool HasMultiParameterLine)
+ : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0),
+ BreakBeforeClosingBrace(false), QuestionColumn(0),
+ AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
+ HasMultiParameterLine(HasMultiParameterLine), ColonPos(0),
+ StartOfFunctionCall(0), NestedNameSpecifierContinuation(0),
+ CallContinuation(0), VariablePos(0) {}
+
+ /// \brief The position to which a specific parenthesis level needs to be
+ /// indented.
+ unsigned Indent;
+
+ /// \brief The position of the last space on each level.
+ ///
+ /// Used e.g. to break like:
+ /// functionCall(Parameter, otherCall(
+ /// OtherParameter));
+ unsigned LastSpace;
+
+ /// \brief The position the first "<<" operator encountered on each level.
+ ///
+ /// Used to align "<<" operators. 0 if no such operator has been encountered
+ /// on a level.
+ unsigned FirstLessLess;
+
+ /// \brief Whether a newline needs to be inserted before the block's closing
+ /// brace.
+ ///
+ /// We only want to insert a newline before the closing brace if there also
+ /// was a newline after the beginning left brace.
+ bool BreakBeforeClosingBrace;
+
+ /// \brief The column of a \c ? in a conditional expression;
+ unsigned QuestionColumn;
+
+ /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple
+ /// lines, in this context.
+ bool AvoidBinPacking;
+
+ /// \brief Break after the next comma (or all the commas in this context if
+ /// \c AvoidBinPacking is \c true).
+ bool BreakBeforeParameter;
+
+ /// \brief This context already has a line with more than one parameter.
+ bool HasMultiParameterLine;
+
+ /// \brief The position of the colon in an ObjC method declaration/call.
+ unsigned ColonPos;
+
+ /// \brief The start of the most recent function in a builder-type call.
+ unsigned StartOfFunctionCall;
+
+ /// \brief If a nested name specifier was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned NestedNameSpecifierContinuation;
+
+ /// \brief If a call expression was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned CallContinuation;
+
+ /// \brief The column of the first variable name in a variable declaration.
+ ///
+ /// Used to align further variables if necessary.
+ unsigned VariablePos;
+
+ bool operator<(const ParenState &Other) const {
+ if (Indent != Other.Indent)
+ return Indent < Other.Indent;
+ if (LastSpace != Other.LastSpace)
+ return LastSpace < Other.LastSpace;
+ if (FirstLessLess != Other.FirstLessLess)
+ return FirstLessLess < Other.FirstLessLess;
+ if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
+ return BreakBeforeClosingBrace;
+ if (QuestionColumn != Other.QuestionColumn)
+ return QuestionColumn < Other.QuestionColumn;
+ if (AvoidBinPacking != Other.AvoidBinPacking)
+ return AvoidBinPacking;
+ if (BreakBeforeParameter != Other.BreakBeforeParameter)
+ return BreakBeforeParameter;
+ if (HasMultiParameterLine != Other.HasMultiParameterLine)
+ return HasMultiParameterLine;
+ if (ColonPos != Other.ColonPos)
+ return ColonPos < Other.ColonPos;
+ if (StartOfFunctionCall != Other.StartOfFunctionCall)
+ return StartOfFunctionCall < Other.StartOfFunctionCall;
+ if (NestedNameSpecifierContinuation !=
+ Other.NestedNameSpecifierContinuation)
+ return NestedNameSpecifierContinuation <
+ Other.NestedNameSpecifierContinuation;
+ if (CallContinuation != Other.CallContinuation)
+ return CallContinuation < Other.CallContinuation;
+ if (VariablePos != Other.VariablePos)
+ return VariablePos < Other.VariablePos;
+ return false;
+ }
+ };
+
+ /// \brief The current state when indenting a unwrapped line.
+ ///
+ /// As the indenting tries different combinations this is copied by value.
+ struct LineState {
+ /// \brief The number of used columns in the current line.
+ unsigned Column;
+
+ /// \brief The token that needs to be next formatted.
+ const AnnotatedToken *NextToken;
+
+ /// \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.
+ unsigned StartOfLineLevel;
+
+ /// \brief The start column of the string literal, if we're in a string
+ /// literal sequence, 0 otherwise.
+ unsigned StartOfStringLiteral;
+
+ /// \brief A stack keeping track of properties applying to parenthesis
+ /// levels.
+ std::vector<ParenState> Stack;
+
+ /// \brief Comparison operator to be able to used \c LineState in \c map.
+ bool operator<(const LineState &Other) const {
+ if (NextToken != Other.NextToken)
+ return NextToken < Other.NextToken;
+ if (Column != Other.Column)
+ return Column < Other.Column;
+ if (LineContainsContinuedForLoopSection !=
+ Other.LineContainsContinuedForLoopSection)
+ return LineContainsContinuedForLoopSection;
+ if (ParenLevel != Other.ParenLevel)
+ return ParenLevel < Other.ParenLevel;
+ if (StartOfLineLevel != Other.StartOfLineLevel)
+ return StartOfLineLevel < Other.StartOfLineLevel;
+ if (StartOfStringLiteral != Other.StartOfStringLiteral)
+ return StartOfStringLiteral < Other.StartOfStringLiteral;
+ return Stack < Other.Stack;
+ }
+ };
+
+ /// \brief Appends the next token to \p State and updates information
+ /// necessary for indentation.
+ ///
+ /// Puts the token on the current line if \p Newline is \c true and adds a
+ /// line break and necessary indentation otherwise.
+ ///
+ /// If \p DryRun is \c false, also creates and stores the required
+ /// \c Replacement.
+ unsigned addTokenToState(bool Newline, bool DryRun, LineState &State) {
+ const AnnotatedToken &Current = *State.NextToken;
+ const AnnotatedToken &Previous = *State.NextToken->Parent;
+
+ if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) {
+ State.Column += State.NextToken->FormatTok.WhiteSpaceLength +
+ State.NextToken->FormatTok.TokenLength;
+ if (State.NextToken->Children.empty())
+ State.NextToken = NULL;
+ else
+ State.NextToken = &State.NextToken->Children[0];
+ return 0;
+ }
+
+ // If we are continuing an expression, we want to indent an extra 4 spaces.
+ unsigned ContinuationIndent =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4;
+ if (Newline) {
+ unsigned WhitespaceStartColumn = State.Column;
+ if (Current.is(tok::r_brace)) {
+ State.Column = Line.Level * 2;
+ } 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 (Previous.is(tok::coloncolon)) {
+ if (State.Stack.back().NestedNameSpecifierContinuation == 0) {
+ State.Column = ContinuationIndent;
+ State.Stack.back().NestedNameSpecifierContinuation = State.Column;
+ } else {
+ State.Column = State.Stack.back().NestedNameSpecifierContinuation;
+ }
+ } else if (Current.isOneOf(tok::period, tok::arrow)) {
+ if (State.Stack.back().CallContinuation == 0) {
+ State.Column = ContinuationIndent;
+ State.Stack.back().CallContinuation = State.Column;
+ } else {
+ State.Column = State.Stack.back().CallContinuation;
+ }
+ } else if (Current.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 (Previous.ClosesTemplateDeclaration ||
+ (Current.Type == TT_StartOfName && State.ParenLevel == 0)) {
+ State.Column = State.Stack.back().Indent;
+ } else if (Current.Type == TT_ObjCSelectorName) {
+ if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) {
+ State.Column =
+ State.Stack.back().ColonPos - Current.FormatTok.TokenLength;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ State.Stack.back().ColonPos =
+ State.Column + Current.FormatTok.TokenLength;
+ }
+ } else if (Current.Type == TT_StartOfName || Current.is(tok::question) ||
+ Previous.is(tok::equal) || isComparison(Previous) ||
+ Previous.Type == TT_ObjCMethodExpr) {
+ State.Column = ContinuationIndent;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ // Ensure that we fall back to indenting 4 spaces instead of just
+ // flushing continuations left.
+ if (State.Column == FirstIndent)
+ State.Column += 4;
+ }
+
+ if (Current.is(tok::question))
+ State.Stack.back().BreakBeforeParameter = true;
+ if (Previous.isOneOf(tok::comma, tok::semi) &&
+ !State.Stack.back().AvoidBinPacking)
+ State.Stack.back().BreakBeforeParameter = false;
+
+ if (!DryRun) {
+ unsigned NewLines = 1;
+ if (Current.Type == TT_LineComment)
+ NewLines =
+ std::max(NewLines, std::min(Current.FormatTok.NewlinesBefore,
+ Style.MaxEmptyLinesToKeep + 1));
+ if (!Line.InPPDirective)
+ Whitespaces.replaceWhitespace(Current, NewLines, State.Column,
+ WhitespaceStartColumn);
+ else
+ Whitespaces.replacePPWhitespace(Current, NewLines, State.Column,
+ WhitespaceStartColumn);
+ }
+
+ State.Stack.back().LastSpace = State.Column;
+ State.StartOfLineLevel = State.ParenLevel;
+
+ // 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;
+ }
+ if (Current.isOneOf(tok::period, tok::arrow))
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // If we break after {, we should also break before the corresponding }.
+ if (Previous.is(tok::l_brace))
+ State.Stack.back().BreakBeforeClosingBrace = true;
+
+ if (State.Stack.back().AvoidBinPacking) {
+ // If we are breaking after '(', '{', '<', this is not bin packing
+ // unless AllowAllParametersOfDeclarationOnNextLine is false.
+ if ((Previous.isNot(tok::l_paren) && Previous.isNot(tok::l_brace)) ||
+ (!Style.AllowAllParametersOfDeclarationOnNextLine &&
+ Line.MustBeDeclaration))
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+ } else {
+ if (Current.is(tok::equal) &&
+ (RootToken.is(tok::kw_for) || State.ParenLevel == 0) &&
+ State.Stack.back().VariablePos == 0) {
+ State.Stack.back().VariablePos = State.Column;
+ // Move over * and & if they are bound to the variable name.
+ const AnnotatedToken *Tok = &Previous;
+ while (Tok &&
+ State.Stack.back().VariablePos >= Tok->FormatTok.TokenLength) {
+ State.Stack.back().VariablePos -= Tok->FormatTok.TokenLength;
+ if (Tok->SpacesRequiredBefore != 0)
+ break;
+ Tok = Tok->Parent;
+ }
+ if (Previous.PartOfMultiVariableDeclStmt)
+ State.Stack.back().LastSpace = State.Stack.back().VariablePos;
+ }
+
+ unsigned Spaces = State.NextToken->SpacesRequiredBefore;
+
+ if (!DryRun)
+ Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column);
+
+ if (Current.Type == TT_ObjCSelectorName &&
+ State.Stack.back().ColonPos == 0) {
+ if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+ State.Column + Spaces + Current.FormatTok.TokenLength)
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + Current.LongestObjCSelectorName;
+ else
+ State.Stack.back().ColonPos =
+ State.Column + Spaces + Current.FormatTok.TokenLength;
+ }
+
+ if (Current.Type != TT_LineComment &&
+ (Previous.isOneOf(tok::l_paren, tok::l_brace) ||
+ State.NextToken->Parent->Type == TT_TemplateOpener))
+ State.Stack.back().Indent = State.Column + Spaces;
+ if (Previous.is(tok::comma) && !isTrailingComment(Current))
+ State.Stack.back().HasMultiParameterLine = true;
+
+ State.Column += Spaces;
+ if (Current.is(tok::l_paren) && 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 an indent of 4.
+ State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
+ else if (Previous.is(tok::comma))
+ State.Stack.back().LastSpace = State.Column;
+ else if ((Previous.Type == TT_BinaryOperator ||
+ Previous.Type == TT_ConditionalExpr ||
+ Previous.Type == TT_CtorInitializerColon) &&
+ getPrecedence(Previous) != prec::Assignment)
+ State.Stack.back().LastSpace = State.Column;
+ else if (Previous.Type == TT_InheritanceColon)
+ State.Stack.back().Indent = State.Column;
+ else if (Previous.ParameterCount > 1 &&
+ (Previous.isOneOf(tok::l_paren, tok::l_square, tok::l_brace) ||
+ Previous.Type == TT_TemplateOpener))
+ // If this function has multiple parameters, indent nested calls from
+ // the start of the first parameter.
+ State.Stack.back().LastSpace = State.Column;
+ }
+
+ return moveStateToNextToken(State, DryRun);
+ }
+
+ /// \brief Mark the next token as consumed in \p State and modify its stacks
+ /// accordingly.
+ unsigned moveStateToNextToken(LineState &State, bool DryRun) {
+ const AnnotatedToken &Current = *State.NextToken;
+ assert(State.Stack.size());
+
+ 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::question))
+ State.Stack.back().QuestionColumn = State.Column;
+ if (Current.isOneOf(tok::period, tok::arrow) &&
+ Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
+ State.Stack.back().StartOfFunctionCall =
+ Current.LastInChainOfCalls ? 0 : State.Column;
+ if (Current.Type == TT_CtorInitializerColon) {
+ if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ State.Stack.back().AvoidBinPacking = true;
+ State.Stack.back().BreakBeforeParameter = false;
+ }
+
+ // In ObjC method declaration we align on the ":" of parameters, but we need
+ // to ensure that we indent parameters on subsequent lines by at least 4.
+ if (Current.Type == TT_ObjCMethodSpecifier)
+ State.Stack.back().Indent += 4;
+
+ // Insert scopes created by fake parenthesis.
+ for (unsigned i = 0, e = Current.FakeLParens; i != e; ++i) {
+ ParenState NewParenState = State.Stack.back();
+ NewParenState.Indent = std::max(State.Column, State.Stack.back().Indent);
+ NewParenState.BreakBeforeParameter = false;
+ State.Stack.push_back(NewParenState);
+ }
+
+ // If we encounter an opening (, [, { or <, we add a level to our stacks to
+ // prepare for the following tokens.
+ if (Current.isOneOf(tok::l_paren, tok::l_square, tok::l_brace) ||
+ State.NextToken->Type == TT_TemplateOpener) {
+ unsigned NewIndent;
+ bool AvoidBinPacking;
+ if (Current.is(tok::l_brace)) {
+ NewIndent = 2 + State.Stack.back().LastSpace;
+ AvoidBinPacking = false;
+ } else {
+ NewIndent = 4 + std::max(State.Stack.back().LastSpace,
+ State.Stack.back().StartOfFunctionCall);
+ AvoidBinPacking =
+ !Style.BinPackParameters || State.Stack.back().AvoidBinPacking;
+ }
+ State.Stack.push_back(
+ ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking,
+ State.Stack.back().HasMultiParameterLine));
+ ++State.ParenLevel;
+ }
+
+ // 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.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr &&
+ Current.MatchingParen != NULL) {
+ if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit())
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
+ // If we encounter a closing ), ], } or >, we can remove a level from our
+ // stacks.
+ if (Current.isOneOf(tok::r_paren, tok::r_square) ||
+ (Current.is(tok::r_brace) && State.NextToken != &RootToken) ||
+ State.NextToken->Type == TT_TemplateCloser) {
+ State.Stack.pop_back();
+ --State.ParenLevel;
+ }
+
+ // Remove scopes created by fake parenthesis.
+ 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 = State.Column;
+ } else if (Current.isNot(tok::comment)) {
+ State.StartOfStringLiteral = 0;
+ }
+
+ State.Column += Current.FormatTok.TokenLength;
+
+ if (State.NextToken->Children.empty())
+ State.NextToken = NULL;
+ else
+ State.NextToken = &State.NextToken->Children[0];
+
+ return breakProtrudingToken(Current, State, DryRun);
+ }
+
+ /// \brief If the current token sticks out over the end of the line, break
+ /// it if possible.
+ unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State,
+ bool DryRun) {
+ if (Current.isNot(tok::string_literal))
+ return 0;
+ // Only break up default narrow strings.
+ const char *LiteralData = Current.FormatTok.Tok.getLiteralData();
+ if (!LiteralData || *LiteralData != '"')
+ return 0;
+
+ unsigned Penalty = 0;
+ unsigned TailOffset = 0;
+ unsigned TailLength = Current.FormatTok.TokenLength;
+ unsigned StartColumn = State.Column - Current.FormatTok.TokenLength;
+ unsigned OffsetFromStart = 0;
+ while (StartColumn + TailLength > getColumnLimit()) {
+ StringRef Text = StringRef(LiteralData + TailOffset, TailLength);
+ if (StartColumn + OffsetFromStart + 1 > getColumnLimit())
+ break;
+ StringRef::size_type SplitPoint = getSplitPoint(
+ Text, getColumnLimit() - StartColumn - OffsetFromStart - 1);
+ if (SplitPoint == StringRef::npos)
+ break;
+ assert(SplitPoint != 0);
+ // +2, because 'Text' starts after the opening quotes, and does not
+ // include the closing quote we need to insert.
+ unsigned WhitespaceStartColumn =
+ StartColumn + OffsetFromStart + SplitPoint + 2;
+ State.Stack.back().LastSpace = StartColumn;
+ if (!DryRun) {
+ Whitespaces.breakToken(Current.FormatTok, TailOffset + SplitPoint + 1,
+ 0, "\"", "\"", Line.InPPDirective, StartColumn,
+ WhitespaceStartColumn);
+ }
+ TailOffset += SplitPoint + 1;
+ TailLength -= SplitPoint + 1;
+ OffsetFromStart = 1;
+ Penalty += Style.PenaltyExcessCharacter;
+ for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
+ State.Stack[i].BreakBeforeParameter = true;
+ }
+ State.Column = StartColumn + TailLength;
+ return Penalty;
+ }
+
+ StringRef::size_type
+ getSplitPoint(StringRef Text, StringRef::size_type Offset) {
+ StringRef::size_type SpaceOffset = Text.rfind(' ', Offset);
+ if (SpaceOffset != StringRef::npos && SpaceOffset != 0)
+ return SpaceOffset;
+ StringRef::size_type SlashOffset = Text.rfind('/', Offset);
+ if (SlashOffset != StringRef::npos && SlashOffset != 0)
+ return SlashOffset;
+ StringRef::size_type Split = getStartOfCharacter(Text, Offset);
+ if (Split != StringRef::npos && Split > 1)
+ // Do not split at 0.
+ return Split - 1;
+ return StringRef::npos;
+ }
+
+ StringRef::size_type
+ getStartOfCharacter(StringRef Text, StringRef::size_type Offset) {
+ StringRef::size_type NextEscape = Text.find('\\');
+ while (NextEscape != StringRef::npos && NextEscape < Offset) {
+ StringRef::size_type SequenceLength =
+ getEscapeSequenceLength(Text.substr(NextEscape));
+ if (Offset < NextEscape + SequenceLength)
+ return NextEscape;
+ NextEscape = Text.find('\\', NextEscape + SequenceLength);
+ }
+ return Offset;
+ }
+
+ unsigned getEscapeSequenceLength(StringRef Text) {
+ assert(Text[0] == '\\');
+ if (Text.size() < 2)
+ return 1;
+
+ switch (Text[1]) {
+ case 'u':
+ return 6;
+ case 'U':
+ return 10;
+ case 'x':
+ return getHexLength(Text);
+ default:
+ if (Text[1] >= '0' && Text[1] <= '7')
+ return getOctalLength(Text);
+ return 2;
+ }
+ }
+
+ unsigned getHexLength(StringRef Text) {
+ unsigned I = 2; // Point after '\x'.
+ while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') ||
+ (Text[I] >= 'a' && Text[I] <= 'f') ||
+ (Text[I] >= 'A' && Text[I] <= 'F'))) {
+ ++I;
+ }
+ return I;
+ }
+
+ unsigned getOctalLength(StringRef Text) {
+ unsigned I = 1;
+ while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
+ ++I;
+ }
+ return I;
+ }
+
+ unsigned getColumnLimit() {
+ return calculateColumnLimit(Style, Line.InPPDirective);
+ }
+
+ /// \brief An edge in the solution space from \c Previous->State to \c State,
+ /// inserting a newline dependent on the \c NewLine.
+ struct StateNode {
+ StateNode(const LineState &State, bool NewLine, StateNode *Previous)
+ : State(State), NewLine(NewLine), Previous(Previous) {}
+ LineState State;
+ bool NewLine;
+ StateNode *Previous;
+ };
+
+ /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
+ ///
+ /// In case of equal penalties, we want to prefer states that were inserted
+ /// first. During state generation we make sure that we insert states first
+ /// that break the line as late as possible.
+ typedef std::pair<unsigned, unsigned> OrderedPenalty;
+
+ /// \brief An item in the prioritized BFS search queue. The \c StateNode's
+ /// \c State has the given \c OrderedPenalty.
+ typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
+
+ /// \brief The BFS queue type.
+ typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
+ std::greater<QueueItem> > QueueType;
+
+ /// \brief Analyze the entire solution space starting from \p InitialState.
+ ///
+ /// This implements a variant of Dijkstra's algorithm on the graph that spans
+ /// the solution space (\c LineStates are the nodes). The algorithm tries to
+ /// find the shortest path (the one with lowest penalty) from \p InitialState
+ /// to a state where all tokens are placed.
+ unsigned analyzeSolutionSpace(LineState &InitialState) {
+ std::set<LineState> Seen;
+
+ // Insert start element into queue.
+ StateNode *Node =
+ new (Allocator.Allocate()) StateNode(InitialState, false, NULL);
+ Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
+ ++Count;
+
+ // While not empty, take first element and follow edges.
+ while (!Queue.empty()) {
+ unsigned Penalty = Queue.top().first.first;
+ StateNode *Node = Queue.top().second;
+ if (Node->State.NextToken == NULL) {
+ DEBUG(llvm::errs() << "\n---\nPenalty for line: " << Penalty << "\n");
+ break;
+ }
+ Queue.pop();
+
+ if (!Seen.insert(Node->State).second)
+ // State already examined with lower penalty.
+ continue;
+
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/ false);
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/ true);
+ }
+
+ if (Queue.empty())
+ // We were unable to find a solution, do nothing.
+ // FIXME: Add diagnostic?
+ return 0;
+
+ // Reconstruct the solution.
+ reconstructPath(InitialState, Queue.top().second);
+ DEBUG(llvm::errs() << "---\n");
+
+ // Return the column after the last token of the solution.
+ return Queue.top().second->State.Column;
+ }
+
+ void reconstructPath(LineState &State, StateNode *Current) {
+ // FIXME: This recursive implementation limits the possible number
+ // of tokens per line if compiled into a binary with small stack space.
+ // To become more independent of stack frame limitations we would need
+ // to also change the TokenAnnotator.
+ if (Current->Previous == NULL)
+ return;
+ reconstructPath(State, Current->Previous);
+ DEBUG({
+ if (Current->NewLine) {
+ llvm::errs()
+ << "Penalty for splitting before "
+ << Current->Previous->State.NextToken->FormatTok.Tok.getName()
+ << ": " << Current->Previous->State.NextToken->SplitPenalty << "\n";
+ }
+ });
+ addTokenToState(Current->NewLine, false, State);
+ }
+
+ /// \brief Add the following state to the analysis queue \c Queue.
+ ///
+ /// Assume the current state is \p PreviousNode and has been reached with a
+ /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
+ void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
+ bool NewLine) {
+ if (NewLine && !canBreak(PreviousNode->State))
+ return;
+ if (!NewLine && mustBreak(PreviousNode->State))
+ return;
+ if (NewLine)
+ Penalty += PreviousNode->State.NextToken->SplitPenalty;
+
+ StateNode *Node = new (Allocator.Allocate())
+ StateNode(PreviousNode->State, NewLine, PreviousNode);
+ Penalty += addTokenToState(NewLine, true, Node->State);
+ if (Node->State.Column > getColumnLimit()) {
+ unsigned ExcessCharacters = Node->State.Column - getColumnLimit();
+ Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
+ }
+
+ Queue.push(QueueItem(OrderedPenalty(Penalty, Count), Node));
+ ++Count;
+ }
+
+ /// \brief Returns \c true, if a line break after \p State is allowed.
+ bool canBreak(const LineState &State) {
+ if (!State.NextToken->CanBreakBefore &&
+ !(State.NextToken->is(tok::r_brace) &&
+ State.Stack.back().BreakBeforeClosingBrace))
+ return false;
+ // Trying to insert a parameter on a new line if there are already more than
+ // one parameter on the current line is bin packing.
+ if (State.Stack.back().HasMultiParameterLine &&
+ State.Stack.back().AvoidBinPacking)
+ return false;
+ return true;
+ }
+
+ /// \brief Returns \c true, if a line break after \p State is mandatory.
+ bool mustBreak(const LineState &State) {
+ if (State.NextToken->MustBreakBefore)
+ return true;
+ if (State.NextToken->is(tok::r_brace) &&
+ State.Stack.back().BreakBeforeClosingBrace)
+ return true;
+ if (State.NextToken->Parent->is(tok::semi) &&
+ State.LineContainsContinuedForLoopSection)
+ return true;
+ if ((State.NextToken->Parent->isOneOf(tok::comma, tok::semi) ||
+ State.NextToken->is(tok::question) ||
+ State.NextToken->Type == TT_ConditionalExpr) &&
+ State.Stack.back().BreakBeforeParameter &&
+ !isTrailingComment(*State.NextToken) &&
+ State.NextToken->isNot(tok::r_paren) &&
+ State.NextToken->isNot(tok::r_brace))
+ return true;
+ // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
+ // out whether it is the first parameter. Clean this up.
+ if (State.NextToken->Type == TT_ObjCSelectorName &&
+ State.NextToken->LongestObjCSelectorName == 0 &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
+ if ((State.NextToken->Type == TT_CtorInitializerColon ||
+ (State.NextToken->Parent->ClosesTemplateDeclaration &&
+ State.ParenLevel == 0)))
+ return true;
+ if (State.NextToken->Type == TT_InlineASMColon)
+ return true;
+ // This prevents breaks like:
+ // ...
+ // SomeParameter, OtherParameter).DoSomething(
+ // ...
+ // As they hide "DoSomething" and generally bad for readability.
+ if (State.NextToken->isOneOf(tok::period, tok::arrow) &&
+ getRemainingLength(State) + State.Column > getColumnLimit() &&
+ State.ParenLevel < State.StartOfLineLevel)
+ return true;
+ return false;
+ }
+
+ // Returns the total number of columns required for the remaining tokens.
+ unsigned getRemainingLength(const LineState &State) {
+ if (State.NextToken && State.NextToken->Parent)
+ return Line.Last->TotalLength - State.NextToken->Parent->TotalLength;
+ return 0;
+ }
+
+ FormatStyle Style;
+ SourceManager &SourceMgr;
+ const AnnotatedLine &Line;
+ const unsigned FirstIndent;
+ const AnnotatedToken &RootToken;
+ WhitespaceManager &Whitespaces;
+
+ llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
+ QueueType Queue;
+ // Increasing count of \c StateNode items we have created. This is used
+ // to create a deterministic order independent of the container.
+ unsigned Count;
+};
+
+class LexerBasedFormatTokenSource : public FormatTokenSource {
+public:
+ LexerBasedFormatTokenSource(Lexer &Lex, SourceManager &SourceMgr)
+ : GreaterStashed(false), Lex(Lex), SourceMgr(SourceMgr),
+ IdentTable(Lex.getLangOpts()) {
+ Lex.SetKeepWhitespaceMode(true);
+ }
+
+ virtual FormatToken getNextToken() {
+ if (GreaterStashed) {
+ FormatTok.NewlinesBefore = 0;
+ FormatTok.WhiteSpaceStart =
+ FormatTok.Tok.getLocation().getLocWithOffset(1);
+ FormatTok.WhiteSpaceLength = 0;
+ GreaterStashed = false;
+ return FormatTok;
+ }
+
+ FormatTok = FormatToken();
+ Lex.LexFromRawLexer(FormatTok.Tok);
+ StringRef Text = rawTokenText(FormatTok.Tok);
+ FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
+ if (SourceMgr.getFileOffset(FormatTok.WhiteSpaceStart) == 0)
+ FormatTok.IsFirst = true;
+
+ // Consume and record whitespace until we find a significant token.
+ while (FormatTok.Tok.is(tok::unknown)) {
+ unsigned Newlines = Text.count('\n');
+ if (Newlines > 0)
+ FormatTok.LastNewlineOffset =
+ FormatTok.WhiteSpaceLength + Text.rfind('\n') + 1;
+ unsigned EscapedNewlines = Text.count("\\\n");
+ FormatTok.NewlinesBefore += Newlines;
+ FormatTok.HasUnescapedNewline |= EscapedNewlines != Newlines;
+ FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
+
+ if (FormatTok.Tok.is(tok::eof))
+ return FormatTok;
+ Lex.LexFromRawLexer(FormatTok.Tok);
+ Text = rawTokenText(FormatTok.Tok);
+ }
+
+ // Now FormatTok is the next non-whitespace token.
+ FormatTok.TokenLength = Text.size();
+
+ // In case the token starts with escaped newlines, we want to
+ // take them into account as whitespace - this pattern is quite frequent
+ // in macro definitions.
+ // FIXME: What do we want to do with other escaped spaces, and escaped
+ // spaces or newlines in the middle of tokens?
+ // FIXME: Add a more explicit test.
+ unsigned i = 0;
+ while (i + 1 < Text.size() && Text[i] == '\\' && Text[i + 1] == '\n') {
+ // FIXME: ++FormatTok.NewlinesBefore is missing...
+ FormatTok.WhiteSpaceLength += 2;
+ FormatTok.TokenLength -= 2;
+ i += 2;
+ }
+
+ if (FormatTok.Tok.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = IdentTable.get(Text);
+ FormatTok.Tok.setIdentifierInfo(&Info);
+ FormatTok.Tok.setKind(Info.getTokenID());
+ }
+
+ if (FormatTok.Tok.is(tok::greatergreater)) {
+ FormatTok.Tok.setKind(tok::greater);
+ FormatTok.TokenLength = 1;
+ GreaterStashed = true;
+ }
+
+ // If we reformat comments, we remove trailing whitespace. Update the length
+ // accordingly.
+ if (FormatTok.Tok.is(tok::comment))
+ FormatTok.TokenLength = Text.rtrim().size();
+
+ return FormatTok;
+ }
+
+ IdentifierTable &getIdentTable() { return IdentTable; }
+
+private:
+ FormatToken FormatTok;
+ bool GreaterStashed;
+ Lexer &Lex;
+ SourceManager &SourceMgr;
+ IdentifierTable IdentTable;
+
+ /// Returns the text of \c FormatTok.
+ StringRef rawTokenText(Token &Tok) {
+ return StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
+ Tok.getLength());
+ }
+};
+
+class Formatter : public UnwrappedLineConsumer {
+public:
+ Formatter(DiagnosticsEngine &Diag, const FormatStyle &Style, Lexer &Lex,
+ SourceManager &SourceMgr,
+ const std::vector<CharSourceRange> &Ranges)
+ : Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr),
+ Whitespaces(SourceMgr, Style), Ranges(Ranges) {}
+
+ virtual ~Formatter() {}
+
+ tooling::Replacements format() {
+ LexerBasedFormatTokenSource Tokens(Lex, SourceMgr);
+ UnwrappedLineParser Parser(Diag, Style, Tokens, *this);
+ StructuralError = Parser.parse();
+ unsigned PreviousEndOfLineColumn = 0;
+ TokenAnnotator Annotator(Style, SourceMgr, Lex,
+ Tokens.getIdentTable().get("in"));
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ Annotator.annotate(AnnotatedLines[i]);
+ }
+ deriveLocalStyle();
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ Annotator.calculateFormattingInformation(AnnotatedLines[i]);
+
+ // Adapt level to the next line if this is a comment.
+ // FIXME: Can/should this be done in the UnwrappedLineParser?
+ if (i + 1 != e && AnnotatedLines[i].First.is(tok::comment) &&
+ AnnotatedLines[i].First.Children.empty() &&
+ AnnotatedLines[i + 1].First.isNot(tok::r_brace))
+ AnnotatedLines[i].Level = AnnotatedLines[i + 1].Level;
+ }
+ std::vector<int> IndentForLevel;
+ bool PreviousLineWasTouched = false;
+ const AnnotatedToken *PreviousLineLastToken = 0;
+ for (std::vector<AnnotatedLine>::iterator I = AnnotatedLines.begin(),
+ E = AnnotatedLines.end();
+ I != E; ++I) {
+ const AnnotatedLine &TheLine = *I;
+ const FormatToken &FirstTok = TheLine.First.FormatTok;
+ int Offset = getIndentOffset(TheLine.First);
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ bool WasMoved = PreviousLineWasTouched && FirstTok.NewlinesBefore == 0;
+ if (TheLine.First.is(tok::eof)) {
+ if (PreviousLineWasTouched) {
+ unsigned NewLines = std::min(FirstTok.NewlinesBefore, 1u);
+ Whitespaces.replaceWhitespace(TheLine.First, NewLines, /*Indent*/ 0,
+ /*WhitespaceStartColumn*/ 0);
+ }
+ } else if (TheLine.Type != LT_Invalid &&
+ (WasMoved || touchesLine(TheLine))) {
+ unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level);
+ unsigned Indent = LevelIndent;
+ if (static_cast<int>(Indent) + Offset >= 0)
+ Indent += Offset;
+ if (!FirstTok.WhiteSpaceStart.isValid() || StructuralError) {
+ Indent = LevelIndent =
+ SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1;
+ } else {
+ formatFirstToken(TheLine.First, PreviousLineLastToken, Indent,
+ TheLine.InPPDirective, PreviousEndOfLineColumn);
+ }
+ tryFitMultipleLinesInOne(Indent, I, E);
+ UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent,
+ TheLine.First, Whitespaces,
+ StructuralError);
+ PreviousEndOfLineColumn =
+ Formatter.format(I + 1 != E ? &*(I + 1) : NULL);
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ PreviousLineWasTouched = true;
+ } else {
+ if (FirstTok.NewlinesBefore > 0 || FirstTok.IsFirst) {
+ unsigned Indent =
+ SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1;
+ unsigned LevelIndent = Indent;
+ if (static_cast<int>(LevelIndent) - Offset >= 0)
+ LevelIndent -= Offset;
+ if (TheLine.First.isNot(tok::comment))
+ IndentForLevel[TheLine.Level] = LevelIndent;
+
+ // Remove trailing whitespace of the previous line if it was touched.
+ if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine))
+ formatFirstToken(TheLine.First, PreviousLineLastToken, Indent,
+ TheLine.InPPDirective, PreviousEndOfLineColumn);
+ }
+ // 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.
+ SourceLocation LastLoc = TheLine.Last->FormatTok.Tok.getLocation();
+ PreviousEndOfLineColumn =
+ SourceMgr.getSpellingColumnNumber(LastLoc) +
+ Lex.MeasureTokenLength(LastLoc, SourceMgr, Lex.getLangOpts()) - 1;
+ PreviousLineWasTouched = false;
+ if (TheLine.Last->is(tok::comment))
+ Whitespaces.addUntouchableComment(SourceMgr.getSpellingColumnNumber(
+ TheLine.Last->FormatTok.Tok.getLocation()) - 1);
+ }
+ PreviousLineLastToken = I->Last;
+ }
+ return Whitespaces.generateReplacements();
+ }
+
+private:
+ void deriveLocalStyle() {
+ unsigned CountBoundToVariable = 0;
+ unsigned CountBoundToType = 0;
+ bool HasCpp03IncompatibleFormat = false;
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ if (AnnotatedLines[i].First.Children.empty())
+ continue;
+ AnnotatedToken *Tok = &AnnotatedLines[i].First.Children[0];
+ while (!Tok->Children.empty()) {
+ if (Tok->Type == TT_PointerOrReference) {
+ bool SpacesBefore = Tok->FormatTok.WhiteSpaceLength > 0;
+ bool SpacesAfter = Tok->Children[0].FormatTok.WhiteSpaceLength > 0;
+ if (SpacesBefore && !SpacesAfter)
+ ++CountBoundToVariable;
+ else if (!SpacesBefore && SpacesAfter)
+ ++CountBoundToType;
+ }
+
+ if (Tok->Type == TT_TemplateCloser &&
+ Tok->Parent->Type == TT_TemplateCloser &&
+ Tok->FormatTok.WhiteSpaceLength == 0)
+ HasCpp03IncompatibleFormat = true;
+ Tok = &Tok->Children[0];
+ }
+ }
+ if (Style.DerivePointerBinding) {
+ if (CountBoundToType > CountBoundToVariable)
+ Style.PointerBindsToType = true;
+ else if (CountBoundToType < CountBoundToVariable)
+ Style.PointerBindsToType = false;
+ }
+ if (Style.Standard == FormatStyle::LS_Auto) {
+ Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11
+ : FormatStyle::LS_Cpp03;
+ }
+ }
+
+ /// \brief Get the indent of \p Level from \p IndentForLevel.
+ ///
+ /// \p IndentForLevel must contain the indent for the level \c l
+ /// at \p IndentForLevel[l], or a value < 0 if the indent for
+ /// that level is unknown.
+ unsigned getIndent(const std::vector<int> IndentForLevel, unsigned Level) {
+ if (IndentForLevel[Level] != -1)
+ return IndentForLevel[Level];
+ if (Level == 0)
+ return 0;
+ return getIndent(IndentForLevel, Level - 1) + 2;
+ }
+
+ /// \brief Get the offset of the line relatively to the level.
+ ///
+ /// For example, 'public:' labels in classes are offset by 1 or 2
+ /// characters to the left from their level.
+ int getIndentOffset(const AnnotatedToken &RootToken) {
+ if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
+ return Style.AccessModifierOffset;
+ return 0;
+ }
+
+ /// \brief Tries to merge lines into one.
+ ///
+ /// This will change \c Line and \c AnnotatedLine to contain the merged line,
+ /// if possible; note that \c I will be incremented when lines are merged.
+ ///
+ /// Returns whether the resulting \c Line can fit in a single line.
+ void tryFitMultipleLinesInOne(unsigned Indent,
+ std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E) {
+ // We can never merge stuff if there are trailing line comments.
+ if (I->Last->Type == TT_LineComment)
+ return;
+
+ unsigned Limit = Style.ColumnLimit - Indent;
+ // If we already exceed the column limit, we set 'Limit' to 0. The different
+ // tryMerge..() functions can then decide whether to still do merging.
+ Limit = I->Last->TotalLength > Limit ? 0 : Limit - I->Last->TotalLength;
+
+ if (I + 1 == E || (I + 1)->Type == LT_Invalid)
+ return;
+
+ if (I->Last->is(tok::l_brace)) {
+ tryMergeSimpleBlock(I, E, Limit);
+ } else if (I->First.is(tok::kw_if)) {
+ tryMergeSimpleIf(I, E, Limit);
+ } else if (I->InPPDirective && (I->First.FormatTok.HasUnescapedNewline ||
+ I->First.FormatTok.IsFirst)) {
+ tryMergeSimplePPDirective(I, E, Limit);
+ }
+ return;
+ }
+
+ void tryMergeSimplePPDirective(std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return;
+ AnnotatedLine &Line = *I;
+ if (!(I + 1)->InPPDirective || (I + 1)->First.FormatTok.HasUnescapedNewline)
+ return;
+ if (I + 2 != E && (I + 2)->InPPDirective &&
+ !(I + 2)->First.FormatTok.HasUnescapedNewline)
+ return;
+ if (1 + (I + 1)->Last->TotalLength > Limit)
+ return;
+ join(Line, *(++I));
+ }
+
+ void tryMergeSimpleIf(std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return;
+ if (!Style.AllowShortIfStatementsOnASingleLine)
+ return;
+ if ((I + 1)->InPPDirective != I->InPPDirective ||
+ ((I + 1)->InPPDirective &&
+ (I + 1)->First.FormatTok.HasUnescapedNewline))
+ return;
+ AnnotatedLine &Line = *I;
+ if (Line.Last->isNot(tok::r_paren))
+ return;
+ if (1 + (I + 1)->Last->TotalLength > Limit)
+ return;
+ if ((I + 1)->First.is(tok::kw_if) || (I + 1)->First.Type == TT_LineComment)
+ return;
+ // Only inline simple if's (no nested if or else).
+ if (I + 2 != E && (I + 2)->First.is(tok::kw_else))
+ return;
+ join(Line, *(++I));
+ }
+
+ void tryMergeSimpleBlock(std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E,
+ unsigned Limit) {
+ // 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))
+ return;
+
+ AnnotatedToken *Tok = &(I + 1)->First;
+ if (Tok->Children.empty() && Tok->is(tok::r_brace) &&
+ !Tok->MustBreakBefore) {
+ // We merge empty blocks even if the line exceeds the column limit.
+ Tok->SpacesRequiredBefore = 0;
+ Tok->CanBreakBefore = true;
+ join(Line, *(I + 1));
+ I += 1;
+ } else if (Limit != 0) {
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || (I + 2)->Type == LT_Invalid ||
+ !nextTwoLinesFitInto(I, Limit))
+ return;
+
+ // 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)
+ return;
+ do {
+ if (Tok->isOneOf(tok::l_brace, tok::r_brace))
+ return;
+ Tok = Tok->Children.empty() ? NULL : &Tok->Children.back();
+ } while (Tok != NULL);
+
+ // Last, check that the third line contains a single closing brace.
+ Tok = &(I + 2)->First;
+ if (!Tok->Children.empty() || Tok->isNot(tok::r_brace) ||
+ Tok->MustBreakBefore)
+ return;
+
+ join(Line, *(I + 1));
+ join(Line, *(I + 2));
+ I += 2;
+ }
+ }
+
+ bool nextTwoLinesFitInto(std::vector<AnnotatedLine>::iterator I,
+ unsigned Limit) {
+ return 1 + (I + 1)->Last->TotalLength + 1 + (I + 2)->Last->TotalLength <=
+ Limit;
+ }
+
+ void join(AnnotatedLine &A, const AnnotatedLine &B) {
+ unsigned LengthA = A.Last->TotalLength + B.First.SpacesRequiredBefore;
+ A.Last->Children.push_back(B.First);
+ while (!A.Last->Children.empty()) {
+ A.Last->Children[0].Parent = A.Last;
+ A.Last->Children[0].TotalLength += LengthA;
+ A.Last = &A.Last->Children[0];
+ }
+ }
+
+ bool touchesRanges(const CharSourceRange &Range) {
+ for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),
+ Ranges[i].getBegin()) &&
+ !SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
+ Range.getBegin()))
+ return true;
+ }
+ return false;
+ }
+
+ bool touchesLine(const AnnotatedLine &TheLine) {
+ const FormatToken *First = &TheLine.First.FormatTok;
+ const FormatToken *Last = &TheLine.Last->FormatTok;
+ CharSourceRange LineRange = CharSourceRange::getTokenRange(
+ First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset),
+ Last->Tok.getLocation());
+ return touchesRanges(LineRange);
+ }
+
+ bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
+ const FormatToken *First = &TheLine.First.FormatTok;
+ CharSourceRange LineRange = CharSourceRange::getCharRange(
+ First->WhiteSpaceStart,
+ First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset));
+ return touchesRanges(LineRange);
+ }
+
+ virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
+ AnnotatedLines.push_back(AnnotatedLine(TheLine));
+ }
+
+ /// \brief Add a new line and the required indent before the first Token
+ /// of the \c UnwrappedLine if there was no structural parsing error.
+ /// Returns the indent level of the \c UnwrappedLine.
+ void formatFirstToken(const AnnotatedToken &RootToken,
+ const AnnotatedToken *PreviousToken, unsigned Indent,
+ bool InPPDirective, unsigned PreviousEndOfLineColumn) {
+ const FormatToken &Tok = RootToken.FormatTok;
+
+ unsigned Newlines =
+ std::min(Tok.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
+ if (Newlines == 0 && !Tok.IsFirst)
+ Newlines = 1;
+
+ if (!InPPDirective || Tok.HasUnescapedNewline) {
+ // Insert extra new line before access specifiers.
+ if (PreviousToken && PreviousToken->isOneOf(tok::semi, tok::r_brace) &&
+ RootToken.isAccessSpecifier() && Tok.NewlinesBefore == 1)
+ ++Newlines;
+
+ Whitespaces.replaceWhitespace(RootToken, Newlines, Indent, 0);
+ } else {
+ Whitespaces.replacePPWhitespace(RootToken, Newlines, Indent,
+ PreviousEndOfLineColumn);
+ }
+ }
+
+ DiagnosticsEngine &Diag;
+ FormatStyle Style;
+ Lexer &Lex;
+ SourceManager &SourceMgr;
+ WhitespaceManager Whitespaces;
+ std::vector<CharSourceRange> Ranges;
+ std::vector<AnnotatedLine> AnnotatedLines;
+ bool StructuralError;
+};
+
+tooling::Replacements
+reformat(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
+ std::vector<CharSourceRange> Ranges, DiagnosticConsumer *DiagClient) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ OwningPtr<DiagnosticConsumer> DiagPrinter;
+ if (DiagClient == 0) {
+ DiagPrinter.reset(new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts));
+ DiagPrinter->BeginSourceFile(Lex.getLangOpts(), Lex.getPP());
+ DiagClient = DiagPrinter.get();
+ }
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ DiagClient, false);
+ Diagnostics.setSourceManager(&SourceMgr);
+ Formatter formatter(Diagnostics, Style, Lex, SourceMgr, Ranges);
+ return formatter.format();
+}
+
+LangOptions getFormattingLangOpts() {
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = 1;
+ LangOpts.CPlusPlus11 = 1;
+ LangOpts.LineComment = 1;
+ LangOpts.Bool = 1;
+ LangOpts.ObjC1 = 1;
+ LangOpts.ObjC2 = 1;
+ return LangOpts;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/Makefile b/lib/Format/Makefile
new file mode 100644
index 000000000000..f4d2b985b12e
--- /dev/null
+++ b/lib/Format/Makefile
@@ -0,0 +1,13 @@
+##===- clang/lib/Format/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangFormat
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
new file mode 100644
index 000000000000..427157e3322d
--- /dev/null
+++ b/lib/Format/TokenAnnotator.cpp
@@ -0,0 +1,1187 @@
+//===--- TokenAnnotator.cpp - Format C++ code -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a token annotator, i.e. creates
+/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TokenAnnotator.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace format {
+
+static bool isUnaryOperator(const AnnotatedToken &Tok) {
+ switch (Tok.FormatTok.Tok.getKind()) {
+ case tok::plus:
+ case tok::plusplus:
+ case tok::minus:
+ case tok::minusminus:
+ case tok::exclaim:
+ case tok::tilde:
+ case tok::kw_sizeof:
+ case tok::kw_alignof:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isBinaryOperator(const AnnotatedToken &Tok) {
+ // Comma is a binary operator, but does not behave as such wrt. formatting.
+ return getPrecedence(Tok) > prec::Comma;
+}
+
+// Returns the previous token ignoring comments.
+static AnnotatedToken *getPreviousToken(AnnotatedToken &Tok) {
+ AnnotatedToken *PrevToken = Tok.Parent;
+ while (PrevToken != NULL && PrevToken->is(tok::comment))
+ PrevToken = PrevToken->Parent;
+ return PrevToken;
+}
+static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) {
+ return getPreviousToken(const_cast<AnnotatedToken &>(Tok));
+}
+
+static bool isTrailingComment(AnnotatedToken *Tok) {
+ return Tok != NULL && Tok->is(tok::comment) &&
+ (Tok->Children.empty() ||
+ Tok->Children[0].FormatTok.NewlinesBefore > 0);
+}
+
+// Returns the next token ignoring comments.
+static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) {
+ if (Tok.Children.empty())
+ return NULL;
+ const AnnotatedToken *NextToken = &Tok.Children[0];
+ while (NextToken->is(tok::comment)) {
+ if (NextToken->Children.empty())
+ return NULL;
+ NextToken = &NextToken->Children[0];
+ }
+ return NextToken;
+}
+
+static bool closesScope(const AnnotatedToken &Tok) {
+ return Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
+ Tok.Type == TT_TemplateCloser;
+}
+
+static bool opensScope(const AnnotatedToken &Tok) {
+ return Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
+ Tok.Type == TT_TemplateOpener;
+}
+
+/// \brief A parser that gathers additional information about tokens.
+///
+/// The \c TokenAnnotator tries to match parenthesis and square brakets and
+/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
+/// into template parameter lists.
+class AnnotatingParser {
+public:
+ AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line,
+ IdentifierInfo &Ident_in)
+ : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
+ KeywordVirtualFound(false), Ident_in(Ident_in) {
+ Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/ false));
+ }
+
+private:
+ bool parseAngle() {
+ if (CurrentToken == NULL)
+ return false;
+ ScopedContextCreator ContextCreator(*this, tok::less, 10);
+ AnnotatedToken *Left = CurrentToken->Parent;
+ Contexts.back().IsExpression = false;
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::greater)) {
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+ CurrentToken->Type = TT_TemplateCloser;
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace,
+ tok::pipepipe, tok::ampamp, tok::question,
+ tok::colon))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseParens(bool LookForDecls = false) {
+ if (CurrentToken == NULL)
+ return false;
+ ScopedContextCreator ContextCreator(*this, tok::l_paren, 1);
+
+ // FIXME: This is a bit of a hack. Do better.
+ Contexts.back().ColonIsForRangeExpr =
+ Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
+
+ bool StartsObjCMethodExpr = false;
+ AnnotatedToken *Left = CurrentToken->Parent;
+ if (CurrentToken->is(tok::caret)) {
+ // ^( starts a block.
+ Left->Type = TT_ObjCBlockLParen;
+ } else if (AnnotatedToken *MaybeSel = Left->Parent) {
+ // @selector( starts a selector.
+ if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent &&
+ MaybeSel->Parent->is(tok::at)) {
+ StartsObjCMethodExpr = true;
+ }
+ }
+
+ if (StartsObjCMethodExpr) {
+ Contexts.back().ColonIsObjCMethodExpr = true;
+ Left->Type = TT_ObjCMethodExpr;
+ }
+
+ while (CurrentToken != NULL) {
+ // 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
+ // categorize it as an unary operator, so set the right type here.
+ if (LookForDecls && !CurrentToken->Children.empty()) {
+ AnnotatedToken &Prev = *CurrentToken->Parent;
+ AnnotatedToken &Next = CurrentToken->Children[0];
+ if (Prev.Parent->is(tok::identifier) &&
+ Prev.isOneOf(tok::star, tok::amp, tok::ampamp) &&
+ CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
+ Prev.Type = TT_BinaryOperator;
+ LookForDecls = false;
+ }
+ }
+
+ if (CurrentToken->is(tok::r_paren)) {
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+
+ if (StartsObjCMethodExpr) {
+ CurrentToken->Type = TT_ObjCMethodExpr;
+ if (Contexts.back().FirstObjCSelectorName != NULL) {
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
+ Contexts.back().LongestObjCSelectorName;
+ }
+ }
+
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseSquare() {
+ if (!CurrentToken)
+ return false;
+
+ // A '[' could be an index subscript (after an indentifier or after
+ // ')' or ']'), it could be the start of an Objective-C method
+ // expression, or it could the the start of an Objective-C array literal.
+ AnnotatedToken *Left = CurrentToken->Parent;
+ AnnotatedToken *Parent = getPreviousToken(*Left);
+ bool StartsObjCMethodExpr =
+ Contexts.back().CanBeExpression &&
+ (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
+ tok::kw_return, tok::kw_throw) ||
+ isUnaryOperator(*Parent) || Parent->Type == TT_ObjCForIn ||
+ Parent->Type == TT_CastRParen ||
+ getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) >
+ prec::Unknown);
+ ScopedContextCreator ContextCreator(*this, tok::l_square, 10);
+ Contexts.back().IsExpression = true;
+ bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at);
+
+ if (StartsObjCMethodExpr) {
+ Contexts.back().ColonIsObjCMethodExpr = true;
+ Left->Type = TT_ObjCMethodExpr;
+ } else if (StartsObjCArrayLiteral) {
+ Left->Type = TT_ObjCArrayLiteral;
+ }
+
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::r_square)) {
+ if (!CurrentToken->Children.empty() &&
+ CurrentToken->Children[0].is(tok::l_paren)) {
+ // An ObjC method call is rarely followed by an open parenthesis.
+ // FIXME: Do we incorrectly label ":" with this?
+ StartsObjCMethodExpr = false;
+ Left->Type = TT_Unknown;
+ }
+ if (StartsObjCMethodExpr) {
+ 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)
+ Parent->Type = TT_BinaryOperator;
+ } else if (StartsObjCArrayLiteral) {
+ CurrentToken->Type = TT_ObjCArrayLiteral;
+ }
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+ if (Contexts.back().FirstObjCSelectorName != NULL)
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
+ Contexts.back().LongestObjCSelectorName;
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseBrace() {
+ // Lines are fine to end with '{'.
+ if (CurrentToken == NULL)
+ return true;
+ ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
+ AnnotatedToken *Left = CurrentToken->Parent;
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::r_brace)) {
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return true;
+ }
+
+ void updateParameterCount(AnnotatedToken *Left, AnnotatedToken *Current) {
+ if (Current->is(tok::comma))
+ ++Left->ParameterCount;
+ else if (Left->ParameterCount == 0 && Current->isNot(tok::comment))
+ Left->ParameterCount = 1;
+ }
+
+ bool parseConditional() {
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::colon)) {
+ CurrentToken->Type = TT_ConditionalExpr;
+ next();
+ return true;
+ }
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseTemplateDeclaration() {
+ if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ CurrentToken->Type = TT_TemplateOpener;
+ next();
+ if (!parseAngle())
+ return false;
+ if (CurrentToken != NULL)
+ CurrentToken->Parent->ClosesTemplateDeclaration = true;
+ return true;
+ }
+ return false;
+ }
+
+ bool consumeToken() {
+ AnnotatedToken *Tok = CurrentToken;
+ next();
+ switch (Tok->FormatTok.Tok.getKind()) {
+ case tok::plus:
+ case tok::minus:
+ if (Tok->Parent == NULL && Line.MustBeDeclaration)
+ Tok->Type = TT_ObjCMethodSpecifier;
+ break;
+ case tok::colon:
+ if (Tok->Parent == NULL)
+ return false;
+ // Colons from ?: are handled in parseConditional().
+ if (Tok->Parent->is(tok::r_paren) && Contexts.size() == 1) {
+ Tok->Type = TT_CtorInitializerColon;
+ } else if (Contexts.back().ColonIsObjCMethodExpr ||
+ Line.First.Type == TT_ObjCMethodSpecifier) {
+ Tok->Type = TT_ObjCMethodExpr;
+ Tok->Parent->Type = TT_ObjCSelectorName;
+ if (Tok->Parent->FormatTok.TokenLength >
+ Contexts.back().LongestObjCSelectorName)
+ Contexts.back().LongestObjCSelectorName =
+ Tok->Parent->FormatTok.TokenLength;
+ if (Contexts.back().FirstObjCSelectorName == NULL)
+ Contexts.back().FirstObjCSelectorName = Tok->Parent;
+ } else if (Contexts.back().ColonIsForRangeExpr) {
+ Tok->Type = TT_RangeBasedForLoopColon;
+ } else if (Contexts.size() == 1) {
+ Tok->Type = TT_InheritanceColon;
+ } else if (Contexts.back().ContextKind == tok::l_paren) {
+ Tok->Type = TT_InlineASMColon;
+ }
+ break;
+ case tok::kw_if:
+ case tok::kw_while:
+ if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
+ next();
+ if (!parseParens(/*LookForDecls=*/ true))
+ return false;
+ }
+ break;
+ case tok::kw_for:
+ Contexts.back().ColonIsForRangeExpr = true;
+ next();
+ if (!parseParens())
+ return false;
+ break;
+ case tok::l_paren:
+ if (!parseParens())
+ return false;
+ if (Line.MustBeDeclaration)
+ Line.MightBeFunctionDecl = true;
+ break;
+ case tok::l_square:
+ if (!parseSquare())
+ return false;
+ break;
+ case tok::l_brace:
+ if (!parseBrace())
+ return false;
+ break;
+ case tok::less:
+ if (parseAngle())
+ Tok->Type = TT_TemplateOpener;
+ else {
+ Tok->Type = TT_BinaryOperator;
+ CurrentToken = Tok;
+ next();
+ }
+ break;
+ case tok::r_paren:
+ case tok::r_square:
+ return false;
+ case tok::r_brace:
+ // Lines can start with '}'.
+ if (Tok->Parent != NULL)
+ return false;
+ break;
+ case tok::greater:
+ Tok->Type = TT_BinaryOperator;
+ break;
+ case tok::kw_operator:
+ while (CurrentToken && CurrentToken->isNot(tok::l_paren)) {
+ if (CurrentToken->isOneOf(tok::star, tok::amp))
+ CurrentToken->Type = TT_PointerOrReference;
+ consumeToken();
+ }
+ if (CurrentToken)
+ CurrentToken->Type = TT_OverloadedOperatorLParen;
+ break;
+ case tok::question:
+ parseConditional();
+ break;
+ case tok::kw_template:
+ parseTemplateDeclaration();
+ break;
+ case tok::identifier:
+ if (Line.First.is(tok::kw_for) &&
+ Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in)
+ Tok->Type = TT_ObjCForIn;
+ break;
+ case tok::comma:
+ if (Contexts.back().FirstStartOfName)
+ Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ void parseIncludeDirective() {
+ next();
+ if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ next();
+ while (CurrentToken != NULL) {
+ if (CurrentToken->isNot(tok::comment) ||
+ !CurrentToken->Children.empty())
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ } else {
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::string_literal))
+ // Mark these string literals as "implicit" literals, too, so that
+ // they are not split or line-wrapped.
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ }
+ }
+
+ void parseWarningOrError() {
+ next();
+ // We still want to format the whitespace left of the first token of the
+ // warning or error.
+ next();
+ while (CurrentToken != NULL) {
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ }
+
+ void parsePreprocessorDirective() {
+ next();
+ if (CurrentToken == NULL)
+ return;
+ // Hashes in the middle of a line can lead to any strange token
+ // sequence.
+ if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
+ return;
+ switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ case tok::pp_import:
+ parseIncludeDirective();
+ break;
+ case tok::pp_error:
+ case tok::pp_warning:
+ parseWarningOrError();
+ break;
+ default:
+ break;
+ }
+ while (CurrentToken != NULL)
+ next();
+ }
+
+public:
+ LineType parseLine() {
+ int PeriodsAndArrows = 0;
+ AnnotatedToken *LastPeriodOrArrow = NULL;
+ bool CanBeBuilderTypeStmt = true;
+ if (CurrentToken->is(tok::hash)) {
+ parsePreprocessorDirective();
+ return LT_PreprocessorDirective;
+ }
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::kw_virtual))
+ KeywordVirtualFound = true;
+ if (CurrentToken->isOneOf(tok::period, tok::arrow)) {
+ ++PeriodsAndArrows;
+ LastPeriodOrArrow = CurrentToken;
+ }
+ AnnotatedToken *TheToken = CurrentToken;
+ if (!consumeToken())
+ return LT_Invalid;
+ if (getPrecedence(*TheToken) > prec::Assignment &&
+ TheToken->Type == TT_BinaryOperator)
+ CanBeBuilderTypeStmt = false;
+ }
+ if (KeywordVirtualFound)
+ return LT_VirtualFunctionDecl;
+
+ // Assume a builder-type call if there are 2 or more "." and "->".
+ if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt) {
+ LastPeriodOrArrow->LastInChainOfCalls = true;
+ return LT_BuilderTypeCall;
+ }
+
+ if (Line.First.Type == TT_ObjCMethodSpecifier) {
+ if (Contexts.back().FirstObjCSelectorName != NULL)
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
+ Contexts.back().LongestObjCSelectorName;
+ return LT_ObjCMethodDecl;
+ }
+
+ return LT_Other;
+ }
+
+private:
+ void next() {
+ if (CurrentToken != NULL) {
+ determineTokenType(*CurrentToken);
+ CurrentToken->BindingStrength = Contexts.back().BindingStrength;
+ }
+
+ if (CurrentToken != NULL && !CurrentToken->Children.empty())
+ CurrentToken = &CurrentToken->Children[0];
+ else
+ 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 != NULL)
+ CurrentToken->Type = TT_Unknown;
+ }
+
+ /// \brief A struct to hold information valid in a specific context, e.g.
+ /// a pair of parenthesis.
+ struct Context {
+ Context(tok::TokenKind ContextKind, unsigned BindingStrength,
+ bool IsExpression)
+ : ContextKind(ContextKind), BindingStrength(BindingStrength),
+ LongestObjCSelectorName(0), ColonIsForRangeExpr(false),
+ ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),
+ FirstStartOfName(NULL), IsExpression(IsExpression),
+ CanBeExpression(true) {}
+
+ tok::TokenKind ContextKind;
+ unsigned BindingStrength;
+ unsigned LongestObjCSelectorName;
+ bool ColonIsForRangeExpr;
+ bool ColonIsObjCMethodExpr;
+ AnnotatedToken *FirstObjCSelectorName;
+ AnnotatedToken *FirstStartOfName;
+ bool IsExpression;
+ bool CanBeExpression;
+ };
+
+ /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
+ /// of each instance.
+ struct ScopedContextCreator {
+ AnnotatingParser &P;
+
+ ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind,
+ unsigned Increase)
+ : P(P) {
+ P.Contexts.push_back(
+ Context(ContextKind, P.Contexts.back().BindingStrength + Increase,
+ P.Contexts.back().IsExpression));
+ }
+
+ ~ScopedContextCreator() { P.Contexts.pop_back(); }
+ };
+
+ void determineTokenType(AnnotatedToken &Current) {
+ if (getPrecedence(Current) == prec::Assignment) {
+ Contexts.back().IsExpression = true;
+ for (AnnotatedToken *Previous = Current.Parent;
+ Previous && Previous->isNot(tok::comma);
+ Previous = Previous->Parent) {
+ if (Previous->is(tok::r_square))
+ 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 &&
+ (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) {
+ Contexts.back().IsExpression = true;
+ } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
+ for (AnnotatedToken *Previous = Current.Parent;
+ Previous && Previous->isOneOf(tok::star, tok::amp);
+ Previous = Previous->Parent)
+ Previous->Type = TT_PointerOrReference;
+ } else if (Current.Parent &&
+ Current.Parent->Type == TT_CtorInitializerColon) {
+ Contexts.back().IsExpression = true;
+ } else if (Current.is(tok::kw_new)) {
+ Contexts.back().CanBeExpression = false;
+ }
+
+ if (Current.Type == TT_Unknown) {
+ if (Current.Parent && Current.is(tok::identifier) &&
+ ((Current.Parent->is(tok::identifier) &&
+ Current.Parent->FormatTok.Tok.getIdentifierInfo()
+ ->getPPKeywordID() == tok::pp_not_keyword) ||
+ isSimpleTypeSpecifier(*Current.Parent) ||
+ Current.Parent->Type == TT_PointerOrReference ||
+ Current.Parent->Type == TT_TemplateCloser)) {
+ Contexts.back().FirstStartOfName = &Current;
+ Current.Type = TT_StartOfName;
+ } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
+ Current.Type =
+ determineStarAmpUsage(Current, Contexts.back().IsExpression);
+ } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
+ Current.Type = determinePlusMinusCaretUsage(Current);
+ } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
+ Current.Type = determineIncrementUsage(Current);
+ } else if (Current.is(tok::exclaim)) {
+ Current.Type = TT_UnaryOperator;
+ } else if (isBinaryOperator(Current)) {
+ Current.Type = TT_BinaryOperator;
+ } else if (Current.is(tok::comment)) {
+ std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
+ Lex.getLangOpts()));
+ if (StringRef(Data).startswith("//"))
+ Current.Type = TT_LineComment;
+ else
+ Current.Type = TT_BlockComment;
+ } else if (Current.is(tok::r_paren)) {
+ bool ParensNotExpr = !Current.Parent ||
+ Current.Parent->Type == TT_PointerOrReference ||
+ Current.Parent->Type == TT_TemplateCloser;
+ bool ParensCouldEndDecl =
+ !Current.Children.empty() &&
+ Current.Children[0].isOneOf(tok::equal, tok::semi, tok::l_brace);
+ bool IsSizeOfOrAlignOf =
+ Current.MatchingParen && Current.MatchingParen->Parent &&
+ Current.MatchingParen->Parent->isOneOf(tok::kw_sizeof,
+ tok::kw_alignof);
+ if (ParensNotExpr && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
+ Contexts.back().IsExpression)
+ // FIXME: We need to get smarter and understand more cases of casts.
+ Current.Type = TT_CastRParen;
+ } else if (Current.is(tok::at) && Current.Children.size()) {
+ switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ case tok::objc_protocol:
+ Current.Type = TT_ObjCDecl;
+ break;
+ case tok::objc_property:
+ Current.Type = TT_ObjCProperty;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /// \brief Return the type of the given token assuming it is * or &.
+ TokenType
+ determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
+ const AnnotatedToken *PrevToken = getPreviousToken(Tok);
+ if (PrevToken == NULL)
+ return TT_UnaryOperator;
+
+ const AnnotatedToken *NextToken = getNextToken(Tok);
+ if (NextToken == NULL)
+ return TT_Unknown;
+
+ if (PrevToken->is(tok::l_paren) && !IsExpression)
+ return TT_PointerOrReference;
+
+ if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
+ tok::comma, tok::semi, tok::kw_return, tok::colon,
+ tok::equal) ||
+ PrevToken->Type == TT_BinaryOperator ||
+ PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
+ return TT_UnaryOperator;
+
+ if (NextToken->is(tok::l_square))
+ return TT_PointerOrReference;
+
+ if (PrevToken->FormatTok.Tok.isLiteral() ||
+ PrevToken->isOneOf(tok::r_paren, tok::r_square) ||
+ NextToken->FormatTok.Tok.isLiteral() || isUnaryOperator(*NextToken))
+ return TT_BinaryOperator;
+
+ // It is very unlikely that we are going to find a pointer or reference type
+ // definition on the RHS of an assignment.
+ if (IsExpression)
+ return TT_BinaryOperator;
+
+ return TT_PointerOrReference;
+ }
+
+ TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
+ const AnnotatedToken *PrevToken = getPreviousToken(Tok);
+ if (PrevToken == NULL)
+ return TT_UnaryOperator;
+
+ // Use heuristics to recognize unary operators.
+ if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square,
+ tok::question, tok::colon, tok::kw_return,
+ tok::kw_case, tok::at, tok::l_brace))
+ return TT_UnaryOperator;
+
+ // There can't be two consecutive binary operators.
+ if (PrevToken->Type == TT_BinaryOperator)
+ return TT_UnaryOperator;
+
+ // Fall back to marking the token as binary operator.
+ return TT_BinaryOperator;
+ }
+
+ /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
+ TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
+ const AnnotatedToken *PrevToken = getPreviousToken(Tok);
+ if (PrevToken == NULL)
+ return TT_UnaryOperator;
+ if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
+ return TT_TrailingUnaryOperator;
+
+ 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 AnnotatedToken &Tok) const {
+ switch (Tok.FormatTok.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:
+ return true;
+ case tok::annot_typename:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_typeof:
+ case tok::kw_decltype:
+ return Lex.getLangOpts().CPlusPlus;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ SmallVector<Context, 8> Contexts;
+
+ SourceManager &SourceMgr;
+ Lexer &Lex;
+ AnnotatedLine &Line;
+ AnnotatedToken *CurrentToken;
+ bool KeywordVirtualFound;
+ IdentifierInfo &Ident_in;
+};
+
+/// \brief Parses binary expressions by inserting fake parenthesis based on
+/// operator precedence.
+class ExpressionParser {
+public:
+ ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {}
+
+ /// \brief Parse expressions with the given operatore precedence.
+ void parse(int Precedence = 0) {
+ if (Precedence > prec::PointerToMember || Current == NULL)
+ return;
+
+ // Skip over "return" until we can properly parse it.
+ if (Current->is(tok::kw_return))
+ next();
+
+ // Eagerly consume trailing comments.
+ while (isTrailingComment(Current)) {
+ next();
+ }
+
+ AnnotatedToken *Start = Current;
+ bool OperatorFound = false;
+
+ while (Current) {
+ // Consume operators with higher precedence.
+ parse(prec::Level(Precedence + 1));
+
+ int CurrentPrecedence = 0;
+ if (Current) {
+ if (Current->Type == TT_ConditionalExpr)
+ CurrentPrecedence = 1 + (int) prec::Conditional;
+ else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
+ Current->Type == TT_CtorInitializerColon)
+ CurrentPrecedence = 1;
+ else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
+ CurrentPrecedence = 1 + (int) getPrecedence(*Current);
+ }
+
+ // At the end of the line or when an operator with higher precedence is
+ // found, insert fake parenthesis and return.
+ if (Current == NULL || closesScope(*Current) ||
+ (CurrentPrecedence != 0 && CurrentPrecedence < Precedence)) {
+ if (OperatorFound) {
+ ++Start->FakeLParens;
+ if (Current)
+ ++Current->Parent->FakeRParens;
+ }
+ return;
+ }
+
+ // Consume scopes: (), [], <> and {}
+ if (opensScope(*Current)) {
+ AnnotatedToken *Left = Current;
+ while (Current && !closesScope(*Current)) {
+ next();
+ parse();
+ }
+ // Remove fake parens that just duplicate the real parens.
+ if (Current && Left->Children[0].FakeLParens > 0 &&
+ Current->Parent->FakeRParens > 0) {
+ --Left->Children[0].FakeLParens;
+ --Current->Parent->FakeRParens;
+ }
+ next();
+ } else {
+ // Operator found.
+ if (CurrentPrecedence == Precedence)
+ OperatorFound = true;
+
+ next();
+ }
+ }
+ }
+
+private:
+ void next() {
+ if (Current != NULL)
+ Current = Current->Children.empty() ? NULL : &Current->Children[0];
+ }
+
+ AnnotatedToken *Current;
+};
+
+void TokenAnnotator::annotate(AnnotatedLine &Line) {
+ AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in);
+ Line.Type = Parser.parseLine();
+ if (Line.Type == LT_Invalid)
+ return;
+
+ ExpressionParser ExprParser(Line);
+ ExprParser.parse();
+
+ if (Line.First.Type == TT_ObjCMethodSpecifier)
+ Line.Type = LT_ObjCMethodDecl;
+ else if (Line.First.Type == TT_ObjCDecl)
+ Line.Type = LT_ObjCDecl;
+ else if (Line.First.Type == TT_ObjCProperty)
+ Line.Type = LT_ObjCProperty;
+
+ Line.First.SpacesRequiredBefore = 1;
+ Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
+ Line.First.CanBreakBefore = Line.First.MustBreakBefore;
+
+ Line.First.TotalLength = Line.First.FormatTok.TokenLength;
+}
+
+void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
+ if (Line.First.Children.empty())
+ return;
+ AnnotatedToken *Current = &Line.First.Children[0];
+ while (Current != NULL) {
+ if (Current->Type == TT_LineComment)
+ Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
+ else
+ Current->SpacesRequiredBefore =
+ spaceRequiredBefore(Line, *Current) ? 1 : 0;
+
+ if (Current->FormatTok.MustBreakBefore) {
+ Current->MustBreakBefore = true;
+ } else if (Current->Type == TT_LineComment) {
+ Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0;
+ } else if (isTrailingComment(Current->Parent) ||
+ (Current->is(tok::string_literal) &&
+ Current->Parent->is(tok::string_literal))) {
+ Current->MustBreakBefore = true;
+ } else if (Current->is(tok::lessless) && !Current->Children.empty() &&
+ Current->Parent->is(tok::string_literal) &&
+ Current->Children[0].is(tok::string_literal)) {
+ Current->MustBreakBefore = true;
+ } else {
+ Current->MustBreakBefore = false;
+ }
+ Current->CanBreakBefore =
+ Current->MustBreakBefore || canBreakBefore(Line, *Current);
+ if (Current->MustBreakBefore)
+ Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit;
+ else
+ Current->TotalLength =
+ Current->Parent->TotalLength + Current->FormatTok.TokenLength +
+ Current->SpacesRequiredBefore;
+ // FIXME: Only calculate this if CanBreakBefore is true once static
+ // initializers etc. are sorted out.
+ // FIXME: Move magic numbers to a better place.
+ Current->SplitPenalty =
+ 20 * Current->BindingStrength + splitPenalty(Line, *Current);
+
+ Current = Current->Children.empty() ? NULL : &Current->Children[0];
+ }
+}
+
+unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
+ const AnnotatedToken &Tok) {
+ const AnnotatedToken &Left = *Tok.Parent;
+ const AnnotatedToken &Right = Tok;
+
+ if (Right.Type == TT_StartOfName) {
+ if (Line.First.is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
+ return 3;
+ else if (Line.MightBeFunctionDecl && Right.BindingStrength == 1)
+ // FIXME: Clean up hack of using BindingStrength to find top-level names.
+ return Style.PenaltyReturnTypeOnItsOwnLine;
+ else
+ return 100;
+ }
+ if (Left.is(tok::equal) && Right.is(tok::l_brace))
+ return 150;
+ if (Left.is(tok::coloncolon))
+ return 500;
+
+ if (Left.Type == TT_RangeBasedForLoopColon ||
+ Left.Type == TT_InheritanceColon)
+ return 2;
+
+ if (Right.isOneOf(tok::arrow, tok::period)) {
+ if (Line.Type == LT_BuilderTypeCall)
+ return prec::PointerToMember;
+ if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
+ Left.MatchingParen->ParameterCount > 0)
+ return 20; // Should be smaller than breaking at a nested comma.
+ return 150;
+ }
+
+ // In for-loops, prefer breaking at ',' and ';'.
+ if (Line.First.is(tok::kw_for) && Left.is(tok::equal))
+ return 4;
+
+ if (Left.is(tok::semi))
+ return 0;
+ if (Left.is(tok::comma))
+ return 1;
+
+ // In Objective-C method expressions, prefer breaking before "param:" over
+ // breaking after it.
+ if (Right.Type == TT_ObjCSelectorName)
+ return 0;
+ if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ return 20;
+
+ if (opensScope(Left))
+ return Left.ParameterCount > 1 ? prec::Comma : 20;
+
+ if (Right.is(tok::lessless)) {
+ if (Left.is(tok::string_literal)) {
+ StringRef Content = StringRef(Left.FormatTok.Tok.getLiteralData(),
+ Left.FormatTok.TokenLength);
+ Content = Content.drop_back(1).drop_front(1).trim();
+ if (Content.size() > 1 &&
+ (Content.back() == ':' || Content.back() == '='))
+ return 100;
+ }
+ return prec::Shift;
+ }
+ if (Left.Type == TT_ConditionalExpr)
+ return prec::Conditional;
+ prec::Level Level = getPrecedence(Left);
+
+ if (Level != prec::Unknown)
+ return Level;
+
+ return 3;
+}
+
+bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
+ const AnnotatedToken &Left,
+ const AnnotatedToken &Right) {
+ if (Right.is(tok::hashhash))
+ return Left.is(tok::hash);
+ if (Left.isOneOf(tok::hashhash, tok::hash))
+ return Right.is(tok::hash);
+ if (Right.isOneOf(tok::r_paren, tok::semi, tok::comma))
+ return false;
+ if (Right.is(tok::less) &&
+ (Left.is(tok::kw_template) ||
+ (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
+ return true;
+ if (Left.is(tok::arrow) || Right.is(tok::arrow))
+ return false;
+ if (Left.isOneOf(tok::exclaim, tok::tilde))
+ return false;
+ if (Left.is(tok::at) &&
+ Right.isOneOf(tok::identifier, tok::string_literal, tok::char_constant,
+ tok::numeric_constant, tok::l_paren, tok::l_brace,
+ tok::kw_true, tok::kw_false))
+ return false;
+ if (Left.is(tok::coloncolon))
+ return false;
+ if (Right.is(tok::coloncolon))
+ return !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren);
+ if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less))
+ return false;
+ if (Right.Type == TT_PointerOrReference)
+ return Left.FormatTok.Tok.isLiteral() ||
+ ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
+ !Style.PointerBindsToType);
+ if (Left.Type == TT_PointerOrReference)
+ return Right.FormatTok.Tok.isLiteral() ||
+ ((Right.Type != TT_PointerOrReference) &&
+ Right.isNot(tok::l_paren) && Style.PointerBindsToType &&
+ Left.Parent && Left.Parent->isNot(tok::l_paren));
+ if (Right.is(tok::star) && Left.is(tok::l_paren))
+ return false;
+ if (Left.is(tok::l_square))
+ return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
+ if (Right.is(tok::r_square))
+ return Right.Type == TT_ObjCArrayLiteral;
+ if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
+ return false;
+ if (Left.is(tok::period) || Right.is(tok::period))
+ return false;
+ if (Left.is(tok::colon))
+ return Left.Type != TT_ObjCMethodExpr;
+ if (Right.is(tok::colon))
+ return Right.Type != TT_ObjCMethodExpr;
+ if (Left.is(tok::l_paren))
+ return false;
+ if (Right.is(tok::l_paren)) {
+ return Line.Type == LT_ObjCDecl ||
+ Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
+ tok::kw_return, tok::kw_catch, tok::kw_new,
+ tok::kw_delete);
+ }
+ if (Left.is(tok::at) &&
+ Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
+ return false;
+ if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
+ return false;
+ return true;
+}
+
+bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
+ const AnnotatedToken &Tok) {
+ if (Tok.FormatTok.Tok.getIdentifierInfo() &&
+ Tok.Parent->FormatTok.Tok.getIdentifierInfo())
+ return true; // Never ever merge two identifiers.
+ if (Line.Type == LT_ObjCMethodDecl) {
+ if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
+ return true;
+ if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
+ // Don't space between ')' and <id>
+ return false;
+ }
+ if (Line.Type == LT_ObjCProperty &&
+ (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
+ return false;
+
+ if (Tok.Parent->is(tok::comma))
+ return true;
+ if (Tok.is(tok::comma))
+ return false;
+ if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
+ return true;
+ if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator))
+ return false;
+ if (Tok.Type == TT_OverloadedOperatorLParen)
+ return false;
+ if (Tok.is(tok::colon))
+ return !Line.First.isOneOf(tok::kw_case, tok::kw_default) &&
+ !Tok.Children.empty() && Tok.Type != TT_ObjCMethodExpr;
+ if (Tok.is(tok::l_paren) && !Tok.Children.empty() &&
+ Tok.Children[0].Type == TT_PointerOrReference &&
+ !Tok.Children[0].Children.empty() &&
+ Tok.Children[0].Children[0].isNot(tok::r_paren) &&
+ Tok.Parent->isNot(tok::l_paren) &&
+ (Tok.Parent->Type != TT_PointerOrReference || Style.PointerBindsToType))
+ return true;
+ if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
+ return false;
+ if (Tok.Type == TT_UnaryOperator)
+ return !Tok.Parent->isOneOf(tok::l_paren, tok::l_square, tok::at) &&
+ (Tok.Parent->isNot(tok::colon) ||
+ Tok.Parent->Type != TT_ObjCMethodExpr);
+ if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
+ return Tok.Type == TT_TemplateCloser &&
+ Tok.Parent->Type == TT_TemplateCloser &&
+ Style.Standard != FormatStyle::LS_Cpp11;
+ }
+ if (Tok.isOneOf(tok::arrowstar, tok::periodstar) ||
+ Tok.Parent->isOneOf(tok::arrowstar, tok::periodstar))
+ return false;
+ if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
+ return true;
+ if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
+ return false;
+ if (Tok.is(tok::less) && Line.First.is(tok::hash))
+ return true;
+ if (Tok.Type == TT_TrailingUnaryOperator)
+ return false;
+ return spaceRequiredBetween(Line, *Tok.Parent, Tok);
+}
+
+bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
+ const AnnotatedToken &Right) {
+ const AnnotatedToken &Left = *Right.Parent;
+ if (Right.Type == TT_StartOfName)
+ return true;
+ if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+ return false;
+ if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ return true;
+ if (Right.Type == TT_ObjCSelectorName)
+ return true;
+ if (Left.ClosesTemplateDeclaration)
+ return true;
+ if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
+ return true;
+ if (Right.Type == TT_RangeBasedForLoopColon ||
+ Right.Type == TT_InheritanceColon)
+ return false;
+ if (Left.Type == TT_RangeBasedForLoopColon ||
+ Left.Type == TT_InheritanceColon)
+ return true;
+ if (Right.Type == TT_RangeBasedForLoopColon)
+ return false;
+ if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
+ Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
+ Left.isOneOf(tok::question, tok::kw_operator))
+ return false;
+ if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
+ return false;
+ if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && Left.Parent &&
+ Left.Parent->is(tok::kw___attribute))
+ return false;
+
+ if (Right.Type == TT_LineComment)
+ // We rely on MustBreakBefore being set correctly here as we should not
+ // change the "binding" behavior of a comment.
+ return false;
+
+ // 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.Parent != NULL &&
+ Left.Parent->is(tok::r_paren))
+ return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal);
+
+ if (Right.is(tok::kw___attribute))
+ return true;
+
+ // We only break before r_brace if there was a corresponding break before
+ // the l_brace, which is tracked by BreakBeforeClosingBrace.
+ if (Right.isOneOf(tok::r_brace, tok::r_paren, tok::greater))
+ return false;
+ if (Left.is(tok::identifier) && Right.is(tok::string_literal))
+ return true;
+ return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
+ Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace) ||
+ Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) ||
+ (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
+ Right.isOneOf(tok::identifier, tok::kw___attribute)) ||
+ (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
+ (Left.is(tok::l_square) && !Right.is(tok::r_square));
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
new file mode 100644
index 000000000000..c41ee33c439b
--- /dev/null
+++ b/lib/Format/TokenAnnotator.h
@@ -0,0 +1,262 @@
+//===--- TokenAnnotator.h - Format C++ code ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a token annotator, i.e. creates
+/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
+#define LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
+
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Format/Format.h"
+#include <string>
+
+namespace clang {
+class Lexer;
+class SourceManager;
+
+namespace format {
+
+enum TokenType {
+ TT_BinaryOperator,
+ TT_BlockComment,
+ TT_CastRParen,
+ TT_ConditionalExpr,
+ TT_CtorInitializerColon,
+ TT_ImplicitStringLiteral,
+ TT_InlineASMColon,
+ TT_InheritanceColon,
+ TT_LineComment,
+ TT_ObjCArrayLiteral,
+ TT_ObjCBlockLParen,
+ TT_ObjCDecl,
+ TT_ObjCForIn,
+ TT_ObjCMethodExpr,
+ TT_ObjCMethodSpecifier,
+ TT_ObjCProperty,
+ TT_ObjCSelectorName,
+ TT_OverloadedOperatorLParen,
+ TT_PointerOrReference,
+ TT_PureVirtualSpecifier,
+ TT_RangeBasedForLoopColon,
+ TT_StartOfName,
+ TT_TemplateCloser,
+ TT_TemplateOpener,
+ TT_TrailingUnaryOperator,
+ TT_UnaryOperator,
+ TT_Unknown
+};
+
+enum LineType {
+ LT_Invalid,
+ LT_Other,
+ LT_BuilderTypeCall,
+ LT_PreprocessorDirective,
+ LT_VirtualFunctionDecl,
+ LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
+ LT_ObjCMethodDecl,
+ LT_ObjCProperty // An @property line.
+};
+
+class AnnotatedToken {
+public:
+ explicit AnnotatedToken(const FormatToken &FormatTok)
+ : FormatTok(FormatTok), Type(TT_Unknown), SpacesRequiredBefore(0),
+ CanBreakBefore(false), MustBreakBefore(false),
+ ClosesTemplateDeclaration(false), MatchingParen(NULL),
+ ParameterCount(0), BindingStrength(0), SplitPenalty(0),
+ LongestObjCSelectorName(0), Parent(NULL), FakeLParens(0),
+ FakeRParens(0), LastInChainOfCalls(false),
+ PartOfMultiVariableDeclStmt(false) {}
+
+ bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
+ return is(K1) || is(K2);
+ }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
+ return is(K1) || is(K2) || is(K3);
+ }
+
+ bool isOneOf(
+ tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
+ tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
+ tok::TokenKind K6 = tok::NUM_TOKENS, tok::TokenKind K7 = tok::NUM_TOKENS,
+ tok::TokenKind K8 = tok::NUM_TOKENS, tok::TokenKind K9 = tok::NUM_TOKENS,
+ tok::TokenKind K10 = tok::NUM_TOKENS,
+ tok::TokenKind K11 = tok::NUM_TOKENS,
+ tok::TokenKind K12 = tok::NUM_TOKENS) const {
+ return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
+ is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
+ }
+
+ bool isNot(tok::TokenKind Kind) const { return FormatTok.Tok.isNot(Kind); }
+
+ bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
+ return FormatTok.Tok.isObjCAtKeyword(Kind);
+ }
+
+ bool isAccessSpecifier(bool ColonRequired = true) const {
+ return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) &&
+ (!ColonRequired ||
+ (!Children.empty() && Children[0].is(tok::colon)));
+ }
+
+ bool isObjCAccessSpecifier() const {
+ return is(tok::at) && !Children.empty() &&
+ (Children[0].isObjCAtKeyword(tok::objc_public) ||
+ Children[0].isObjCAtKeyword(tok::objc_protected) ||
+ Children[0].isObjCAtKeyword(tok::objc_package) ||
+ Children[0].isObjCAtKeyword(tok::objc_private));
+ }
+
+ FormatToken FormatTok;
+
+ TokenType Type;
+
+ unsigned SpacesRequiredBefore;
+ bool CanBreakBefore;
+ bool MustBreakBefore;
+
+ bool ClosesTemplateDeclaration;
+
+ AnnotatedToken *MatchingParen;
+
+ /// \brief Number of parameters, if this is "(", "[" or "<".
+ ///
+ /// This is initialized to 1 as we don't need to distinguish functions with
+ /// 0 parameters from functions with 1 parameter. Thus, we can simply count
+ /// the number of commas.
+ unsigned ParameterCount;
+
+ /// \brief The total length of the line up to and including this token.
+ unsigned TotalLength;
+
+ // FIXME: Come up with a 'cleaner' concept.
+ /// \brief The binding strength of a token. This is a combined value of
+ /// operator precedence, parenthesis nesting, etc.
+ unsigned BindingStrength;
+
+ /// \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.
+ unsigned LongestObjCSelectorName;
+
+ std::vector<AnnotatedToken> Children;
+ AnnotatedToken *Parent;
+
+ /// \brief Insert this many fake ( before this token for correct indentation.
+ unsigned FakeLParens;
+ /// \brief Insert this many fake ) after this token for correct indentation.
+ unsigned FakeRParens;
+
+ /// \brief Is this the last "." or "->" in a builder-type call?
+ bool LastInChainOfCalls;
+
+ /// \brief Is this token part of a \c DeclStmt defining multiple variables?
+ ///
+ /// Only set if \c Type == \c TT_StartOfName.
+ bool PartOfMultiVariableDeclStmt;
+
+ const AnnotatedToken *getPreviousNoneComment() const {
+ AnnotatedToken *Tok = Parent;
+ while (Tok != NULL && Tok->is(tok::comment))
+ Tok = Tok->Parent;
+ return Tok;
+ }
+};
+
+class AnnotatedLine {
+public:
+ AnnotatedLine(const UnwrappedLine &Line)
+ : First(Line.Tokens.front()), Level(Line.Level),
+ InPPDirective(Line.InPPDirective),
+ MustBeDeclaration(Line.MustBeDeclaration),
+ MightBeFunctionDecl(false) {
+ assert(!Line.Tokens.empty());
+ AnnotatedToken *Current = &First;
+ for (std::list<FormatToken>::const_iterator I = ++Line.Tokens.begin(),
+ E = Line.Tokens.end();
+ I != E; ++I) {
+ Current->Children.push_back(AnnotatedToken(*I));
+ Current->Children[0].Parent = Current;
+ Current = &Current->Children[0];
+ }
+ Last = Current;
+ }
+ AnnotatedLine(const AnnotatedLine &Other)
+ : First(Other.First), Type(Other.Type), Level(Other.Level),
+ InPPDirective(Other.InPPDirective),
+ MustBeDeclaration(Other.MustBeDeclaration),
+ MightBeFunctionDecl(Other.MightBeFunctionDecl) {
+ Last = &First;
+ while (!Last->Children.empty()) {
+ Last->Children[0].Parent = Last;
+ Last = &Last->Children[0];
+ }
+ }
+
+ AnnotatedToken First;
+ AnnotatedToken *Last;
+
+ LineType Type;
+ unsigned Level;
+ bool InPPDirective;
+ bool MustBeDeclaration;
+ bool MightBeFunctionDecl;
+};
+
+inline prec::Level getPrecedence(const AnnotatedToken &Tok) {
+ return getBinOpPrecedence(Tok.FormatTok.Tok.getKind(), true, true);
+}
+
+/// \brief Determines extra information about the tokens comprising an
+/// \c UnwrappedLine.
+class TokenAnnotator {
+public:
+ TokenAnnotator(const FormatStyle &Style, SourceManager &SourceMgr, Lexer &Lex,
+ IdentifierInfo &Ident_in)
+ : Style(Style), SourceMgr(SourceMgr), Lex(Lex), Ident_in(Ident_in) {
+ }
+
+ void annotate(AnnotatedLine &Line);
+ void calculateFormattingInformation(AnnotatedLine &Line);
+
+private:
+ /// \brief Calculate the penalty for splitting before \c Tok.
+ unsigned splitPenalty(const AnnotatedLine &Line, const AnnotatedToken &Tok);
+
+ bool spaceRequiredBetween(const AnnotatedLine &Line,
+ const AnnotatedToken &Left,
+ const AnnotatedToken &Right);
+
+ bool spaceRequiredBefore(const AnnotatedLine &Line,
+ const AnnotatedToken &Tok);
+
+ bool canBreakBefore(const AnnotatedLine &Line, const AnnotatedToken &Right);
+
+ const FormatStyle &Style;
+ SourceManager &SourceMgr;
+ Lexer &Lex;
+
+ // Contextual keywords:
+ IdentifierInfo &Ident_in;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
new file mode 100644
index 000000000000..89a391bd1928
--- /dev/null
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -0,0 +1,858 @@
+//===--- UnwrappedLineParser.cpp - Format C++ code ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the implementation of the UnwrappedLineParser,
+/// which turns a stream of tokens into UnwrappedLines.
+///
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-parser"
+
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/Debug.h"
+
+namespace clang {
+namespace format {
+
+class ScopedDeclarationState {
+public:
+ ScopedDeclarationState(UnwrappedLine &Line, std::vector<bool> &Stack,
+ bool MustBeDeclaration)
+ : Line(Line), Stack(Stack) {
+ Line.MustBeDeclaration = MustBeDeclaration;
+ Stack.push_back(MustBeDeclaration);
+ }
+ ~ScopedDeclarationState() {
+ Stack.pop_back();
+ if (!Stack.empty())
+ Line.MustBeDeclaration = Stack.back();
+ else
+ Line.MustBeDeclaration = true;
+ }
+private:
+ UnwrappedLine &Line;
+ std::vector<bool> &Stack;
+};
+
+class ScopedMacroState : public FormatTokenSource {
+public:
+ ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
+ FormatToken &ResetToken)
+ : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
+ PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource) {
+ TokenSource = this;
+ Line.Level = 0;
+ Line.InPPDirective = true;
+ }
+
+ ~ScopedMacroState() {
+ TokenSource = PreviousTokenSource;
+ ResetToken = Token;
+ Line.InPPDirective = false;
+ Line.Level = PreviousLineLevel;
+ }
+
+ virtual FormatToken getNextToken() {
+ // The \c UnwrappedLineParser guards against this by never calling
+ // \c getNextToken() after it has encountered the first eof token.
+ assert(!eof());
+ Token = PreviousTokenSource->getNextToken();
+ if (eof())
+ return createEOF();
+ return Token;
+ }
+
+private:
+ bool eof() { return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline; }
+
+ FormatToken createEOF() {
+ FormatToken FormatTok;
+ FormatTok.Tok.startToken();
+ FormatTok.Tok.setKind(tok::eof);
+ return FormatTok;
+ }
+
+ UnwrappedLine &Line;
+ FormatTokenSource *&TokenSource;
+ FormatToken &ResetToken;
+ unsigned PreviousLineLevel;
+ FormatTokenSource *PreviousTokenSource;
+
+ FormatToken Token;
+};
+
+class ScopedLineState {
+public:
+ ScopedLineState(UnwrappedLineParser &Parser,
+ bool SwitchToPreprocessorLines = false)
+ : Parser(Parser), SwitchToPreprocessorLines(SwitchToPreprocessorLines) {
+ if (SwitchToPreprocessorLines)
+ Parser.CurrentLines = &Parser.PreprocessorDirectives;
+ PreBlockLine = Parser.Line.take();
+ Parser.Line.reset(new UnwrappedLine());
+ Parser.Line->Level = PreBlockLine->Level;
+ Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
+ }
+
+ ~ScopedLineState() {
+ if (!Parser.Line->Tokens.empty()) {
+ Parser.addUnwrappedLine();
+ }
+ assert(Parser.Line->Tokens.empty());
+ Parser.Line.reset(PreBlockLine);
+ Parser.MustBreakBeforeNextToken = true;
+ if (SwitchToPreprocessorLines)
+ Parser.CurrentLines = &Parser.Lines;
+ }
+
+private:
+ UnwrappedLineParser &Parser;
+ const bool SwitchToPreprocessorLines;
+
+ UnwrappedLine *PreBlockLine;
+};
+
+UnwrappedLineParser::UnwrappedLineParser(
+ clang::DiagnosticsEngine &Diag, const FormatStyle &Style,
+ FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback)
+ : Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
+ CurrentLines(&Lines), Diag(Diag), Style(Style), Tokens(&Tokens),
+ Callback(Callback) {}
+
+bool UnwrappedLineParser::parse() {
+ DEBUG(llvm::dbgs() << "----\n");
+ readToken();
+ bool Error = parseFile();
+ for (std::vector<UnwrappedLine>::iterator I = Lines.begin(), E = Lines.end();
+ I != E; ++I) {
+ Callback.consumeUnwrappedLine(*I);
+ }
+
+ // Create line with eof token.
+ pushToken(FormatTok);
+ Callback.consumeUnwrappedLine(*Line);
+
+ return Error;
+}
+
+bool UnwrappedLineParser::parseFile() {
+ ScopedDeclarationState DeclarationState(
+ *Line, DeclarationScopeStack,
+ /*MustBeDeclaration=*/ !Line->InPPDirective);
+ bool Error = parseLevel(/*HasOpeningBrace=*/ false);
+ // Make sure to format the remaining tokens.
+ flushComments(true);
+ addUnwrappedLine();
+ return Error;
+}
+
+bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
+ bool Error = false;
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::comment:
+ nextToken();
+ addUnwrappedLine();
+ break;
+ case tok::l_brace:
+ // FIXME: Add parameter whether this can happen - if this happens, we must
+ // be in a non-declaration context.
+ Error |= parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ break;
+ case tok::r_brace:
+ if (HasOpeningBrace) {
+ return false;
+ } else {
+ Diag.Report(FormatTok.Tok.getLocation(),
+ Diag.getCustomDiagID(clang::DiagnosticsEngine::Error,
+ "unexpected '}'"));
+ Error = true;
+ nextToken();
+ addUnwrappedLine();
+ }
+ break;
+ default:
+ parseStructuralElement();
+ break;
+ }
+ } while (!eof());
+ return Error;
+}
+
+bool UnwrappedLineParser::parseBlock(bool MustBeDeclaration,
+ unsigned AddLevels) {
+ assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
+ nextToken();
+
+ addUnwrappedLine();
+
+ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+ MustBeDeclaration);
+ Line->Level += AddLevels;
+ parseLevel(/*HasOpeningBrace=*/ true);
+
+ if (!FormatTok.Tok.is(tok::r_brace)) {
+ Line->Level -= AddLevels;
+ return true;
+ }
+
+ nextToken(); // Munch the closing brace.
+ Line->Level -= AddLevels;
+ return false;
+}
+
+void UnwrappedLineParser::parsePPDirective() {
+ assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
+ ScopedMacroState MacroState(*Line, Tokens, FormatTok);
+ nextToken();
+
+ if (FormatTok.Tok.getIdentifierInfo() == NULL) {
+ parsePPUnknown();
+ return;
+ }
+
+ switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_define:
+ parsePPDefine();
+ break;
+ default:
+ parsePPUnknown();
+ break;
+ }
+}
+
+void UnwrappedLineParser::parsePPDefine() {
+ nextToken();
+
+ if (FormatTok.Tok.getKind() != tok::identifier) {
+ parsePPUnknown();
+ return;
+ }
+ nextToken();
+ if (FormatTok.Tok.getKind() == tok::l_paren &&
+ FormatTok.WhiteSpaceLength == 0) {
+ parseParens();
+ }
+ addUnwrappedLine();
+ Line->Level = 1;
+
+ // Errors during a preprocessor directive can only affect the layout of the
+ // preprocessor directive, and thus we ignore them. An alternative approach
+ // would be to use the same approach we use on the file level (no
+ // re-indentation if there was a structural error) within the macro
+ // definition.
+ parseFile();
+}
+
+void UnwrappedLineParser::parsePPUnknown() {
+ do {
+ nextToken();
+ } while (!eof());
+ addUnwrappedLine();
+}
+
+void UnwrappedLineParser::parseStructuralElement() {
+ assert(!FormatTok.Tok.is(tok::l_brace));
+ int TokenNumber = 0;
+ switch (FormatTok.Tok.getKind()) {
+ case tok::at:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBracedList();
+ break;
+ }
+ switch (FormatTok.Tok.getObjCKeywordID()) {
+ case tok::objc_public:
+ case tok::objc_protected:
+ case tok::objc_package:
+ case tok::objc_private:
+ return parseAccessSpecifier();
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ return parseObjCInterfaceOrImplementation();
+ case tok::objc_protocol:
+ return parseObjCProtocol();
+ case tok::objc_end:
+ return; // Handled by the caller.
+ case tok::objc_optional:
+ case tok::objc_required:
+ nextToken();
+ addUnwrappedLine();
+ return;
+ default:
+ break;
+ }
+ break;
+ case tok::kw_namespace:
+ parseNamespace();
+ return;
+ case tok::kw_inline:
+ nextToken();
+ TokenNumber++;
+ if (FormatTok.Tok.is(tok::kw_namespace)) {
+ parseNamespace();
+ return;
+ }
+ break;
+ case tok::kw_public:
+ case tok::kw_protected:
+ case tok::kw_private:
+ parseAccessSpecifier();
+ return;
+ case tok::kw_if:
+ parseIfThenElse();
+ return;
+ case tok::kw_for:
+ case tok::kw_while:
+ parseForOrWhileLoop();
+ return;
+ case tok::kw_do:
+ parseDoWhile();
+ return;
+ case tok::kw_switch:
+ parseSwitch();
+ return;
+ case tok::kw_default:
+ nextToken();
+ parseLabel();
+ return;
+ case tok::kw_case:
+ parseCaseLabel();
+ return;
+ case tok::kw_return:
+ parseReturn();
+ return;
+ case tok::kw_extern:
+ nextToken();
+ if (FormatTok.Tok.is(tok::string_literal)) {
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ true, 0);
+ addUnwrappedLine();
+ return;
+ }
+ }
+ // In all other cases, parse the declaration.
+ break;
+ default:
+ break;
+ }
+ do {
+ ++TokenNumber;
+ switch (FormatTok.Tok.getKind()) {
+ case tok::at:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBracedList();
+ break;
+ case tok::kw_enum:
+ parseEnum();
+ break;
+ case tok::kw_struct:
+ case tok::kw_union:
+ case tok::kw_class:
+ parseRecord();
+ // A record declaration or definition is always the start of a structural
+ // element.
+ break;
+ case tok::semi:
+ nextToken();
+ addUnwrappedLine();
+ return;
+ case tok::r_brace:
+ addUnwrappedLine();
+ return;
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::l_brace:
+ // A block outside of parentheses must be the last part of a
+ // structural element.
+ // FIXME: Figure out cases where this is not true, and add projections for
+ // them (the one we know is missing are lambdas).
+ parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ return;
+ case tok::identifier:
+ nextToken();
+ if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
+ parseLabel();
+ return;
+ }
+ break;
+ case tok::equal:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBracedList();
+ }
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseBracedList() {
+ nextToken();
+
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_brace:
+ parseBracedList();
+ break;
+ case tok::r_brace:
+ nextToken();
+ return;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseReturn() {
+ nextToken();
+
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_brace:
+ parseBracedList();
+ break;
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_brace:
+ // Assume missing ';'.
+ addUnwrappedLine();
+ return;
+ case tok::semi:
+ nextToken();
+ addUnwrappedLine();
+ return;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseParens() {
+ assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
+ nextToken();
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_paren:
+ nextToken();
+ return;
+ case tok::l_brace: {
+ nextToken();
+ ScopedLineState LineState(*this);
+ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+ /*MustBeDeclaration=*/ false);
+ Line->Level += 1;
+ parseLevel(/*HasOpeningBrace=*/ true);
+ Line->Level -= 1;
+ break;
+ }
+ case tok::at:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBracedList();
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseIfThenElse() {
+ assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_paren))
+ parseParens();
+ bool NeedsUnwrappedLine = false;
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ NeedsUnwrappedLine = true;
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+ if (FormatTok.Tok.is(tok::kw_else)) {
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ } else if (FormatTok.Tok.is(tok::kw_if)) {
+ parseIfThenElse();
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+ } else if (NeedsUnwrappedLine) {
+ addUnwrappedLine();
+ }
+}
+
+void UnwrappedLineParser::parseNamespace() {
+ assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::identifier))
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ true, 0);
+ // Munch the semicolon after a namespace. This is more common than one would
+ // think. Puttin the semicolon into its own line is very ugly.
+ if (FormatTok.Tok.is(tok::semi))
+ nextToken();
+ addUnwrappedLine();
+ }
+ // FIXME: Add error handling.
+}
+
+void UnwrappedLineParser::parseForOrWhileLoop() {
+ assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
+ "'for' or 'while' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_paren))
+ parseParens();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+}
+
+void UnwrappedLineParser::parseDoWhile() {
+ assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+
+ // FIXME: Add error handling.
+ if (!FormatTok.Tok.is(tok::kw_while)) {
+ addUnwrappedLine();
+ return;
+ }
+
+ nextToken();
+ parseStructuralElement();
+}
+
+void UnwrappedLineParser::parseLabel() {
+ if (FormatTok.Tok.isNot(tok::colon))
+ return;
+ nextToken();
+ unsigned OldLineLevel = Line->Level;
+ if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
+ --Line->Level;
+ if (CommentsBeforeNextToken.empty() && FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ if (FormatTok.Tok.is(tok::kw_break))
+ parseStructuralElement(); // "break;" after "}" goes on the same line.
+ }
+ addUnwrappedLine();
+ Line->Level = OldLineLevel;
+}
+
+void UnwrappedLineParser::parseCaseLabel() {
+ assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
+ // FIXME: fix handling of complex expressions here.
+ do {
+ nextToken();
+ } while (!eof() && !FormatTok.Tok.is(tok::colon));
+ parseLabel();
+}
+
+void UnwrappedLineParser::parseSwitch() {
+ assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_paren))
+ parseParens();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false, Style.IndentCaseLabels ? 2 : 1);
+ addUnwrappedLine();
+ } else {
+ addUnwrappedLine();
+ Line->Level += (Style.IndentCaseLabels ? 2 : 1);
+ parseStructuralElement();
+ Line->Level -= (Style.IndentCaseLabels ? 2 : 1);
+ }
+}
+
+void UnwrappedLineParser::parseAccessSpecifier() {
+ nextToken();
+ // Otherwise, we don't know what it is, and we'd better keep the next token.
+ if (FormatTok.Tok.is(tok::colon))
+ nextToken();
+ addUnwrappedLine();
+}
+
+void UnwrappedLineParser::parseEnum() {
+ nextToken();
+ if (FormatTok.Tok.is(tok::identifier) ||
+ FormatTok.Tok.is(tok::kw___attribute) ||
+ FormatTok.Tok.is(tok::kw___declspec)) {
+ nextToken();
+ // We can have macros or attributes in between 'enum' and the enum name.
+ if (FormatTok.Tok.is(tok::l_paren)) {
+ parseParens();
+ }
+ if (FormatTok.Tok.is(tok::identifier))
+ nextToken();
+ }
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ nextToken();
+ addUnwrappedLine();
+ ++Line->Level;
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_brace:
+ addUnwrappedLine();
+ nextToken();
+ --Line->Level;
+ return;
+ case tok::comma:
+ nextToken();
+ addUnwrappedLine();
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+ }
+ // We fall through to parsing a structural element afterwards, so that in
+ // enum A {} n, m;
+ // "} n, m;" will end up in one unwrapped line.
+}
+
+void UnwrappedLineParser::parseRecord() {
+ nextToken();
+ if (FormatTok.Tok.is(tok::identifier) ||
+ FormatTok.Tok.is(tok::kw___attribute) ||
+ FormatTok.Tok.is(tok::kw___declspec)) {
+ nextToken();
+ // We can have macros or attributes in between 'class' and the class name.
+ if (FormatTok.Tok.is(tok::l_paren)) {
+ parseParens();
+ }
+ // The actual identifier can be a nested name specifier, and in macros
+ // it is often token-pasted.
+ while (FormatTok.Tok.is(tok::identifier) ||
+ FormatTok.Tok.is(tok::coloncolon) || FormatTok.Tok.is(tok::hashhash))
+ nextToken();
+
+ // Note that parsing away template declarations here leads to incorrectly
+ // accepting function declarations as record declarations.
+ // In general, we cannot solve this problem. Consider:
+ // class A<int> B() {}
+ // which can be a function definition or a class definition when B() is a
+ // macro. If we find enough real-world cases where this is a problem, we
+ // can parse for the 'template' keyword in the beginning of the statement,
+ // and thus rule out the record production in case there is no template
+ // (this would still leave us with an ambiguity between template function
+ // and class declarations).
+ if (FormatTok.Tok.is(tok::colon) || FormatTok.Tok.is(tok::less)) {
+ while (!eof() && FormatTok.Tok.isNot(tok::l_brace)) {
+ if (FormatTok.Tok.is(tok::semi))
+ return;
+ nextToken();
+ }
+ }
+ }
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBlock(/*MustBeDeclaration=*/ true);
+ // We fall through to parsing a structural element afterwards, so
+ // class A {} n, m;
+ // will end up in one unwrapped line.
+}
+
+void UnwrappedLineParser::parseObjCProtocolList() {
+ assert(FormatTok.Tok.is(tok::less) && "'<' expected.");
+ do
+ nextToken();
+ while (!eof() && FormatTok.Tok.isNot(tok::greater));
+ nextToken(); // Skip '>'.
+}
+
+void UnwrappedLineParser::parseObjCUntilAtEnd() {
+ do {
+ if (FormatTok.Tok.isObjCAtKeyword(tok::objc_end)) {
+ nextToken();
+ addUnwrappedLine();
+ break;
+ }
+ parseStructuralElement();
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
+ nextToken();
+ nextToken(); // interface name
+
+ // @interface can be followed by either a base class, or a category.
+ if (FormatTok.Tok.is(tok::colon)) {
+ nextToken();
+ nextToken(); // base class name
+ } else if (FormatTok.Tok.is(tok::l_paren))
+ // Skip category, if present.
+ parseParens();
+
+ 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))
+ parseBlock(/*MustBeDeclaration=*/ true);
+
+ // With instance variables, this puts '}' on its own line. Without instance
+ // variables, this ends the @interface line.
+ addUnwrappedLine();
+
+ parseObjCUntilAtEnd();
+}
+
+void UnwrappedLineParser::parseObjCProtocol() {
+ nextToken();
+ nextToken(); // protocol name
+
+ if (FormatTok.Tok.is(tok::less))
+ parseObjCProtocolList();
+
+ // Check for protocol declaration.
+ if (FormatTok.Tok.is(tok::semi)) {
+ nextToken();
+ return addUnwrappedLine();
+ }
+
+ addUnwrappedLine();
+ parseObjCUntilAtEnd();
+}
+
+void UnwrappedLineParser::addUnwrappedLine() {
+ if (Line->Tokens.empty())
+ return;
+ DEBUG({
+ llvm::dbgs() << "Line(" << Line->Level << ")"
+ << (Line->InPPDirective ? " MACRO" : "") << ": ";
+ for (std::list<FormatToken>::iterator I = Line->Tokens.begin(),
+ E = Line->Tokens.end();
+ I != E; ++I) {
+ llvm::dbgs() << I->Tok.getName() << " ";
+
+ }
+ llvm::dbgs() << "\n";
+ });
+ CurrentLines->push_back(*Line);
+ Line->Tokens.clear();
+ if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
+ for (std::vector<UnwrappedLine>::iterator
+ I = PreprocessorDirectives.begin(),
+ E = PreprocessorDirectives.end();
+ I != E; ++I) {
+ CurrentLines->push_back(*I);
+ }
+ PreprocessorDirectives.clear();
+ }
+}
+
+bool UnwrappedLineParser::eof() const { return FormatTok.Tok.is(tok::eof); }
+
+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) {
+ addUnwrappedLine();
+ }
+ pushToken(*I);
+ }
+ if (NewlineBeforeNext && JustComments) {
+ addUnwrappedLine();
+ }
+ CommentsBeforeNextToken.clear();
+}
+
+void UnwrappedLineParser::nextToken() {
+ if (eof())
+ return;
+ flushComments(FormatTok.NewlinesBefore > 0);
+ pushToken(FormatTok);
+ readToken();
+}
+
+void UnwrappedLineParser::readToken() {
+ bool CommentsInCurrentLine = true;
+ do {
+ FormatTok = Tokens->getNextToken();
+ while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
+ ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
+ FormatTok.IsFirst)) {
+ // If there is an unfinished unwrapped line, we flush the preprocessor
+ // directives only after that unwrapped line was finished later.
+ bool SwitchToPreprocessorLines =
+ !Line->Tokens.empty() && CurrentLines == &Lines;
+ ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
+ // 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);
+ parsePPDirective();
+ }
+ if (!FormatTok.Tok.is(tok::comment))
+ return;
+ if (FormatTok.NewlinesBefore > 0 || FormatTok.IsFirst) {
+ CommentsInCurrentLine = false;
+ }
+ if (CommentsInCurrentLine) {
+ pushToken(FormatTok);
+ } else {
+ CommentsBeforeNextToken.push_back(FormatTok);
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::pushToken(const FormatToken &Tok) {
+ Line->Tokens.push_back(Tok);
+ if (MustBreakBeforeNextToken) {
+ Line->Tokens.back().MustBreakBefore = true;
+ MustBreakBeforeNextToken = false;
+ }
+}
+
+} // end namespace format
+} // end namespace clang
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
new file mode 100644
index 000000000000..f4fecc5ef0ac
--- /dev/null
+++ b/lib/Format/UnwrappedLineParser.h
@@ -0,0 +1,201 @@
+//===--- UnwrappedLineParser.h - Format C++ code ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the declaration of the UnwrappedLineParser,
+/// which turns a stream of tokens into UnwrappedLines.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+#define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include <list>
+
+namespace clang {
+
+class DiagnosticsEngine;
+
+namespace format {
+
+/// \brief A wrapper around a \c Token storing information about the
+/// whitespace characters preceeding it.
+struct FormatToken {
+ FormatToken()
+ : NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
+ LastNewlineOffset(0), TokenLength(0), IsFirst(false),
+ MustBreakBefore(false) {}
+
+ /// \brief The \c Token.
+ Token Tok;
+
+ /// \brief The number of newlines immediately before the \c Token.
+ ///
+ /// This can be used to determine what the user wrote in the original code
+ /// and thereby e.g. leave an empty line between two function definitions.
+ unsigned NewlinesBefore;
+
+ /// \brief Whether there is at least one unescaped newline before the \c
+ /// Token.
+ bool HasUnescapedNewline;
+
+ /// \brief The location of the start of the whitespace immediately preceeding
+ /// the \c Token.
+ ///
+ /// Used together with \c WhiteSpaceLength to create a \c Replacement.
+ SourceLocation WhiteSpaceStart;
+
+ /// \brief The length in characters of the whitespace immediately preceeding
+ /// the \c Token.
+ unsigned WhiteSpaceLength;
+
+ /// \brief The offset just past the last '\n' in this token's leading
+ /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
+ unsigned LastNewlineOffset;
+
+ /// \brief The length of the non-whitespace parts of the token. This is
+ /// necessary because we need to handle escaped newlines that are stored
+ /// with the token.
+ unsigned TokenLength;
+
+ /// \brief Indicates that this is the first token.
+ bool IsFirst;
+
+ /// \brief Whether there must be a line break before this token.
+ ///
+ /// This happens for example when a preprocessor directive ended directly
+ /// before the token.
+ bool MustBreakBefore;
+};
+
+/// \brief An unwrapped line is a sequence of \c Token, that we would like to
+/// put on a single line if there was no column limit.
+///
+/// This is used as a main interface between the \c UnwrappedLineParser and the
+/// \c UnwrappedLineFormatter. The key property is that changing the formatting
+/// within an unwrapped line does not affect any other unwrapped lines.
+struct UnwrappedLine {
+ UnwrappedLine() : Level(0), InPPDirective(false), MustBeDeclaration(false) {
+ }
+
+ // FIXME: Don't use std::list here.
+ /// \brief The \c Tokens comprising this \c UnwrappedLine.
+ std::list<FormatToken> Tokens;
+
+ /// \brief The indent level of the \c UnwrappedLine.
+ unsigned Level;
+
+ /// \brief Whether this \c UnwrappedLine is part of a preprocessor directive.
+ bool InPPDirective;
+
+ bool MustBeDeclaration;
+};
+
+class UnwrappedLineConsumer {
+public:
+ virtual ~UnwrappedLineConsumer() {
+ }
+ virtual void consumeUnwrappedLine(const UnwrappedLine &Line) = 0;
+};
+
+class FormatTokenSource {
+public:
+ virtual ~FormatTokenSource() {
+ }
+ virtual FormatToken getNextToken() = 0;
+};
+
+class UnwrappedLineParser {
+public:
+ UnwrappedLineParser(clang::DiagnosticsEngine &Diag, const FormatStyle &Style,
+ FormatTokenSource &Tokens,
+ UnwrappedLineConsumer &Callback);
+
+ /// Returns true in case of a structural error.
+ bool parse();
+
+private:
+ bool parseFile();
+ bool parseLevel(bool HasOpeningBrace);
+ bool parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1);
+ void parsePPDirective();
+ void parsePPDefine();
+ void parsePPUnknown();
+ void parseStructuralElement();
+ void parseBracedList();
+ void parseReturn();
+ void parseParens();
+ void parseIfThenElse();
+ void parseForOrWhileLoop();
+ void parseDoWhile();
+ void parseLabel();
+ void parseCaseLabel();
+ void parseSwitch();
+ void parseNamespace();
+ void parseAccessSpecifier();
+ void parseEnum();
+ void parseRecord();
+ void parseObjCProtocolList();
+ void parseObjCUntilAtEnd();
+ void parseObjCInterfaceOrImplementation();
+ void parseObjCProtocol();
+ void addUnwrappedLine();
+ bool eof() const;
+ void nextToken();
+ void readToken();
+ void flushComments(bool NewlineBeforeNext);
+ void pushToken(const FormatToken &Tok);
+
+ // 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;
+
+ // 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.
+ // Since the next token might already be in a new unwrapped line, we need to
+ // store the comments belonging to that token.
+ SmallVector<FormatToken, 1> CommentsBeforeNextToken;
+ FormatToken FormatTok;
+ bool MustBreakBeforeNextToken;
+
+ // The parsed lines. Only added to through \c CurrentLines.
+ std::vector<UnwrappedLine> Lines;
+
+ // Preprocessor directives are parsed out-of-order from other unwrapped lines.
+ // Thus, we need to keep a list of preprocessor directives to be reported
+ // after an unwarpped line that has been started was finished.
+ std::vector<UnwrappedLine> PreprocessorDirectives;
+
+ // New unwrapped lines are added via CurrentLines.
+ // Usually points to \c &Lines. While parsing a preprocessor directive when
+ // there is an unfinished previous unwrapped line, will point to
+ // \c &PreprocessorDirectives.
+ std::vector<UnwrappedLine> *CurrentLines;
+
+ // We store for each line whether it must be a declaration depending on
+ // whether we are in a compound statement or not.
+ std::vector<bool> DeclarationScopeStack;
+
+ clang::DiagnosticsEngine &Diag;
+ const FormatStyle &Style;
+ FormatTokenSource *Tokens;
+ UnwrappedLineConsumer &Callback;
+
+ friend class ScopedLineState;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 882d400c4292..4a63d76a73e3 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "llvm/Module.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -59,9 +59,12 @@ namespace {
bool TraverseDecl(Decl *D) {
if (D != NULL && filterMatches(D)) {
- Out.changeColor(llvm::raw_ostream::BLUE) <<
- (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
- Out.resetColor();
+ bool ShowColors = Out.has_colors();
+ if (ShowColors)
+ Out.changeColor(raw_ostream::BLUE);
+ Out << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
+ if (ShowColors)
+ Out.resetColor();
if (Dump)
D->dump(Out);
else
@@ -101,7 +104,8 @@ namespace {
bool shouldWalkTypesOfTypeLocs() const { return false; }
virtual bool VisitNamedDecl(NamedDecl *D) {
- Out << D->getQualifiedNameAsString() << "\n";
+ D->printQualifiedName(Out);
+ Out << '\n';
return true;
}
@@ -459,6 +463,10 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<class template> " << *CTD << '\n';
break;
}
+ case Decl::OMPThreadPrivate: {
+ Out << "<omp threadprivate> " << '"' << *I << "\"\n";
+ break;
+ }
default:
Out << "DeclKind: " << DK << '"' << *I << "\"\n";
llvm_unreachable("decl unhandled");
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index 31b1df43df79..bfb30836d819 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTImporter.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
using namespace clang;
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 5576854a7d8b..c1115aedbf83 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -12,40 +12,40 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTUnit.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/Diagnostic.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Atomic.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Timer.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"
#include "llvm/Support/MutexGuard.h"
-#include "llvm/Support/CrashRecoveryContext.h"
-#include <cstdlib>
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+#include <cstdlib>
#include <sys/stat.h>
using namespace clang;
@@ -103,7 +103,7 @@ static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
return M;
}
-static void cleanupOnDiskMapAtExit(void);
+static void cleanupOnDiskMapAtExit();
typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap;
static OnDiskDataMap &getOnDiskDataMap() {
@@ -116,7 +116,7 @@ static OnDiskDataMap &getOnDiskDataMap() {
return M;
}
-static void cleanupOnDiskMapAtExit(void) {
+static void cleanupOnDiskMapAtExit() {
// Use the mutex because there can be an alive thread destroying an ASTUnit.
llvm::MutexGuard Guard(getOnDiskMutex());
OnDiskDataMap &M = getOnDiskDataMap();
@@ -155,7 +155,7 @@ static void removeOnDiskEntry(const ASTUnit *AU) {
}
}
-static void setPreambleFile(const ASTUnit *AU, llvm::StringRef preambleFile) {
+static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) {
getOnDiskData(AU).PreambleFile = preambleFile;
}
@@ -270,7 +270,7 @@ void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; }
/// \brief Determine the set of code-completion contexts in which this
/// declaration should be shown.
-static unsigned getDeclShowContexts(NamedDecl *ND,
+static unsigned getDeclShowContexts(const NamedDecl *ND,
const LangOptions &LangOpts,
bool &IsNestedNameSpecifier) {
IsNestedNameSpecifier = false;
@@ -310,9 +310,9 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag);
// Part of the nested-name-specifier in C++0x.
- if (LangOpts.CPlusPlus0x)
+ if (LangOpts.CPlusPlus11)
IsNestedNameSpecifier = true;
- } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
+ } else if (const RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
if (Record->isUnion())
Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag);
else
@@ -356,8 +356,9 @@ void ASTUnit::CacheCodeCompletionResults() {
typedef CodeCompletionResult Result;
SmallVector<Result, 8> Results;
CachedCompletionAllocator = new GlobalCodeCompletionAllocator;
+ CodeCompletionTUInfo CCTUInfo(CachedCompletionAllocator);
TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator,
- getCodeCompletionTUInfo(), Results);
+ CCTUInfo, Results);
// Translate global code completions into cached completions.
llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
@@ -369,7 +370,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedCodeCompletionResult CachedResult;
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema,
*CachedCompletionAllocator,
- getCodeCompletionTUInfo(),
+ CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
Ctx->getLangOpts(),
@@ -435,7 +436,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedResult.Completion
= Results[I].CreateCodeCompletionString(*TheSema,
*CachedCompletionAllocator,
- getCodeCompletionTUInfo(),
+ CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts = RemainingContexts;
CachedResult.Priority = CCP_NestedNameSpecifier;
@@ -458,7 +459,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedResult.Completion
= Results[I].CreateCodeCompletionString(*TheSema,
*CachedCompletionAllocator,
- getCodeCompletionTUInfo(),
+ CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts
= (1LL << CodeCompletionContext::CCC_TopLevel)
@@ -541,8 +542,8 @@ public:
return false;
this->TargetOpts = new TargetOptions(TargetOpts);
- Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
- *this->TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
+ &*this->TargetOpts);
updated();
return false;
@@ -572,6 +573,11 @@ private:
// Initialize the ASTContext
Context.InitBuiltinTypes(*Target);
+
+ // We didn't have access to the comment options when the ASTContext was
+ // constructed, so register them now.
+ Context.getCommentCommandTraits().registerCommentOptions(
+ LangOpt.CommentOpts);
}
};
@@ -655,8 +661,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
if (CaptureDiagnostics)
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
- ArgEnd-ArgBegin,
- ArgBegin, Client,
+ Client,
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/false);
} else if (CaptureDiagnostics) {
@@ -791,11 +796,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Counter));
switch (Reader->ReadAST(Filename, serialization::MK_MainFile,
- ASTReader::ARR_None)) {
+ SourceLocation(), ASTReader::ARR_None)) {
case ASTReader::Success:
break;
case ASTReader::Failure:
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -842,7 +848,8 @@ class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
public:
explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
- virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ virtual void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
}
};
@@ -1081,7 +1088,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
delete OverrideMainBuffer;
return true;
@@ -1550,7 +1557,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
@@ -1688,7 +1695,30 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
}
StringRef ASTUnit::getMainFileName() const {
- return Invocation->getFrontendOpts().Inputs[0].getFile();
+ if (Invocation && !Invocation->getFrontendOpts().Inputs.empty()) {
+ const FrontendInputFile &Input = Invocation->getFrontendOpts().Inputs[0];
+ if (Input.isFile())
+ return Input.getFile();
+ else
+ return Input.getBuffer()->getBufferIdentifier();
+ }
+
+ if (SourceMgr) {
+ if (const FileEntry *
+ FE = SourceMgr->getFileEntryForID(SourceMgr->getMainFileID()))
+ return FE->getName();
+ }
+
+ return StringRef();
+}
+
+StringRef ASTUnit::getASTFileName() const {
+ if (!isMainFileAST())
+ return StringRef();
+
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ return Mod.FileName;
}
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
@@ -1773,7 +1803,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget())
return 0;
@@ -1898,6 +1928,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->IncludeBriefCommentsInCodeCompletion
= IncludeBriefCommentsInCodeCompletion;
AST->Invocation = CI;
+ AST->FileSystemOpts = CI->getFileSystemOpts();
+ AST->FileMgr = new FileManager(AST->FileSystemOpts);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
// Recover resources if we crash before exiting this method.
@@ -1931,9 +1963,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
- ArgEnd - ArgBegin,
- ArgBegin);
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions());
}
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -2369,7 +2399,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
Clang->setInvocation(0);
return;
@@ -2434,9 +2464,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- StoredDiagnostics.insert(StoredDiagnostics.end(),
- stored_diag_begin(),
- stored_diag_afterDriver_begin());
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
@@ -2458,17 +2485,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- if (OverrideMainBuffer) {
- std::string ModName = getPreambleFile(this);
- TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
- getSourceManager(), PreambleDiagnostics,
- StoredDiagnostics);
- }
Act->Execute();
Act->EndSourceFile();
}
-
- checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
}
bool ASTUnit::Save(StringRef File) {
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 3e666132dc8a..3f80a16b403a 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -25,8 +25,8 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
// FIXME: put this somewhere else?
#ifndef S_ISDIR
@@ -517,8 +517,8 @@ public:
~StatListener() {}
LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
+ bool isFile, int *FileDescriptor) {
+ LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor);
if (Result == CacheMissing) // Failed 'stat'.
PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index 2d586400ec46..a17def0b37b7 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -13,14 +13,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ChainedIncludesSource.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Parse/ParseAST.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
@@ -39,7 +39,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
Reader->addInMemoryBuffer(sr, memBufs[ti]);
}
Reader->setDeserializationListener(deserialListener);
- switch (Reader->ReadAST(pchFile, serialization::MK_PCH,
+ switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader.
@@ -47,6 +47,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
return Reader.take();
case ASTReader::Failure:
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -99,7 +100,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
Clang->setInvocation(CInvok.take());
Clang->setDiagnostics(Diags.getPtr());
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
Clang->createPreprocessor();
@@ -112,8 +113,6 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
OwningPtr<ASTConsumer> consumer;
consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0,
/*isysroot=*/"", &OS));
- Clang->getPreprocessor().setPPMutationListener(
- consumer->GetPPMutationListener());
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
Clang->setASTConsumer(consumer.take());
@@ -191,7 +190,7 @@ CXXBaseSpecifier *
ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
}
-DeclContextLookupResult
+bool
ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 22a74fcc35d9..df06a816e84e 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Sema/Sema.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -17,9 +16,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PTHManager.h"
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
@@ -27,28 +23,35 @@
#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Serialization/ASTReader.h"
+#include "clang/Frontend/VerifyDiagnosticConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Support/Timer.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LockFileManager.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Support/CrashRecoveryContext.h"
-#include "llvm/Config/config.h"
+#include <sys/stat.h>
+#include <time.h>
using namespace clang;
CompilerInstance::CompilerInstance()
- : Invocation(new CompilerInvocation()), ModuleManager(0) {
+ : Invocation(new CompilerInvocation()), ModuleManager(0),
+ BuildGlobalModuleIndex(false), ModuleBuildFailed(false) {
}
CompilerInstance::~CompilerInstance() {
@@ -59,6 +62,13 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) {
Invocation = Value;
}
+bool CompilerInstance::shouldBuildGlobalModuleIndex() const {
+ return (BuildGlobalModuleIndex ||
+ (ModuleManager && ModuleManager->isGlobalIndexUnavailable() &&
+ getFrontendOpts().GenerateGlobalModuleIndex)) &&
+ !ModuleBuildFailed;
+}
+
void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) {
Diagnostics = Value;
}
@@ -92,29 +102,6 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
}
// Diagnostics
-static void SetUpBuildDumpLog(DiagnosticOptions *DiagOpts,
- unsigned argc, const char* const *argv,
- DiagnosticsEngine &Diags) {
- std::string ErrorInfo;
- OwningPtr<raw_ostream> OS(
- new llvm::raw_fd_ostream(DiagOpts->DumpBuildInformation.c_str(),ErrorInfo));
- if (!ErrorInfo.empty()) {
- Diags.Report(diag::err_fe_unable_to_open_logfile)
- << DiagOpts->DumpBuildInformation << ErrorInfo;
- return;
- }
-
- (*OS) << "clang -cc1 command line arguments: ";
- for (unsigned i = 0; i != argc; ++i)
- (*OS) << argv[i] << ' ';
- (*OS) << '\n';
-
- // Chain in a diagnostic client which will log the diagnostics.
- DiagnosticConsumer *Logger =
- new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
- Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
-}
-
static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
const CodeGenOptions *CodeGenOpts,
DiagnosticsEngine &Diags) {
@@ -128,7 +115,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
ErrorInfo, llvm::raw_fd_ostream::F_Append));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
- << DiagOpts->DumpBuildInformation << ErrorInfo;
+ << DiagOpts->DiagnosticLogFile << ErrorInfo;
} else {
FileOS->SetUnbuffered();
FileOS->SetUseAtomicWrites(true);
@@ -167,18 +154,16 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
SerializedConsumer));
}
-void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
- DiagnosticConsumer *Client,
+void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient) {
- Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client,
+ Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client,
ShouldOwnClient, ShouldCloneClient,
&getCodeGenOpts());
}
IntrusiveRefCntPtr<DiagnosticsEngine>
CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
- int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient,
@@ -205,9 +190,6 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
if (!Opts->DiagnosticLogFile.empty())
SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
- if (!Opts->DumpBuildInformation.empty())
- SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
-
if (!Opts->DiagnosticSerializationFile.empty())
SetupSerializedDiagnostics(Opts, *Diags,
Opts->DiagnosticSerializationFile);
@@ -260,10 +242,12 @@ void CompilerInstance::createPreprocessor() {
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord(PPOpts.DetailedRecordConditionalDirectives);
+ PP->createPreprocessingRecord();
InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
+ PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP);
+
// Set up the module path, including the hash for the
// module-creation options.
SmallString<256> SpecificModuleCache(
@@ -317,7 +301,8 @@ void CompilerInstance::createPCHExternalASTSource(StringRef Path,
AllowPCHWithCompilerErrors,
getPreprocessor(), getASTContext(),
DeserializationListener,
- Preamble));
+ Preamble,
+ getFrontendOpts().UseGlobalModuleIndex));
ModuleManager = static_cast<ASTReader*>(Source.get());
getASTContext().setExternalSource(Source);
}
@@ -330,18 +315,21 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
Preprocessor &PP,
ASTContext &Context,
void *DeserializationListener,
- bool Preamble) {
+ bool Preamble,
+ bool UseGlobalModuleIndex) {
OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
DisablePCHValidation,
- AllowPCHWithCompilerErrors));
+ AllowPCHWithCompilerErrors,
+ UseGlobalModuleIndex));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
: serialization::MK_PCH,
+ SourceLocation(),
ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
@@ -353,6 +341,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
// Unrecoverable failure: don't even try to process the input file.
break;
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -619,7 +608,6 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
}
- SourceMgr.createMainFileID(File, Kind);
// The natural SourceManager infrastructure can't currently handle named
// pipes, but we would at least like to accept them for the main
@@ -631,8 +619,13 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message();
return false;
}
+
+ // Create a new virtual file that will have the correct size.
+ File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0);
SourceMgr.overrideFileContents(File, MB.take());
}
+
+ SourceMgr.createMainFileID(File, Kind);
} else {
OwningPtr<llvm::MemoryBuffer> SB;
if (llvm::MemoryBuffer::getSTDIN(SB)) {
@@ -663,7 +656,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
raw_ostream &OS = llvm::errs();
// Create the target instance.
- setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
+ setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), &getTargetOpts()));
if (!hasTarget())
return false;
@@ -754,9 +747,27 @@ static void doCompileMapModule(void *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) {
llvm::LockFileManager Locked(ModuleFileName);
@@ -789,12 +800,25 @@ static void compileModule(CompilerInstance &ImportingInstance,
Invocation->getLangOpts()->resetNonModularOptions();
PPOpts.resetNonModularOptions();
+ // 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());
+
+
// Note the name of the module we're building.
Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
- // Note that this module is part of the module build path, so that we
- // can detect cycles in the module graph.
- PPOpts.ModuleBuildPath.push_back(Module->getTopLevelModuleName());
+ // Make sure that the failed-module structure has been allocated in
+ // the importing instance, and propagate the pointer to the newly-created
+ // instance.
+ PreprocessorOptions &ImportingPPOpts
+ = ImportingInstance.getInvocation().getPreprocessorOpts();
+ if (!ImportingPPOpts.FailedModules)
+ ImportingPPOpts.FailedModules = new PreprocessorOptions::FailedModulesSet;
+ PPOpts.FailedModules = ImportingPPOpts.FailedModules;
// If there is a module map file, build the module using the module map.
// Set up the inputs/outputs so that we build the module from its umbrella
@@ -802,6 +826,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
FrontendOpts.OutputFile = ModuleFileName.str();
FrontendOpts.DisableFree = false;
+ FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.Inputs.clear();
InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
@@ -843,11 +868,21 @@ static void compileModule(CompilerInstance &ImportingInstance,
// module.
CompilerInstance Instance;
Instance.setInvocation(&*Invocation);
- Instance.createDiagnostics(/*argc=*/0, /*argv=*/0,
- &ImportingInstance.getDiagnosticClient(),
+ Instance.createDiagnostics(&ImportingInstance.getDiagnosticClient(),
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/true);
-
+
+ // 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.createSourceManager(Instance.getFileManager());
+ SourceManager &SourceMgr = Instance.getSourceManager();
+ SourceMgr.setModuleBuildStack(
+ ImportingInstance.getSourceManager().getModuleBuildStack());
+ SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
+ FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
+
+
// Construct a module-generating action.
GenerateModuleAction CreateModuleAction;
@@ -865,19 +900,204 @@ static void compileModule(CompilerInstance &ImportingInstance,
Instance.clearOutputFiles(/*EraseFiles=*/true);
if (!TempModuleMapFileName.empty())
llvm::sys::Path(TempModuleMapFileName).eraseFromDisk();
+
+ // We've rebuilt a module. If we're allowed to generate or update the global
+ // module index, record that fact in the importing compiler instance.
+ if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
+ ImportingInstance.setBuildGlobalModuleIndex(true);
+ }
+}
+
+/// \brief Diagnose differences between the current definition of the given
+/// configuration macro and the definition provided on the command line.
+static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
+ Module *Mod, SourceLocation ImportLoc) {
+ IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro);
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // If this identifier has never had a macro definition, then it could
+ // not have changed.
+ if (!Id->hadMacroDefinition())
+ return;
+
+ // If this identifier does not currently have a macro definition,
+ // check whether it had one on the command line.
+ if (!Id->hasMacroDefinition()) {
+ MacroDirective::DefInfo LatestDef =
+ PP.getMacroDirectiveHistory(Id)->getDefinition();
+ for (MacroDirective::DefInfo Def = LatestDef; Def;
+ Def = Def.getPreviousDefinition()) {
+ FileID FID = SourceMgr.getFileID(Def.getLocation());
+ if (FID.isInvalid())
+ continue;
+
+ // We only care about the predefines buffer.
+ if (FID != PP.getPredefinesFileID())
+ continue;
+
+ // This macro was defined on the command line, then #undef'd later.
+ // Complain.
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << true << ConfigMacro << Mod->getFullModuleName();
+ if (LatestDef.isUndefined())
+ PP.Diag(LatestDef.getUndefLocation(), diag::note_module_def_undef_here)
+ << true;
+ return;
+ }
+
+ // Okay: no definition in the predefines buffer.
+ return;
+ }
+
+ // This identifier has a macro definition. Check whether we had a definition
+ // on the command line.
+ MacroDirective::DefInfo LatestDef =
+ PP.getMacroDirectiveHistory(Id)->getDefinition();
+ MacroDirective::DefInfo PredefinedDef;
+ for (MacroDirective::DefInfo Def = LatestDef; Def;
+ Def = Def.getPreviousDefinition()) {
+ FileID FID = SourceMgr.getFileID(Def.getLocation());
+ if (FID.isInvalid())
+ continue;
+
+ // We only care about the predefines buffer.
+ if (FID != PP.getPredefinesFileID())
+ continue;
+
+ PredefinedDef = Def;
+ break;
+ }
+
+ // If there was no definition for this macro in the predefines buffer,
+ // complain.
+ if (!PredefinedDef ||
+ (!PredefinedDef.getLocation().isValid() &&
+ PredefinedDef.getUndefLocation().isValid())) {
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << false << ConfigMacro << Mod->getFullModuleName();
+ PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here)
+ << false;
+ return;
+ }
+
+ // If the current macro definition is the same as the predefined macro
+ // definition, it's okay.
+ if (LatestDef.getMacroInfo() == PredefinedDef.getMacroInfo() ||
+ LatestDef.getMacroInfo()->isIdenticalTo(*PredefinedDef.getMacroInfo(),PP,
+ /*Syntactically=*/true))
+ return;
+
+ // The macro definitions differ.
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << false << ConfigMacro << Mod->getFullModuleName();
+ PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here)
+ << false;
+}
+
+/// \brief Write a new timestamp file with the given path.
+static void writeTimestampFile(StringRef TimestampFile) {
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary);
}
-Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+/// \brief Prune the module cache of modules that haven't been accessed in
+/// a long time.
+static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
+ struct stat StatBuf;
+ llvm::SmallString<128> TimestampFile;
+ TimestampFile = HSOpts.ModuleCachePath;
+ llvm::sys::path::append(TimestampFile, "modules.timestamp");
+
+ // Try to stat() the timestamp file.
+ if (::stat(TimestampFile.c_str(), &StatBuf)) {
+ // If the timestamp file wasn't there, create one now.
+ if (errno == ENOENT) {
+ writeTimestampFile(TimestampFile);
+ }
+ return;
+ }
+
+ // 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);
+ if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval))
+ return;
+
+ // Write a new timestamp file so that nobody else attempts to prune.
+ // There is a benign race condition here, if two Clang instances happen to
+ // notice at the same time that the timestamp is out-of-date.
+ writeTimestampFile(TimestampFile);
+
+ // Walk the entire module cache, looking for unused module files and module
+ // indices.
+ llvm::error_code EC;
+ SmallString<128> ModuleCachePathNative;
+ llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative);
+ for (llvm::sys::fs::directory_iterator
+ Dir(ModuleCachePathNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ // If we don't have a directory, there's nothing to look into.
+ bool IsDirectory;
+ if (llvm::sys::fs::is_directory(Dir->path(), IsDirectory) || !IsDirectory)
+ 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;
+ 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;
+ 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;
+ }
+ }
+
+ // 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);
+ }
+ }
+}
+
+ModuleLoadResult
+CompilerInstance::loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
// If we've already handled this import, just return the cached result.
// This one-element cache is important to eliminate redundant diagnostics
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
// Make the named module visible.
if (LastModuleImportResult)
- ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility);
+ ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
+ ImportLoc, /*Complain=*/false);
return LastModuleImportResult;
}
@@ -901,79 +1121,36 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
// Search for a module with the given name.
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
std::string ModuleFileName;
- if (Module)
+ if (Module) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- else
+ } else
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName);
-
- if (ModuleFileName.empty()) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = 0;
- return 0;
- }
-
- const FileEntry *ModuleFile
- = getFileManager().getFile(ModuleFileName, /*OpenFile=*/false,
- /*CacheFailure=*/false);
- bool BuildingModule = false;
- if (!ModuleFile && Module) {
- // The module is not cached, but we have a module map from which we can
- // build the module.
-
- // Check whether there is a cycle in the module graph.
- SmallVectorImpl<std::string> &ModuleBuildPath
- = getPreprocessorOpts().ModuleBuildPath;
- SmallVectorImpl<std::string>::iterator Pos
- = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(), ModuleName);
- if (Pos != ModuleBuildPath.end()) {
- SmallString<256> CyclePath;
- for (; Pos != ModuleBuildPath.end(); ++Pos) {
- CyclePath += *Pos;
- CyclePath += " -> ";
- }
- CyclePath += ModuleName;
-
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
- << ModuleName << CyclePath;
- return 0;
- }
-
- getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build)
- << ModuleName;
- BuildingModule = true;
- compileModule(*this, Module, ModuleFileName);
- ModuleFile = FileMgr->getFile(ModuleFileName);
- }
-
- if (!ModuleFile) {
- getDiagnostics().Report(ModuleNameLoc,
- BuildingModule? diag::err_module_not_built
- : diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- return 0;
- }
// 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());
+ }
+
std::string Sysroot = getHeaderSearchOpts().Sysroot;
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
ModuleManager = new ASTReader(getPreprocessor(), *Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation);
+ PPOpts.DisablePCHValidation,
+ /*AllowASTWithCompilerErrors=*/false,
+ getFrontendOpts().UseGlobalModuleIndex);
if (hasASTConsumer()) {
ModuleManager->setDeserializationListener(
getASTConsumer().GetASTDeserializationListener());
getASTContext().setASTMutationListener(
getASTConsumer().GetASTMutationListener());
- getPreprocessor().setPPMutationListener(
- getASTConsumer().GetPPMutationListener());
}
OwningPtr<ExternalASTSource> Source;
Source.reset(ModuleManager);
@@ -984,31 +1161,87 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleManager->StartTranslationUnit(&getASTConsumer());
}
- // Try to load the module we found.
- unsigned ARRFlags = ASTReader::ARR_None;
- if (Module)
- ARRFlags |= ASTReader::ARR_OutOfDate;
- switch (ModuleManager->ReadAST(ModuleFile->getName(),
- serialization::MK_Module,
- ARRFlags)) {
+ // Try to load the module file.
+ unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success:
break;
case ASTReader::OutOfDate: {
- // The module file is out-of-date. Rebuild it.
- getFileManager().invalidateCache(ModuleFile);
+ // The module file is out-of-date. Remove it, then rebuild it.
bool Existed;
llvm::sys::fs::remove(ModuleFileName, Existed);
- compileModule(*this, Module, ModuleFileName);
-
- // Try loading the module again.
- ModuleFile = FileMgr->getFile(ModuleFileName);
- if (!ModuleFile ||
- ModuleManager->ReadAST(ModuleFileName,
- serialization::MK_Module,
- ASTReader::ARR_None) != ASTReader::Success) {
+ }
+ // Fall through to build the module again.
+
+ case ASTReader::Missing: {
+ // The module file is (now) missing. 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();
+ }
+
+ // Check whether there is a cycle in the module graph.
+ ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack();
+ ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end();
+ for (; Pos != PosEnd; ++Pos) {
+ if (Pos->first == ModuleName)
+ break;
+ }
+
+ if (Pos != PosEnd) {
+ SmallString<256> CyclePath;
+ for (; Pos != PosEnd; ++Pos) {
+ CyclePath += Pos->first;
+ CyclePath += " -> ";
+ }
+ CyclePath += ModuleName;
+
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+ << ModuleName << CyclePath;
+ return ModuleLoadResult();
+ }
+
+ // Check whether we have already attempted to build this module (but
+ // failed).
+ if (getPreprocessorOpts().FailedModules &&
+ getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ 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);
+ }
+
+ if (getPreprocessorOpts().FailedModules)
+ getPreprocessorOpts().FailedModules->addFailed(ModuleName);
KnownModules[Path[0].first] = 0;
- return 0;
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
}
// Okay, we've rebuilt and now loaded the module.
@@ -1021,12 +1254,13 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
KnownModules[Path[0].first] = 0;
- return 0;
+ return ModuleLoadResult();
case ASTReader::Failure:
// Already complained, but note now that we failed.
KnownModules[Path[0].first] = 0;
- return 0;
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
}
if (!Module) {
@@ -1036,16 +1270,13 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
.findModule((Path[0].first->getName()));
}
- if (Module)
- Module->setASTFile(ModuleFile);
-
// Cache the result of this top-level module lookup for later.
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
}
// If we never found the module, fail.
if (!Module)
- return 0;
+ return ModuleLoadResult();
// Verify that the rest of the module path actually corresponds to
// a submodule.
@@ -1056,7 +1287,7 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
if (!Sub) {
// Attempt to perform typo correction to find a module name that works.
- llvm::SmallVector<StringRef, 2> Best;
+ SmallVector<StringRef, 2> Best;
unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)();
for (clang::Module::submodule_iterator J = Module->submodule_begin(),
@@ -1115,7 +1346,7 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
<< Module->getFullModuleName()
<< SourceRange(Path.front().second, Path.back().second);
- return 0;
+ return ModuleLoadResult(0, true);
}
// Check whether this module is available.
@@ -1126,13 +1357,21 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
<< Feature
<< SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = 0;
- return 0;
+ LastModuleImportResult = ModuleLoadResult();
+ return ModuleLoadResult();
}
- ModuleManager->makeModuleVisible(Module, Visibility);
+ ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc,
+ /*Complain=*/true);
}
-
+
+ // Check for any configuration macros that have changed.
+ clang::Module *TopModule = Module->getTopLevelModule();
+ for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) {
+ checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I],
+ Module, ImportLoc);
+ }
+
// If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
if (IsInclusionDirective && hasASTContext()) {
@@ -1146,6 +1385,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
}
LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = Module;
- return Module;
+ LastModuleImportResult = ModuleLoadResult(Module, false);
+ return LastModuleImportResult;
+}
+
+void CompilerInstance::makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain){
+ ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
}
+
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b9c198b11191..41f941729a66 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -9,17 +9,16 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/Version.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Options.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
-#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Driver/Options.h"
#include "clang/Frontend/LangStandard.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/OwningPtr.h"
@@ -71,7 +70,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
assert (A->getOption().matches(options::OPT_O));
- llvm::StringRef S(A->getValue());
+ StringRef S(A->getValue());
if (S == "s" || S == "z" || S.empty())
return 2;
@@ -189,22 +188,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
}
- if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) {
- StringRef Name = A->getValue();
- AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name)
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
- .Case(CMDFLAG, NAME)
-#include "clang/StaticAnalyzer/Core/Analyses.def"
- .Default(NumIPAModes);
- if (Value == NumIPAModes) {
- Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << Name;
- Success = false;
- } else {
- Opts.IPAMode = Value;
- }
- }
-
if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
StringRef Name = A->getValue();
AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
@@ -235,15 +218,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
- Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
Opts.PrintStats = Args.hasArg(OPT_analyzer_stats);
Opts.InlineMaxStackDepth =
Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth,
Opts.InlineMaxStackDepth, Diags);
- Opts.InlineMaxFunctionSize =
- Args.getLastArgIntValue(OPT_analyzer_inline_max_function_size,
- Opts.InlineMaxFunctionSize, Diags);
Opts.CheckersControlList.clear();
for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker,
@@ -300,6 +279,10 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) {
return true;
}
+static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) {
+ Opts.BlockCommandNames = Args.getAllArgValues(OPT_fcomment_block_commands);
+}
+
static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
using namespace options;
@@ -332,13 +315,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.setDebugInfo(CodeGenOptions::FullDebugInfo);
}
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
+ Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
+ Opts.ModulesAutolink = Args.hasArg(OPT_fmodules_autolink);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
OPT_fuse_register_sized_bitfield_access);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
+ Opts.StructPathTBAA = Args.hasArg(OPT_struct_path_tbaa);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
@@ -373,6 +359,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
+ Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
@@ -386,8 +373,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ);
- Opts.BoundsChecking = Args.getLastArgIntValue(OPT_fbounds_checking_EQ, 0,
- Diags);
Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array);
Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
@@ -395,15 +380,40 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+ Opts.SanitizeRecover = !Args.hasArg(OPT_fno_sanitize_recover);
- Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
- Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.DisableGCov = Args.hasArg(OPT_test_coverage);
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
- Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
+ if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) {
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
+ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum);
+ Opts.CoverageNoFunctionNamesInData =
+ Args.hasArg(OPT_coverage_no_function_names_in_data);
+ if (Args.hasArg(OPT_coverage_version_EQ)) {
+ StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ);
+ if (CoverageVersion.size() != 4) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_coverage_version_EQ)->getAsString(Args)
+ << CoverageVersion;
+ } else {
+ memcpy(Opts.CoverageVersion, CoverageVersion.data(), 4);
+ }
+ }
+ }
+
+ Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
+ Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
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);
+ Opts.SanitizeUndefinedTrapOnError =
+ Args.hasArg(OPT_fsanitize_undefined_trap_on_error);
Opts.SSPBufferSize =
Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -446,6 +456,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
+ StringRef Val = A->getValue();
+ if (Val == "fast")
+ Opts.setFPContractMode(CodeGenOptions::FPC_Fast);
+ else if (Val == "on")
+ Opts.setFPContractMode(CodeGenOptions::FPC_On);
+ else if (Val == "off")
+ Opts.setFPContractMode(CodeGenOptions::FPC_Off);
+ else
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ }
+
return Success;
}
@@ -538,9 +560,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
+ Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.ElideType = !Args.hasArg(OPT_fno_elide_type);
Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree);
+ Opts.WarnOnSpellCheck = Args.hasArg(OPT_fwarn_on_spellcheck);
Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
Opts.MacroBacktraceLimit
= Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
@@ -562,7 +586,6 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
<< Opts.TabStop << DiagnosticOptions::DefaultTabStop;
}
Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
- Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information);
addWarningArgs(Args, Opts.Warnings);
return Success;
@@ -623,6 +646,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::InitOnly; break;
case OPT_fsyntax_only:
Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
+ case OPT_module_file_info:
+ Opts.ProgramAction = frontend::ModuleFileInfo; break;
case OPT_print_decl_contexts:
Opts.ProgramAction = frontend::PrintDeclContext; break;
case OPT_print_preamble:
@@ -689,7 +714,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
-
+ Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
+ Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex;
+
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
Opts.CodeCompleteOpts.IncludeCodePatterns
@@ -756,7 +783,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Case("objective-c-header", IK_ObjC)
.Case("c++-header", IK_CXX)
.Case("objective-c++-header", IK_ObjCXX)
- .Case("ast", IK_AST)
+ .Cases("ast", "pcm", IK_AST)
.Case("ir", IK_LLVM_IR)
.Default(IK_None);
if (DashX == IK_None)
@@ -811,9 +838,18 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
- Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path);
+ Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path);
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
-
+ Opts.ModuleCachePruneInterval
+ = Args.getLastArgIntValue(OPT_fmodules_prune_interval, 7*24*60*60);
+ Opts.ModuleCachePruneAfter
+ = Args.getLastArgIntValue(OPT_fmodules_prune_after, 31*24*60*60);
+ for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ StringRef MacroDef = (*it)->getValue();
+ Opts.ModulesIgnoreMacros.insert(MacroDef.split('=').first);
+ }
+
// Add -I..., -F..., and -index-header-map options in order.
bool IsIndexHeaderMap = false;
for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F,
@@ -828,12 +864,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
frontend::IncludeDirGroup Group
= IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled;
- Opts.AddPath((*it)->getValue(), Group, true,
- /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
+ Opts.AddPath((*it)->getValue(), Group,
+ /*IsFramework=*/ (*it)->getOption().matches(OPT_F), true);
IsIndexHeaderMap = false;
}
- // Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
+ // Add -iprefix/-iwithprefix/-iwithprefixbefore options.
StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix,
OPT_iwithprefixbefore),
@@ -843,50 +879,50 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Prefix = A->getValue();
else if (A->getOption().matches(OPT_iwithprefix))
Opts.AddPath(Prefix.str() + A->getValue(),
- frontend::System, false, false, false);
+ frontend::After, false, true);
else
Opts.AddPath(Prefix.str() + A->getValue(),
- frontend::Angled, false, false, false);
+ frontend::Angled, false, true);
}
for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::After, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::After, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::Quoted, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_isystem,
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::System, true, false,
+ Opts.AddPath((*it)->getValue(), frontend::System, false,
!(*it)->getOption().matches(OPT_iwithsysroot));
for (arg_iterator it = Args.filtered_begin(OPT_iframework),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::System, true, true,
- true);
+ Opts.AddPath((*it)->getValue(), frontend::System, true, true);
// Add the paths for the various language specific isystem flags.
for (arg_iterator it = Args.filtered_begin(OPT_c_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::CSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CSystem, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CXXSystem, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true);
+ Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, false,true);
for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false,
- true);
+ Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, false, true);
// Add the internal paths from a driver that detects standard include paths.
for (arg_iterator I = Args.filtered_begin(OPT_internal_isystem,
OPT_internal_externc_isystem),
E = Args.filtered_end();
- I != E; ++I)
- Opts.AddPath((*I)->getValue(), frontend::System,
- false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true,
- (*I)->getOption().matches(OPT_internal_externc_isystem));
+ I != E; ++I) {
+ frontend::IncludeDirGroup Group = frontend::System;
+ if ((*I)->getOption().matches(OPT_internal_externc_isystem))
+ Group = frontend::ExternCSystem;
+ Opts.AddPath((*I)->getValue(), Group, false, true);
+ }
// Add the path prefixes which are implicitly treated as being system headers.
for (arg_iterator I = Args.filtered_begin(OPT_isystem_prefix,
@@ -945,7 +981,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.C99 = Std.isC99();
Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
- Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus1y = Std.isCPlusPlus1y();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
@@ -973,6 +1009,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CXXOperatorNames = 1;
Opts.LaxVectorConversions = 0;
Opts.DefaultFPContract = 1;
+ Opts.NativeHalfType = 1;
}
if (LangStd == LangStandard::lang_cuda)
@@ -994,6 +1031,24 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.DollarIdents = !Opts.AsmPreprocessor;
}
+/// Attempt to parse a visibility value out of the given argument.
+static Visibility parseVisibility(Arg *arg, ArgList &args,
+ DiagnosticsEngine &diags) {
+ StringRef value = arg->getValue();
+ if (value == "default") {
+ return DefaultVisibility;
+ } else if (value == "hidden") {
+ return HiddenVisibility;
+ } else if (value == "protected") {
+ // FIXME: diagnose if target does not support protected visibility
+ return ProtectedVisibility;
+ }
+
+ diags.Report(diag::err_drv_invalid_value)
+ << arg->getAsString(args) << value;
+ return DefaultVisibility;
+}
+
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff.
@@ -1122,31 +1177,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_pthread))
Opts.POSIXThreads = 1;
- if (Args.hasArg(OPT_fdelayed_template_parsing))
- Opts.DelayedTemplateParsing = 1;
-
- StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
- if (Vis == "default")
- Opts.setVisibilityMode(DefaultVisibility);
- else if (Vis == "hidden")
- Opts.setVisibilityMode(HiddenVisibility);
- else if (Vis == "protected")
- // FIXME: diagnose if target does not support protected visibility
- Opts.setVisibilityMode(ProtectedVisibility);
- else
- Diags.Report(diag::err_drv_invalid_value)
- << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
+ // The value-visibility mode defaults to "default".
+ if (Arg *visOpt = Args.getLastArg(OPT_fvisibility)) {
+ Opts.setValueVisibilityMode(parseVisibility(visOpt, Args, Diags));
+ } else {
+ Opts.setValueVisibilityMode(DefaultVisibility);
+ }
- if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
- StringRef Val = A->getValue();
- if (Val == "fast")
- Opts.setFPContractMode(LangOptions::FPC_Fast);
- else if (Val == "on")
- Opts.setFPContractMode(LangOptions::FPC_On);
- else if (Val == "off")
- Opts.setFPContractMode(LangOptions::FPC_Off);
- else
- Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ // The type-visibility mode defaults to the value-visibility mode.
+ if (Arg *typeVisOpt = Args.getLastArg(OPT_ftype_visibility)) {
+ Opts.setTypeVisibilityMode(parseVisibility(typeVisOpt, Args, Diags));
+ } else {
+ Opts.setTypeVisibilityMode(Opts.getValueVisibilityMode());
}
if (Args.hasArg(OPT_fvisibility_inlines_hidden))
@@ -1171,6 +1213,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.MicrosoftExt
= Args.hasArg(OPT_fms_extensions) || Args.hasArg(OPT_fms_compatibility);
Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility);
+ Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
@@ -1205,6 +1248,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Diags);
Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512,
Diags);
+ Opts.BracketDepth = Args.getLastArgIntValue(OPT_fbracket_depth, 256, Diags);
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ,
0, Diags);
@@ -1238,6 +1282,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+ // Check if -fopenmp is specified.
+ Opts.OpenMP = Args.hasArg(OPT_fopenmp);
+
// Record whether the __DEPRECATED define was requested.
Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
OPT_fno_deprecated_macro,
@@ -1257,8 +1304,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.FastMath = Args.hasArg(OPT_ffast_math);
Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only);
- Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm);
-
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
@@ -1293,7 +1338,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
.Default(Unknown)) {
#define SANITIZER(NAME, ID) \
case ID: \
- Opts.Sanitize##ID = true; \
+ Opts.Sanitize.ID = true; \
break;
#include "clang/Basic/Sanitizers.def"
@@ -1354,8 +1399,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros);
// Add the ordered list of -includes.
- for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch,
- OPT_include_pth),
+ for (arg_iterator it = Args.filtered_begin(OPT_include),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
Opts.Includes.push_back(A->getValue());
@@ -1400,9 +1444,49 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
- ArgList &Args) {
+ ArgList &Args,
+ frontend::ActionKind Action) {
using namespace options;
- Opts.ShowCPP = !Args.hasArg(OPT_dM);
+
+ switch (Action) {
+ case frontend::ASTDeclList:
+ case frontend::ASTDump:
+ case frontend::ASTDumpXML:
+ case frontend::ASTPrint:
+ case frontend::ASTView:
+ case frontend::EmitAssembly:
+ case frontend::EmitBC:
+ case frontend::EmitHTML:
+ case frontend::EmitLLVM:
+ case frontend::EmitLLVMOnly:
+ case frontend::EmitCodeGenOnly:
+ case frontend::EmitObj:
+ case frontend::FixIt:
+ case frontend::GenerateModule:
+ case frontend::GeneratePCH:
+ case frontend::GeneratePTH:
+ case frontend::ParseSyntaxOnly:
+ case frontend::ModuleFileInfo:
+ case frontend::PluginAction:
+ case frontend::PrintDeclContext:
+ case frontend::RewriteObjC:
+ case frontend::RewriteTest:
+ case frontend::RunAnalysis:
+ case frontend::MigrateSource:
+ Opts.ShowCPP = 0;
+ break;
+
+ case frontend::DumpRawTokens:
+ case frontend::DumpTokens:
+ case frontend::InitOnly:
+ case frontend::PrintPreamble:
+ case frontend::PrintPreprocessedInput:
+ case frontend::RewriteMacros:
+ case frontend::RunPreprocessorOnly:
+ Opts.ShowCPP = !Args.hasArg(OPT_dM);
+ break;
+ }
+
Opts.ShowComments = Args.hasArg(OPT_C);
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
Opts.ShowMacroComments = Args.hasArg(OPT_CC);
@@ -1466,6 +1550,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags)
&& Success;
+ ParseCommentArgs(Res.getLangOpts()->CommentOpts, *Args);
ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
// FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
@@ -1483,7 +1568,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// parameters from the function and the "FileManager.h" #include.
FileManager FileMgr(Res.getFileSystemOpts());
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
- ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
+ ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args,
+ Res.getFrontendOpts().ProgramAction);
ParseTargetArgs(Res.getTargetOpts(), *Args);
return Success;
@@ -1492,7 +1578,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
namespace {
class ModuleSignature {
- llvm::SmallVector<uint64_t, 16> Data;
+ SmallVector<uint64_t, 16> Data;
unsigned CurBit;
uint64_t CurValue;
@@ -1543,6 +1629,8 @@ llvm::APInt ModuleSignature::getAsInteger() const {
}
std::string CompilerInvocation::getModuleHash() const {
+ // Note: For QoI reasons, the things we use as a hash here should all be
+ // dumped via the -module-info flag.
using llvm::hash_code;
using llvm::hash_value;
using llvm::hash_combine;
@@ -1570,6 +1658,7 @@ std::string CompilerInvocation::getModuleHash() const {
// Extend the signature with preprocessor options.
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
+ const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
std::vector<StringRef> MacroDefs;
@@ -1577,11 +1666,19 @@ std::string CompilerInvocation::getModuleHash() const {
I = getPreprocessorOpts().Macros.begin(),
IEnd = getPreprocessorOpts().Macros.end();
I != IEnd; ++I) {
+ // If we're supposed to ignore this macro for the purposes of modules,
+ // don't put it into the hash.
+ if (!hsOpts.ModulesIgnoreMacros.empty()) {
+ // Check whether we're ignoring this macro.
+ StringRef MacroDef = I->first;
+ if (hsOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first))
+ continue;
+ }
+
code = hash_combine(code, I->first, I->second);
}
// Extend the signature with the sysroot.
- const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
hsOpts.UseStandardSystemIncludes,
hsOpts.UseStandardCXXIncludes,
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index d82cb6d05157..e25eb4322c55 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/Host.h"
using namespace clang;
@@ -34,9 +34,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions,
- ArgList.size(),
- ArgList.begin());
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
}
SmallVector<const char *, 16> Args;
@@ -48,7 +46,7 @@ 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", false, *Diags);
+ "a.out", *Diags);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 53ea8befbc09..628def68e5e0 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -151,12 +151,14 @@ void DependencyFileCallback::AddFilename(StringRef Filename) {
Files.push_back(Filename);
}
-/// PrintFilename - GCC escapes spaces, but apparently not ' or " or other
-/// scary characters.
+/// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or
+/// other scary characters.
static void PrintFilename(raw_ostream &OS, StringRef Filename) {
for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
- if (Filename[i] == ' ')
+ if (Filename[i] == ' ' || Filename[i] == '#')
OS << '\\';
+ else if (Filename[i] == '$') // $ is escaped by $$.
+ OS << '$';
OS << Filename[i];
}
}
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index 28d9c5d320e2..e128d91c4083 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -19,8 +19,8 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SetVector.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace DOT = llvm::DOT;
@@ -31,15 +31,14 @@ class DependencyGraphCallback : public PPCallbacks {
std::string OutputFile;
std::string SysRoot;
llvm::SetVector<const FileEntry *> AllFiles;
- typedef llvm::DenseMap<const FileEntry *,
- llvm::SmallVector<const FileEntry *, 2> >
- DependencyMap;
+ typedef llvm::DenseMap<const FileEntry *,
+ SmallVector<const FileEntry *, 2> > DependencyMap;
DependencyMap Dependencies;
private:
- llvm::raw_ostream &writeNodeReference(llvm::raw_ostream &OS,
- const FileEntry *Node);
+ raw_ostream &writeNodeReference(raw_ostream &OS,
+ const FileEntry *Node);
void OutputGraphFile();
public:
@@ -93,8 +92,8 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
AllFiles.insert(FromFile);
}
-llvm::raw_ostream &
-DependencyGraphCallback::writeNodeReference(llvm::raw_ostream &OS,
+raw_ostream &
+DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
const FileEntry *Node) {
OS << "header_" << Node->getUID();
return OS;
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index 359b82be6062..3b4f55c6c41b 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -11,15 +11,15 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Edit/EditedSource.h"
#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
#include "clang/Edit/EditsReceiver.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
@@ -47,6 +47,11 @@ static StringRef getImmediateMacroName(SourceLocation Loc,
while (SM.isMacroArgExpansion(Loc))
Loc = SM.getImmediateExpansionRange(Loc).first;
+ // If the macro's spelling has no FileID, then it's actually a token paste
+ // or stringization (or similar) and not a macro at all.
+ if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc))))
+ return StringRef();
+
// Find the spelling location of the start of the non-argument expansion
// range. This is where the macro name was spelled in order to begin
// expanding this macro.
@@ -123,28 +128,18 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
const SourceManager *SM,
DiagOrStoredDiag D) {
assert(SM || Loc.isInvalid());
-
+
beginDiagnostic(D, Level);
-
- PresumedLoc PLoc;
- if (Loc.isValid()) {
- PLoc = SM->getPresumedLocForDisplay(Loc);
-
- // First, if this diagnostic is not in the main file, print out the
- // "included from" lines.
- emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM);
- }
-
- // Next, emit the actual diagnostic message.
- emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
-
- // Only recurse if we have a valid location.
- if (Loc.isValid()) {
+
+ if (!Loc.isValid())
+ // If we have no source location, just emit the diagnostic message.
+ emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
+ else {
// Get the ranges into a local array we can hack on.
SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
Ranges.end());
-
- llvm::SmallVector<FixItHint, 8> MergedFixits;
+
+ SmallVector<FixItHint, 8> MergedFixits;
if (!FixItHints.empty()) {
mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
FixItHints = MergedFixits;
@@ -155,15 +150,34 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
I != E; ++I)
if (I->RemoveRange.isValid())
MutableRanges.push_back(I->RemoveRange);
-
- unsigned MacroDepth = 0;
- emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, *SM,
- MacroDepth);
+
+ SourceLocation UnexpandedLoc = Loc;
+
+ // Find the ultimate expansion location for the diagnostic.
+ Loc = SM->getFileLoc(Loc);
+
+ PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ emitIncludeStack(Loc, PLoc, Level, *SM);
+
+ // Next, emit the actual diagnostic message and caret.
+ emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
+ emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
+
+ // If this location is within a macro, walk from UnexpandedLoc up to Loc
+ // and produce a macro backtrace.
+ if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
+ unsigned MacroDepth = 0;
+ emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM,
+ MacroDepth);
+ }
}
-
+
LastLoc = Loc;
LastLevel = Level;
-
+
endDiagnostic(D, Level);
}
@@ -184,34 +198,55 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
/// repeated warnings occur within the same file. It also handles the logic
/// of customizing the formatting and display of the include stack.
///
+/// \param Loc The diagnostic location.
+/// \param PLoc The presumed location of the diagnostic location.
/// \param Level The diagnostic level of the message this stack pertains to.
-/// \param Loc The include location of the current file (not the diagnostic
-/// location).
void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
+ PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
const SourceManager &SM) {
+ SourceLocation IncludeLoc = PLoc.getIncludeLoc();
+
// Skip redundant include stacks altogether.
- if (LastIncludeLoc == Loc)
+ if (LastIncludeLoc == IncludeLoc)
return;
- LastIncludeLoc = Loc;
+
+ LastIncludeLoc = IncludeLoc;
if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
return;
-
- emitIncludeStackRecursively(Loc, SM);
+
+ if (IncludeLoc.isValid())
+ emitIncludeStackRecursively(IncludeLoc, SM);
+ else {
+ emitModuleBuildStack(SM);
+ emitImportStack(Loc, SM);
+ }
}
/// \brief Helper to recursivly walk up the include stack and print each layer
/// on the way back down.
void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
const SourceManager &SM) {
- if (Loc.isInvalid())
+ if (Loc.isInvalid()) {
+ emitModuleBuildStack(SM);
return;
+ }
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
if (PLoc.isInvalid())
return;
-
+
+ // If this source location was imported from a module, print the module
+ // import stack rather than the
+ // FIXME: We want submodule granularity here.
+ std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
+ if (Imported.first.isValid()) {
+ // This location was imported by a module. Emit the module import stack.
+ emitImportStackRecursively(Imported.first, Imported.second, SM);
+ return;
+ }
+
// Emit the other include frames first.
emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
@@ -219,6 +254,56 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
emitIncludeLocation(Loc, PLoc, SM);
}
+/// \brief Emit the module import stack associated with the current location.
+void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
+ const SourceManager &SM) {
+ if (Loc.isInvalid()) {
+ emitModuleBuildStack(SM);
+ return;
+ }
+
+ std::pair<SourceLocation, StringRef> NextImportLoc
+ = SM.getModuleImportLoc(Loc);
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+}
+
+/// \brief Helper to recursivly walk up the import stack and print each layer
+/// on the way back down.
+void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ if (Loc.isInvalid()) {
+ return;
+ }
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ if (PLoc.isInvalid())
+ return;
+
+ // Emit the other import frames first.
+ std::pair<SourceLocation, StringRef> NextImportLoc
+ = SM.getModuleImportLoc(Loc);
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+
+ // Emit the inclusion text/note.
+ emitImportLocation(Loc, PLoc, ModuleName, SM);
+}
+
+/// \brief Emit the module build stack, for cases where a module is (re-)built
+/// on demand.
+void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
+ ModuleBuildStack Stack = SM.getModuleBuildStack();
+ for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
+ const SourceManager &CurSM = Stack[I].second.getManager();
+ SourceLocation CurLoc = Stack[I].second;
+ emitBuildingModuleLocation(CurLoc,
+ CurSM.getPresumedLoc(CurLoc,
+ DiagOpts->ShowPresumedLoc),
+ Stack[I].first,
+ CurSM);
+ }
+}
+
// Helper function to fix up source ranges. It takes in an array of ranges,
// and outputs an array of ranges where we want to draw the range highlighting
// around the location specified by CaretLoc.
@@ -231,31 +316,58 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
// iff the FileID is the same.
static void mapDiagnosticRanges(
SourceLocation CaretLoc,
- const SmallVectorImpl<CharSourceRange>& Ranges,
- SmallVectorImpl<CharSourceRange>& SpellingRanges,
+ ArrayRef<CharSourceRange> Ranges,
+ SmallVectorImpl<CharSourceRange> &SpellingRanges,
const SourceManager *SM) {
FileID CaretLocFileID = SM->getFileID(CaretLoc);
- for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
+ for (ArrayRef<CharSourceRange>::const_iterator I = Ranges.begin(),
E = Ranges.end();
I != E; ++I) {
SourceLocation Begin = I->getBegin(), End = I->getEnd();
bool IsTokenRange = I->isTokenRange();
- // Search the macro caller chain for the beginning of the range.
- while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID)
- Begin = SM->getImmediateMacroCallerLoc(Begin);
+ FileID BeginFileID = SM->getFileID(Begin);
+ FileID EndFileID = SM->getFileID(End);
- // Search the macro caller chain for the beginning of the range.
- while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) {
- // The computation of the next End is an inlined version of
- // getImmediateMacroCallerLoc, except it chooses the end of an
- // expansion range.
- if (SM->isMacroArgExpansion(End)) {
+ // Find the common parent for the beginning and end of the range.
+
+ // First, crawl the expansion chain for the beginning of the range.
+ llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
+ while (Begin.isMacroID() && BeginFileID != EndFileID) {
+ BeginLocsMap[BeginFileID] = Begin;
+ Begin = SM->getImmediateExpansionRange(Begin).first;
+ BeginFileID = SM->getFileID(Begin);
+ }
+
+ // Then, crawl the expansion chain for the end of the range.
+ if (BeginFileID != EndFileID) {
+ while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
+ End = SM->getImmediateExpansionRange(End).second;
+ EndFileID = SM->getFileID(End);
+ }
+ if (End.isMacroID()) {
+ Begin = BeginLocsMap[EndFileID];
+ BeginFileID = EndFileID;
+ }
+ }
+
+ while (Begin.isMacroID() && BeginFileID != CaretLocFileID) {
+ if (SM->isMacroArgExpansion(Begin)) {
+ Begin = SM->getImmediateSpellingLoc(Begin);
End = SM->getImmediateSpellingLoc(End);
} else {
+ Begin = SM->getImmediateExpansionRange(Begin).first;
End = SM->getImmediateExpansionRange(End).second;
}
+ BeginFileID = SM->getFileID(Begin);
+ if (BeginFileID != SM->getFileID(End)) {
+ // FIXME: Ugly hack to stop a crash; this code is making bad
+ // assumptions and it's too complicated for me to reason
+ // about.
+ Begin = End = SourceLocation();
+ break;
+ }
}
// Return the spelling location of the beginning and end of the range.
@@ -266,6 +378,16 @@ static void mapDiagnosticRanges(
}
}
+void DiagnosticRenderer::emitCaret(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
+}
+
/// \brief Recursively emit notes for each macro expansion and caret
/// diagnostics where appropriate.
///
@@ -277,48 +399,24 @@ static void mapDiagnosticRanges(
/// \param Level The diagnostic level currently being emitted.
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
-/// \param MacroSkipEnd The depth to stop skipping macro expansions.
/// \param OnMacroInst The current depth of the macro expansion stack.
-void DiagnosticRenderer::emitMacroExpansionsAndCarets(
- SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM,
- unsigned &MacroDepth,
- unsigned OnMacroInst)
-{
+void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM,
+ unsigned &MacroDepth,
+ unsigned OnMacroInst) {
assert(!Loc.isInvalid() && "must have a valid source location here");
-
- // If this is a file source location, directly emit the source snippet and
- // caret line. Also record the macro depth reached.
- if (Loc.isFileID()) {
- // Map the ranges.
- SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
-
- assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
- MacroDepth = OnMacroInst;
- emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
- return;
- }
- // Otherwise recurse through each macro expansion layer.
-
- // When processing macros, skip over the expansions leading up to
- // a macro argument, and trace the argument's expansion stack instead.
- Loc = SM.skipToMacroArgExpansion(Loc);
-
+
+ // Walk up to the caller of this macro, and produce a backtrace down to there.
SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc);
+ if (OneLevelUp.isMacroID())
+ emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM,
+ MacroDepth, OnMacroInst + 1);
+ else
+ MacroDepth = OnMacroInst + 1;
- emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth,
- OnMacroInst + 1);
-
- // Save the original location so we can find the spelling of the macro call.
- SourceLocation MacroLoc = Loc;
-
- // Map the location.
- Loc = SM.getImmediateMacroCalleeLoc(Loc);
-
unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
if (MacroDepth > DiagOpts->MacroBacktraceLimit &&
DiagOpts->MacroBacktraceLimit != 0) {
@@ -326,11 +424,11 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
DiagOpts->MacroBacktraceLimit % 2;
MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2;
}
-
+
// Whether to suppress printing this macro expansion.
bool Suppressed = (OnMacroInst >= MacroSkipStart &&
OnMacroInst < MacroSkipEnd);
-
+
if (Suppressed) {
// Tell the user that we've skipped contexts.
if (OnMacroInst == MacroSkipStart) {
@@ -344,15 +442,27 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
return;
}
- // Map the ranges.
+ // Find the spelling location for the macro definition. We must use the
+ // spelling location here to avoid emitting a macro bactrace for the note.
+ SourceLocation SpellingLoc = Loc;
+ // If this is the expansion of a macro argument, point the caret at the
+ // use of the argument in the definition of the macro, not the expansion.
+ if (SM.isMacroArgExpansion(Loc))
+ SpellingLoc = SM.getImmediateExpansionRange(Loc).first;
+ SpellingLoc = SM.getSpellingLoc(SpellingLoc);
+
+ // Map the ranges into the FileID of the diagnostic location.
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- Message << "expanded from macro '"
- << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
- emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
+ StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts);
+ if (MacroName.empty())
+ Message << "expanded from here";
+ else
+ Message << "expanded from macro '" << MacroName << "'";
+ emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note,
Message.str(),
SpellingRanges, ArrayRef<FixItHint>(), &SM);
}
@@ -370,6 +480,32 @@ void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
emitNote(Loc, Message.str(), &SM);
}
+void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ // Generate a note indicating the include location.
+ SmallString<200> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ Message << "in module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
+ emitNote(Loc, Message.str(), &SM);
+}
+
+void
+DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ // 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() << ":";
+ 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 2e9a791c3039..6031ad2b361b 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -11,8 +11,6 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/ChainedIncludesSource.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -20,15 +18,18 @@
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Support/Timer.h"
using namespace clang;
namespace {
@@ -187,6 +188,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
setCurrentInput(Input, AST);
+ // Inform the diagnostic client we are processing a source file.
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
+ HasBegunSourceFile = true;
+
// Set the shared objects, these are reset when we finish processing the
// file, otherwise the CompilerInstance will happily destroy them.
CI.setFileManager(&AST->getFileManager());
@@ -198,7 +203,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
- /// Create the AST consumer.
+ // Create the AST consumer.
CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
if (!CI.hasASTConsumer())
goto failure;
@@ -246,16 +251,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getLangOpts(),
CI.getTargetOpts(),
CI.getPreprocessorOpts())) {
- for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) {
- if (PPOpts.Includes[I] == PPOpts.ImplicitPCHInclude) {
- PPOpts.Includes[I] = Dir->path();
- PPOpts.ImplicitPCHInclude = Dir->path();
- Found = true;
- break;
- }
- }
-
- assert(Found && "Implicit PCH include not in includes list?");
+ PPOpts.ImplicitPCHInclude = Dir->path();
+ Found = true;
break;
}
}
@@ -279,8 +276,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
- /// Create the AST context and consumer unless this is a preprocessor only
- /// action.
+ // Create the AST context and consumer unless this is a preprocessor only
+ // action.
if (!usesPreprocessorOnly()) {
CI.createASTContext();
@@ -290,8 +287,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
- CI.getPreprocessor().setPPMutationListener(
- Consumer->GetPPMutationListener());
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
@@ -380,6 +375,15 @@ bool FrontendAction::Execute() {
}
else ExecuteAction();
+ // If we are supposed to rebuild the global module index, do so now unless
+ // there were any module-build failures.
+ if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() &&
+ CI.hasPreprocessor()) {
+ GlobalModuleIndex::writeIndex(
+ CI.getFileManager(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ }
+
return true;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 47063f78b5d9..5c7567fa8c02 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -9,16 +9,17 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Pragma.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Parse/Parser.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
+#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"
@@ -173,12 +174,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
const FileEntry *Header = Module->Headers[I];
- Module->TopHeaders.insert(Header);
+ Module->addTopHeader(Header);
addHeaderInclude(Header, Includes, LangOpts);
}
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
- Module->TopHeaders.insert(UmbrellaHeader);
+ Module->addTopHeader(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
@@ -203,7 +204,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
if (ModMap.isHeaderInUnavailableModule(Header))
continue;
- Module->TopHeaders.insert(Header);
+ Module->addTopHeader(Header);
}
// Include this header umbrella header for submodules.
@@ -273,19 +274,11 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, HeaderContents);
- StringRef InputName = Module::getModuleInputBufferName();
-
- // We consistently construct a buffer as input to build the module.
- // This means the main file for modules will always be a virtual one.
- // FIXME: Maybe allow using a memory buffer as input directly instead of
- // messing with virtual files.
- const FileEntry *HeaderFile = FileMgr.getVirtualFile(InputName,
- HeaderContents.size(),
- time(0));
- llvm::MemoryBuffer *HeaderContentsBuf
- = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
- CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
- setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(),
+ llvm::MemoryBuffer *InputBuffer =
+ llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
+ Module::getModuleInputBufferName());
+ // Ownership of InputBuffer will be transfered to the SourceManager.
+ setCurrentInput(FrontendInputFile(InputBuffer, getCurrentFileKind(),
Module->IsSystem));
return true;
}
@@ -324,6 +317,130 @@ ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
return new ASTConsumer();
}
+ASTConsumer *DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return new ASTConsumer();
+}
+
+namespace {
+ /// \brief AST reader listener that dumps module information for a module
+ /// file.
+ class DumpModuleInfoListener : public ASTReaderListener {
+ llvm::raw_ostream &Out;
+
+ public:
+ DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { }
+
+#define DUMP_BOOLEAN(Value, Text) \
+ Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n"
+
+ virtual bool ReadFullVersionInformation(StringRef FullVersion) {
+ Out.indent(2)
+ << "Generated by "
+ << (FullVersion == getClangFullRepositoryVersion()? "this"
+ : "a different")
+ << " Clang: " << FullVersion << "\n";
+ return ASTReaderListener::ReadFullVersionInformation(FullVersion);
+ }
+
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ Out.indent(2) << "Language options:\n";
+#define LANGOPT(Name, Bits, Default, Description) \
+ DUMP_BOOLEAN(LangOpts.Name, Description);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Out.indent(4) << Description << ": " \
+ << static_cast<unsigned>(LangOpts.get##Name()) << "\n";
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ Out.indent(4) << Description << ": " << LangOpts.Name << "\n";
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+ return false;
+ }
+
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ 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";
+ for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size();
+ I != N; ++I) {
+ Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n";
+ }
+ }
+
+ return false;
+ }
+
+ virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ bool Complain) {
+ Out.indent(2) << "Header search options:\n";
+ Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
+ DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
+ "Use builtin include directories [-nobuiltininc]");
+ DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes,
+ "Use standard system include directories [-nostdinc]");
+ DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes,
+ "Use standard C++ include directories [-nostdinc++]");
+ DUMP_BOOLEAN(HSOpts.UseLibcxx,
+ "Use libc++ (rather than libstdc++) [-stdlib=]");
+ return false;
+ }
+
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ Out.indent(2) << "Preprocessor options:\n";
+ DUMP_BOOLEAN(PPOpts.UsePredefines,
+ "Uses compiler/target-specific predefines [-undef]");
+ DUMP_BOOLEAN(PPOpts.DetailedRecord,
+ "Uses detailed preprocessing record (for indexing)");
+
+ if (!PPOpts.Macros.empty()) {
+ Out.indent(4) << "Predefined macros:\n";
+ }
+
+ for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
+ I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end();
+ I != IEnd; ++I) {
+ Out.indent(6);
+ if (I->second)
+ Out << "-U";
+ else
+ Out << "-D";
+ Out << I->first << "\n";
+ }
+ return false;
+ }
+#undef DUMP_BOOLEAN
+ };
+}
+
+void DumpModuleInfoAction::ExecuteAction() {
+ // Set up the output file.
+ llvm::OwningPtr<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));
+ }
+ llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
+
+ Out << "Information for module file '" << getCurrentFile() << "':\n";
+ DumpModuleInfoListener Listener(Out);
+ ASTReader::readASTFileControlBlock(getCurrentFile(),
+ getCompilerInstance().getFileManager(),
+ Listener);
+}
+
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index ea4005f7c960..f1823c69e96c 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -13,7 +13,7 @@ using namespace clang;
InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
- .Case("ast", IK_AST)
+ .Cases("ast", "pcm", IK_AST)
.Case("c", IK_C)
.Cases("S", "s", IK_Asm)
.Case("i", IK_PreprocessedC)
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 4fddd112df7e..35eec565f7ac 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -14,19 +14,18 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Config/config.h" // C_INCLUDE_DIRS
#include "clang/Lex/HeaderSearch.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
-
-#include "clang/Config/config.h" // C_INCLUDE_DIRS
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::frontend;
@@ -44,19 +43,23 @@ class InitHeaderSearch {
HeaderSearch &Headers;
bool Verbose;
std::string IncludeSysroot;
- bool IsNotEmptyOrRoot;
+ bool HasSysroot;
public:
InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot)
: Headers(HS), Verbose(verbose), IncludeSysroot(sysroot),
- IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) {
+ HasSysroot(!(sysroot.empty() || sysroot == "/")) {
}
- /// AddPath - Add the specified path to the specified group list.
- void AddPath(const Twine &Path, IncludeDirGroup Group,
- bool isCXXAware, bool isUserSupplied,
- bool isFramework, bool IgnoreSysRoot = false);
+ /// AddPath - Add the specified path to the specified group list, prefixing
+ /// the sysroot if used.
+ void AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework);
+
+ /// AddUnmappedPath - Add the specified path to the specified group list,
+ /// without performing any sysroot remapping.
+ void AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
+ bool isFramework);
/// AddSystemHeaderPrefix - Add the specified prefix to the system header
/// prefix list.
@@ -105,45 +108,52 @@ public:
} // end anonymous namespace.
-void InitHeaderSearch::AddPath(const Twine &Path,
- IncludeDirGroup Group, bool isCXXAware,
- bool isUserSupplied, bool isFramework,
- bool IgnoreSysRoot) {
- assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
- FileManager &FM = Headers.getFileMgr();
-
- // Compute the actual path, taking into consideration -isysroot.
- SmallString<256> MappedPathStorage;
- StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
-
- // Handle isysroot.
- if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot &&
+static bool CanPrefixSysroot(StringRef Path) {
#if defined(_WIN32)
- !MappedPathStr.empty() &&
- llvm::sys::path::is_separator(MappedPathStr[0]) &&
+ return !Path.empty() && llvm::sys::path::is_separator(Path[0]);
#else
- llvm::sys::path::is_absolute(MappedPathStr) &&
+ return llvm::sys::path::is_absolute(Path);
#endif
- IsNotEmptyOrRoot) {
- MappedPathStorage.clear();
- MappedPathStr =
- (IncludeSysroot + Path).toStringRef(MappedPathStorage);
+}
+
+void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,
+ bool isFramework) {
+ // Add the path with sysroot prepended, if desired and this is a system header
+ // group.
+ if (HasSysroot) {
+ SmallString<256> MappedPathStorage;
+ StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
+ if (CanPrefixSysroot(MappedPathStr)) {
+ AddUnmappedPath(IncludeSysroot + Path, Group, isFramework);
+ return;
+ }
}
+ AddUnmappedPath(Path, Group, isFramework);
+}
+
+void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
+ bool isFramework) {
+ assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
+
+ FileManager &FM = Headers.getFileMgr();
+ SmallString<256> MappedPathStorage;
+ StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
+
// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
- if (Group == Quoted || Group == Angled || Group == IndexHeaderMap)
+ if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) {
Type = SrcMgr::C_User;
- else if (isCXXAware)
- Type = SrcMgr::C_System;
- else
+ } else if (Group == ExternCSystem) {
Type = SrcMgr::C_ExternCSystem;
-
+ } else {
+ Type = SrcMgr::C_System;
+ }
// If the directory exists, add it.
if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) {
- IncludePath.push_back(std::make_pair(Group, DirectoryLookup(DE, Type,
- isUserSupplied, isFramework)));
+ IncludePath.push_back(
+ std::make_pair(Group, DirectoryLookup(DE, Type, isFramework)));
return;
}
@@ -153,8 +163,9 @@ void InitHeaderSearch::AddPath(const Twine &Path,
if (const FileEntry *FE = FM.getFile(MappedPathStr)) {
if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
// It is a headermap, add it to the search path.
- IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type,
- isUserSupplied, Group == IndexHeaderMap)));
+ IncludePath.push_back(
+ std::make_pair(Group,
+ DirectoryLookup(HM, Type, Group == IndexHeaderMap)));
return;
}
}
@@ -171,42 +182,42 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base,
StringRef Dir64,
const llvm::Triple &triple) {
// Add the base dir
- AddPath(Base, CXXSystem, true, false, false);
+ AddPath(Base, CXXSystem, false);
// Add the multilib dirs
llvm::Triple::ArchType arch = triple.getArch();
bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
if (is64bit)
- AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, false);
else
- AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, false);
// Add the backward dir
- AddPath(Base + "/backward", CXXSystem, true, false, false);
+ AddPath(Base + "/backward", CXXSystem, false);
}
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,
StringRef Arch,
StringRef Version) {
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",
- CXXSystem, true, false, false);
+ CXXSystem, false);
}
void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base,
StringRef Version) {
// Assumes Base is HeaderSearchOpts' ResourceDir
AddPath(Base + "/../../../include/c++/" + Version,
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/../../../include/c++/" + Version + "/x86_64-w64-mingw32",
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/../../../include/c++/" + Version + "/i686-w64-mingw32",
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/../../../include/c++/" + Version + "/backward",
- CXXSystem, true, false, false);
+ CXXSystem, false);
}
void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
@@ -222,7 +233,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
break;
default:
// FIXME: temporary hack: hard-coded paths.
- AddPath("/usr/local/include", System, true, false, false);
+ AddPath("/usr/local/include", System, false);
break;
}
}
@@ -234,7 +245,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
// supplied path.
llvm::sys::Path P(HSOpts.ResourceDir);
P.appendComponent("include");
- AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
+ AddUnmappedPath(P.str(), ExternCSystem, false);
}
// All remaining additions are for system include directories, early exit if
@@ -250,7 +261,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
for (SmallVectorImpl<StringRef>::iterator i = dirs.begin();
i != dirs.end();
++i)
- AddPath(*i, System, false, false, false);
+ AddPath(*i, ExternCSystem, false);
return;
}
@@ -260,68 +271,59 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
llvm_unreachable("Include management is handled in the driver.");
case llvm::Triple::Haiku:
- AddPath("/boot/common/include", System, true, false, false);
- AddPath("/boot/develop/headers/os", System, true, false, false);
- AddPath("/boot/develop/headers/os/app", System, true, false, false);
- AddPath("/boot/develop/headers/os/arch", System, true, false, false);
- AddPath("/boot/develop/headers/os/device", System, true, false, false);
- AddPath("/boot/develop/headers/os/drivers", System, true, false, false);
- AddPath("/boot/develop/headers/os/game", System, true, false, false);
- AddPath("/boot/develop/headers/os/interface", System, true, false, false);
- AddPath("/boot/develop/headers/os/kernel", System, true, false, false);
- AddPath("/boot/develop/headers/os/locale", System, true, false, false);
- AddPath("/boot/develop/headers/os/mail", System, true, false, false);
- AddPath("/boot/develop/headers/os/media", System, true, false, false);
- AddPath("/boot/develop/headers/os/midi", System, true, false, false);
- AddPath("/boot/develop/headers/os/midi2", System, true, false, false);
- AddPath("/boot/develop/headers/os/net", System, true, false, false);
- AddPath("/boot/develop/headers/os/storage", System, true, false, false);
- AddPath("/boot/develop/headers/os/support", System, true, false, false);
- AddPath("/boot/develop/headers/os/translation",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/graphics",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/input_server",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/screen_saver",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/tracker",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/be_apps/Deskbar",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/be_apps/NetPositive",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/be_apps/Tracker",
- System, true, false, false);
- AddPath("/boot/develop/headers/cpp", System, true, false, false);
- AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
- System, true, false, false);
- AddPath("/boot/develop/headers/3rdparty", System, true, false, false);
- AddPath("/boot/develop/headers/bsd", System, true, false, false);
- AddPath("/boot/develop/headers/glibc", System, true, false, false);
- AddPath("/boot/develop/headers/posix", System, true, false, false);
- AddPath("/boot/develop/headers", System, true, false, false);
+ AddPath("/boot/common/include", System, false);
+ AddPath("/boot/develop/headers/os", System, false);
+ AddPath("/boot/develop/headers/os/app", System, false);
+ AddPath("/boot/develop/headers/os/arch", System, false);
+ AddPath("/boot/develop/headers/os/device", System, false);
+ AddPath("/boot/develop/headers/os/drivers", System, false);
+ AddPath("/boot/develop/headers/os/game", System, false);
+ AddPath("/boot/develop/headers/os/interface", System, false);
+ AddPath("/boot/develop/headers/os/kernel", System, false);
+ AddPath("/boot/develop/headers/os/locale", System, false);
+ AddPath("/boot/develop/headers/os/mail", System, false);
+ AddPath("/boot/develop/headers/os/media", System, false);
+ AddPath("/boot/develop/headers/os/midi", System, false);
+ AddPath("/boot/develop/headers/os/midi2", System, false);
+ AddPath("/boot/develop/headers/os/net", System, false);
+ AddPath("/boot/develop/headers/os/storage", System, false);
+ AddPath("/boot/develop/headers/os/support", System, false);
+ AddPath("/boot/develop/headers/os/translation", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/graphics", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/input_server", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/screen_saver", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/tracker", System, false);
+ AddPath("/boot/develop/headers/os/be_apps/Deskbar", System, false);
+ AddPath("/boot/develop/headers/os/be_apps/NetPositive", System, false);
+ AddPath("/boot/develop/headers/os/be_apps/Tracker", System, false);
+ AddPath("/boot/develop/headers/cpp", System, false);
+ AddPath("/boot/develop/headers/cpp/i586-pc-haiku", System, false);
+ AddPath("/boot/develop/headers/3rdparty", System, false);
+ AddPath("/boot/develop/headers/bsd", System, false);
+ AddPath("/boot/develop/headers/glibc", System, false);
+ AddPath("/boot/develop/headers/posix", System, false);
+ AddPath("/boot/develop/headers", System, false);
break;
case llvm::Triple::RTEMS:
break;
case llvm::Triple::Cygwin:
- AddPath("/usr/include/w32api", System, true, false, false);
+ AddPath("/usr/include/w32api", System, false);
break;
case llvm::Triple::MinGW32: {
// mingw-w64 crt include paths
llvm::sys::Path P(HSOpts.ResourceDir);
P.appendComponent("../../../i686-w64-mingw32/include"); // <sysroot>/i686-w64-mingw32/include
- AddPath(P.str(), System, true, false, false);
+ AddPath(P.str(), System, false);
P = llvm::sys::Path(HSOpts.ResourceDir);
P.appendComponent("../../../x86_64-w64-mingw32/include"); // <sysroot>/x86_64-w64-mingw32/include
- AddPath(P.str(), System, true, false, false);
+ AddPath(P.str(), System, false);
// mingw.org crt include paths
P = llvm::sys::Path(HSOpts.ResourceDir);
P.appendComponent("../../../include"); // <sysroot>/include
- AddPath(P.str(), System, true, false, false);
- AddPath("/mingw/include", System, true, false, false);
+ AddPath(P.str(), System, false);
+ AddPath("/mingw/include", System, false);
#if defined(_WIN32)
- AddPath("c:/mingw/include", System, true, false, false);
+ AddPath("c:/mingw/include", System, false);
#endif
}
break;
@@ -331,7 +333,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
}
if ( os != llvm::Triple::RTEMS )
- AddPath("/usr/include", System, false, false, false);
+ AddPath("/usr/include", ExternCSystem, false);
}
void InitHeaderSearch::
@@ -408,7 +410,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
#endif
break;
case llvm::Triple::DragonFly:
- AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false);
+ AddPath("/usr/include/c++/4.1", CXXSystem, false);
break;
case llvm::Triple::FreeBSD:
// FreeBSD 8.0
@@ -474,16 +476,15 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
// Get foo/lib/c++/v1
P.appendComponent("c++");
P.appendComponent("v1");
- AddPath(P.str(), CXXSystem, true, false, false, true);
+ AddUnmappedPath(P.str(), CXXSystem, false);
}
}
// On Solaris, include the support directory for things like xlocale and
// fudged system headers.
if (triple.getOS() == llvm::Triple::Solaris)
- AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, true, false,
- false);
+ AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, false);
- AddPath("/usr/include/c++/v1", CXXSystem, true, false, false);
+ AddPath("/usr/include/c++/v1", CXXSystem, false);
} else {
AddDefaultCPlusPlusIncludePaths(triple, HSOpts);
}
@@ -494,8 +495,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
// Add the default framework include paths on Darwin.
if (HSOpts.UseStandardSystemIncludes) {
if (triple.isOSDarwin()) {
- AddPath("/System/Library/Frameworks", System, true, false, true);
- AddPath("/Library/Frameworks", System, true, false, true);
+ AddPath("/System/Library/Frameworks", System, true);
+ AddPath("/Library/Frameworks", System, true);
}
}
}
@@ -613,7 +614,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
- if (it->first == System ||
+ if (it->first == System || it->first == ExternCSystem ||
(!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) ||
(/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) ||
(Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) ||
@@ -669,8 +670,11 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
// Add the user defined entries.
for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
- Init.AddPath(E.Path, E.Group, !E.ImplicitExternC, E.IsUserSupplied,
- E.IsFramework, E.IgnoreSysRoot);
+ if (E.IgnoreSysRoot) {
+ Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework);
+ } else {
+ Init.AddPath(E.Path, E.Group, E.IsFramework);
+ }
}
Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 4bbd033f1c2e..25cfac632330 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -11,17 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Version.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/FileSystem.h"
@@ -307,7 +307,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
// C++11 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201103L when compiling a
// C++ translation unit.
- if (LangOpts.CPlusPlus0x)
+ if (LangOpts.CPlusPlus11)
Builder.defineMacro("__cplusplus", "201103L");
// C++03 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 199711L when compiling a
@@ -377,7 +377,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.GNUMode)
Builder.defineMacro("__STRICT_ANSI__");
- if (LangOpts.CPlusPlus0x)
+ if (LangOpts.CPlusPlus11)
Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
if (LangOpts.ObjC1) {
@@ -490,6 +490,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder);
DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
+ DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder);
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
@@ -507,6 +508,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTypeWidth(TI.getWCharType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WINT_T__",
TI.getTypeWidth(TI.getWIntType()), TI, Builder);
+ if (TI.hasInt128Type())
+ DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
@@ -639,6 +642,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
"__attribute__((objc_ownership(none)))");
}
+ // OpenMP definition
+ if (LangOpts.OpenMP) {
+ // 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");
+ }
+
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
@@ -772,15 +785,16 @@ void clang::InitializePreprocessor(Preprocessor &PP,
AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i],
PP.getFileManager());
+ // Process -include-pch/-include-pth directives.
+ if (!InitOpts.ImplicitPCHInclude.empty())
+ AddImplicitIncludePCH(Builder, PP, InitOpts.ImplicitPCHInclude);
+ if (!InitOpts.ImplicitPTHInclude.empty())
+ AddImplicitIncludePTH(Builder, PP, InitOpts.ImplicitPTHInclude);
+
// Process -include directives.
for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
const std::string &Path = InitOpts.Includes[i];
- if (Path == InitOpts.ImplicitPTHInclude)
- AddImplicitIncludePTH(Builder, PP, Path);
- else if (Path == InitOpts.ImplicitPCHInclude)
- AddImplicitIncludePCH(Builder, PP, Path);
- else
- AddImplicitInclude(Builder, Path, PP.getFileManager());
+ AddImplicitInclude(Builder, Path, PP.getFileManager());
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
diff --git a/lib/Frontend/LayoutOverrideSource.cpp b/lib/Frontend/LayoutOverrideSource.cpp
index e0232503dfe4..924a64068fe4 100644
--- a/lib/Frontend/LayoutOverrideSource.cpp
+++ b/lib/Frontend/LayoutOverrideSource.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/Support/raw_ostream.h"
-#include <cctype>
#include <fstream>
#include <string>
@@ -17,16 +17,17 @@ using namespace clang;
/// \brief Parse a simple identifier.
static std::string parseName(StringRef S) {
- unsigned Offset = 0;
- while (Offset < S.size() &&
- (isalpha(S[Offset]) || S[Offset] == '_' ||
- (Offset > 0 && isdigit(S[Offset]))))
+ if (S.empty() || !isIdentifierHead(S[0]))
+ return "";
+
+ unsigned Offset = 1;
+ while (Offset < S.size() && isIdentifierBody(S[Offset]))
++Offset;
return S.substr(0, Offset).str();
}
-LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
+LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
std::ifstream Input(Filename.str().c_str());
if (!Input.is_open())
return;
@@ -128,10 +129,10 @@ LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
continue;
LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
- while (!LineStr.empty() && isdigit(LineStr[0])) {
+ while (!LineStr.empty() && isDigit(LineStr[0])) {
// Parse this offset.
unsigned Idx = 1;
- while (Idx < LineStr.size() && isdigit(LineStr[Idx]))
+ while (Idx < LineStr.size() && isDigit(LineStr[Idx]))
++Idx;
unsigned long long Offset = 0;
@@ -141,7 +142,7 @@ LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
// Skip over this offset, the following comma, and any spaces.
LineStr = LineStr.substr(Idx + 1);
- while (!LineStr.empty() && isspace(LineStr[0]))
+ while (!LineStr.empty() && isWhitespace(LineStr[0]))
LineStr = LineStr.substr(1);
}
}
@@ -188,7 +189,7 @@ LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
}
void LayoutOverrideSource::dump() {
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
LEnd = Layouts.end();
L != LEnd; ++L) {
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 3a04f1859bda..0a22481cb634 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -12,8 +12,8 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 992eeb0f2b9b..ba83580cb69c 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -14,7 +14,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/MultiplexConsumer.h"
-
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Serialization/ASTDeserializationListener.h"
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 30707dc0c008..f70bd7c93e53 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
@@ -21,12 +22,11 @@
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
@@ -95,6 +95,7 @@ private:
bool DisableLineMarkers;
bool DumpDefines;
bool UseLineDirective;
+ bool IsFirstFileEntered;
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os,
bool lineMarkers, bool defines)
@@ -107,6 +108,7 @@ public:
EmittedDirectiveOnThisLine = false;
FileType = SrcMgr::C_User;
Initialized = false;
+ IsFirstFileEntered = false;
// If we're in microsoft mode, use normal #line instead of line markers.
UseLineDirective = PP.getLangOpts().MicrosoftExt;
@@ -137,11 +139,15 @@ public:
diag::Mapping Map, StringRef Str);
bool HandleFirstTokOnLine(Token &Tok);
+
+ /// Move to the line of the provided source location. This will
+ /// return true if the output stream required adjustment or if
+ /// the requested location is on the first line.
bool MoveToLine(SourceLocation Loc) {
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid())
return false;
- return MoveToLine(PLoc.getLine());
+ return MoveToLine(PLoc.getLine()) || (PLoc.getLine() == 1);
}
bool MoveToLine(unsigned LineNo);
@@ -154,10 +160,10 @@ public:
void HandleNewlinesInToken(const char *TokStr, unsigned Len);
/// MacroDefined - This hook is called whenever a macro definition is seen.
- void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI);
+ void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD);
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
- void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI);
+ void MacroUndefined(const Token &MacroNameTok, const MacroDirective *MD);
};
} // end anonymous namespace
@@ -266,13 +272,25 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
Lexer::Stringify(CurFilename);
FileType = NewFileType;
- if (DisableLineMarkers) return;
+ if (DisableLineMarkers) {
+ startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
+ return;
+ }
if (!Initialized) {
WriteLineInfo(CurLine);
Initialized = true;
}
+ // Do not emit an enter marker for the main file (which we expect is the first
+ // entered file). This matches gcc, and improves compatibility with some tools
+ // which track the # line markers as a way to determine when the preprocessed
+ // output is in the context of the main file.
+ if (Reason == PPCallbacks::EnterFile && !IsFirstFileEntered) {
+ IsFirstFileEntered = true;
+ return;
+ }
+
switch (Reason) {
case PPCallbacks::EnterFile:
WriteLineInfo(CurLine, " 1", 2);
@@ -299,7 +317,8 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
/// MacroDefined - This hook is called whenever a macro definition is seen.
void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
- const MacroInfo *MI) {
+ const MacroDirective *MD) {
+ const MacroInfo *MI = MD->getMacroInfo();
// Only print out macro definitions in -dD mode.
if (!DumpDefines ||
// Ignore __FILE__ etc.
@@ -311,7 +330,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
}
void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroInfo *MI) {
+ const MacroDirective *MD) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
@@ -332,7 +351,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
unsigned char Char = Str[i];
- if (isprint(Char) && Char != '\\' && Char != '"')
+ if (isPrintable(Char) && Char != '\\' && Char != '"')
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -357,7 +376,7 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
unsigned char Char = Str[i];
- if (isprint(Char) && Char != '\\' && Char != '"')
+ if (isPrintable(Char) && Char != '\\' && Char != '"')
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -496,6 +515,9 @@ struct UnknownPragmaHandler : public PragmaHandler {
static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PrintPPOutputPPCallbacks *Callbacks,
raw_ostream &OS) {
+ bool DropComments = PP.getLangOpts().TraditionalCPP &&
+ !PP.getCommentRetentionState();
+
char Buffer[256];
Token PrevPrevTok, PrevTok;
PrevPrevTok.startToken();
@@ -518,7 +540,13 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
OS << ' ';
}
- if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ if (DropComments && Tok.is(tok::comment)) {
+ // Skip comments. Normally the preprocessor does not generate
+ // tok::comment nodes at all when not keeping comments, but under
+ // -traditional-cpp the lexer keeps /all/ whitespace, including comments.
+ SourceLocation StartLoc = Tok.getLocation();
+ Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
+ } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
Tok.getLiteralData()) {
@@ -530,7 +558,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// Tokens that can contain embedded newlines need to adjust our current
// line number.
- if (Tok.getKind() == tok::comment)
+ if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
Callbacks->HandleNewlinesInToken(TokPtr, Len);
} else {
std::string S = PP.getSpelling(Tok);
@@ -538,7 +566,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// Tokens that can contain embedded newlines need to adjust our current
// line number.
- if (Tok.getKind() == tok::comment)
+ if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
Callbacks->HandleNewlinesInToken(&S[0], S.size());
}
Callbacks->setEmittedTokensOnThisLine();
@@ -551,7 +579,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
}
}
-typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+typedef std::pair<const IdentifierInfo *, MacroInfo *> id_macro_pair;
static int MacroIDCompare(const void* a, const void* b) {
const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a);
const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b);
@@ -574,7 +602,7 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) {
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
if (I->first->hasMacroDefinition())
- MacrosByID.push_back(id_macro_pair(I->first, I->second));
+ MacrosByID.push_back(id_macro_pair(I->first, I->second->getMacroInfo()));
}
llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 5f8fc1ecfc60..4bb662bb2650 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -7,19 +7,19 @@
//
//===----------------------------------------------------------------------===//
-#include <vector>
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/DenseSet.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
using namespace clang;
using namespace clang::serialized_diags;
@@ -44,8 +44,8 @@ public:
}
};
-typedef llvm::SmallVector<uint64_t, 64> RecordData;
-typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
+typedef SmallVector<uint64_t, 64> RecordData;
+typedef SmallVectorImpl<uint64_t> RecordDataImpl;
class SDiagsWriter;
@@ -89,10 +89,16 @@ protected:
class SDiagsWriter : public DiagnosticConsumer {
friend class SDiagsRenderer;
-public:
- explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags)
- : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os),
- EmittedAnyDiagBlocks(false) {
+
+ struct SharedState;
+
+ explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)
+ : LangOpts(0), OriginalInstance(false), State(State) { }
+
+public:
+ SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags)
+ : LangOpts(0), OriginalInstance(true), State(new SharedState(os, diags))
+ {
EmitPreamble();
}
@@ -109,8 +115,7 @@ public:
virtual void finish();
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
- // It makes no sense to clone this.
- return 0;
+ return new SDiagsWriter(State);
}
private:
@@ -175,50 +180,67 @@ private:
/// \brief The version of the diagnostics file.
enum { Version = 1 };
+ /// \brief Language options, which can differ from one clone of this client
+ /// to another.
const LangOptions *LangOpts;
- llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
-
- /// \brief The byte buffer for the serialized content.
- SmallString<1024> Buffer;
- /// \brief The BitStreamWriter for the serialized diagnostics.
- llvm::BitstreamWriter Stream;
+ /// \brief Whether this is the original instance (rather than one of its
+ /// clones), responsible for writing the file at the end.
+ bool OriginalInstance;
- /// \brief The name of the diagnostics file.
- OwningPtr<llvm::raw_ostream> OS;
-
- /// \brief The set of constructed record abbreviations.
- AbbreviationMap Abbrevs;
+ /// \brief State that is shared among the various clones of this diagnostic
+ /// consumer.
+ struct SharedState : RefCountedBase<SharedState> {
+ SharedState(raw_ostream *os, DiagnosticOptions *diags)
+ : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { }
- /// \brief A utility buffer for constructing record content.
- RecordData Record;
+ /// \brief Diagnostic options.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
- /// \brief A text buffer for rendering diagnostic text.
- SmallString<256> diagBuf;
-
- /// \brief The collection of diagnostic categories used.
- llvm::DenseSet<unsigned> Categories;
-
- /// \brief The collection of files used.
- llvm::DenseMap<const char *, unsigned> Files;
+ /// \brief The byte buffer for the serialized content.
+ SmallString<1024> Buffer;
+
+ /// \brief The BitStreamWriter for the serialized diagnostics.
+ llvm::BitstreamWriter Stream;
+
+ /// \brief The name of the diagnostics file.
+ OwningPtr<raw_ostream> OS;
+
+ /// \brief The set of constructed record abbreviations.
+ AbbreviationMap Abbrevs;
+
+ /// \brief A utility buffer for constructing record content.
+ RecordData Record;
+
+ /// \brief A text buffer for rendering diagnostic text.
+ SmallString<256> diagBuf;
+
+ /// \brief The collection of diagnostic categories used.
+ llvm::DenseSet<unsigned> Categories;
+
+ /// \brief The collection of files used.
+ llvm::DenseMap<const char *, unsigned> Files;
+
+ typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
+ DiagFlagsTy;
- typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
- DiagFlagsTy;
+ /// \brief Map for uniquing strings.
+ DiagFlagsTy DiagFlags;
- /// \brief Map for uniquing strings.
- DiagFlagsTy DiagFlags;
+ /// \brief Whether we have already started emission of any DIAG blocks. Once
+ /// this becomes \c true, we never close a DIAG block until we know that we're
+ /// starting another one or we're done.
+ bool EmittedAnyDiagBlocks;
+ };
- /// \brief Whether we have already started emission of any DIAG blocks. Once
- /// this becomes \c true, we never close a DIAG block until we know that we're
- /// starting another one or we're done.
- bool EmittedAnyDiagBlocks;
+ /// \brief State shared among the various clones of this diagnostic consumer.
+ IntrusiveRefCntPtr<SharedState> State;
};
} // end anonymous namespace
namespace clang {
namespace serialized_diags {
-DiagnosticConsumer *create(llvm::raw_ostream *OS,
- DiagnosticOptions *diags) {
+DiagnosticConsumer *create(raw_ostream *OS, DiagnosticOptions *diags) {
return new SDiagsWriter(OS, diags);
}
} // end namespace serialized_diags
@@ -297,12 +319,12 @@ unsigned SDiagsWriter::getEmitFile(const char *FileName){
if (!FileName)
return 0;
- unsigned &entry = Files[FileName];
+ unsigned &entry = State->Files[FileName];
if (entry)
return entry;
// Lazily generate the record for the file.
- entry = Files.size();
+ entry = State->Files.size();
RecordData Record;
Record.push_back(RECORD_FILENAME);
Record.push_back(entry);
@@ -310,26 +332,28 @@ unsigned SDiagsWriter::getEmitFile(const char *FileName){
Record.push_back(0); // For legacy.
StringRef Name(FileName);
Record.push_back(Name.size());
- Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
+ State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record,
+ Name);
return entry;
}
void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
const SourceManager &SM) {
- Record.clear();
- Record.push_back(RECORD_SOURCE_RANGE);
- AddCharSourceRangeToRecord(R, Record, SM);
- Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
+ State->Record.clear();
+ State->Record.push_back(RECORD_SOURCE_RANGE);
+ AddCharSourceRangeToRecord(R, State->Record, SM);
+ State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
+ State->Record);
}
/// \brief Emits the preamble of the diagnostics file.
void SDiagsWriter::EmitPreamble() {
// Emit the file header.
- Stream.Emit((unsigned)'D', 8);
- Stream.Emit((unsigned)'I', 8);
- Stream.Emit((unsigned)'A', 8);
- Stream.Emit((unsigned)'G', 8);
+ State->Stream.Emit((unsigned)'D', 8);
+ State->Stream.Emit((unsigned)'I', 8);
+ State->Stream.Emit((unsigned)'A', 8);
+ State->Stream.Emit((unsigned)'G', 8);
EmitBlockInfoBlock();
EmitMetaBlock();
@@ -349,9 +373,12 @@ static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
}
void SDiagsWriter::EmitBlockInfoBlock() {
- Stream.EnterBlockInfoBlock(3);
+ State->Stream.EnterBlockInfoBlock(3);
using namespace llvm;
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
// ==---------------------------------------------------------------------==//
// The subsequent records and Abbrevs are for the "Meta" block.
@@ -435,6 +462,10 @@ void SDiagsWriter::EmitBlockInfoBlock() {
}
void SDiagsWriter::EmitMetaBlock() {
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
+
Stream.EnterSubblock(BLOCK_META, 3);
Record.clear();
Record.push_back(RECORD_VERSION);
@@ -444,10 +475,10 @@ void SDiagsWriter::EmitMetaBlock() {
}
unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
- if (Categories.count(category))
+ if (State->Categories.count(category))
return category;
- Categories.insert(category);
+ State->Categories.insert(category);
// We use a local version of 'Record' so that we can be generating
// another record when we lazily generate one for the category entry.
@@ -456,7 +487,8 @@ unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
Record.push_back(category);
StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Record.push_back(catName.size());
- Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
+ State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
+ catName);
return category;
}
@@ -473,9 +505,9 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
// Here we assume that FlagName points to static data whose pointer
// value is fixed. This allows us to unique by diagnostic groups.
const void *data = FlagName.data();
- std::pair<unsigned, StringRef> &entry = DiagFlags[data];
+ std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
if (entry.first == 0) {
- entry.first = DiagFlags.size();
+ entry.first = State->DiagFlags.size();
entry.second = FlagName;
// Lazily emit the string in a separate record.
@@ -483,8 +515,8 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
Record.push_back(RECORD_DIAG_FLAG);
Record.push_back(entry.first);
Record.push_back(FlagName.size());
- Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
- Record, FlagName);
+ State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG),
+ Record, FlagName);
}
return entry.first;
@@ -496,31 +528,41 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
// for beginDiagnostic, in case associated notes are emitted before we get
// there.
if (DiagLevel != DiagnosticsEngine::Note) {
- if (EmittedAnyDiagBlocks)
+ if (State->EmittedAnyDiagBlocks)
ExitDiagBlock();
EnterDiagBlock();
- EmittedAnyDiagBlocks = true;
+ State->EmittedAnyDiagBlocks = true;
}
// Compute the diagnostic text.
- diagBuf.clear();
- Info.FormatDiagnostic(diagBuf);
+ State->diagBuf.clear();
+ Info.FormatDiagnostic(State->diagBuf);
if (Info.getLocation().isInvalid()) {
// Special-case diagnostics with no location. We may not have entered a
// source file in this case, so we can't use the normal DiagnosticsRenderer
// machinery.
+
+ // Make sure we bracket all notes as "sub-diagnostics". This matches
+ // the behavior in SDiagsRenderer::emitDiagnostic().
+ if (DiagLevel == DiagnosticsEngine::Note)
+ EnterDiagBlock();
+
EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
- diagBuf, 0, &Info);
+ State->diagBuf, 0, &Info);
+
+ if (DiagLevel == DiagnosticsEngine::Note)
+ ExitDiagBlock();
+
return;
}
assert(Info.hasSourceManager() && LangOpts &&
"Unexpected diagnostic with valid location outside of a source file");
- SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts);
+ SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
- diagBuf.str(),
+ State->diagBuf.str(),
Info.getRanges(),
llvm::makeArrayRef(Info.getFixItHints(),
Info.getNumFixItHints()),
@@ -534,6 +576,10 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
StringRef Message,
const SourceManager *SM,
DiagOrStoredDiag D) {
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
+
// Emit the RECORD_DIAG record.
Record.clear();
Record.push_back(RECORD_DIAG);
@@ -567,11 +613,11 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
}
void SDiagsWriter::EnterDiagBlock() {
- Stream.EnterSubblock(BLOCK_DIAG, 4);
+ State->Stream.EnterSubblock(BLOCK_DIAG, 4);
}
void SDiagsWriter::ExitDiagBlock() {
- Stream.ExitBlock();
+ State->Stream.ExitBlock();
}
void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
@@ -591,6 +637,10 @@ void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
ArrayRef<FixItHint> Hints,
const SourceManager &SM) {
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
+
// Emit Source Ranges.
for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
I != E; ++I)
@@ -630,13 +680,17 @@ void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
}
void SDiagsWriter::finish() {
+ // The original instance is responsible for writing the file.
+ if (!OriginalInstance)
+ return;
+
// Finish off any diagnostic we were in the process of emitting.
- if (EmittedAnyDiagBlocks)
+ if (State->EmittedAnyDiagBlocks)
ExitDiagBlock();
// Write the generated bitstream to "Out".
- OS->write((char *)&Buffer.front(), Buffer.size());
- OS->flush();
+ State->OS->write((char *)&State->Buffer.front(), State->Buffer.size());
+ State->OS->flush();
- OS.reset(0);
+ State->OS.reset(0);
}
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 35dabad60657..ca4ad60c524d 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -8,19 +8,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/TextDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/ConvertUTF.h"
-#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Locale.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Locale.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <cctype>
using namespace clang;
@@ -248,6 +248,7 @@ static void columnToByte(StringRef SourceLine, unsigned TabStop,
out.back() = i;
}
+namespace {
struct SourceColumnMap {
SourceColumnMap(StringRef SourceLine, unsigned TabStop)
: m_SourceLine(SourceLine) {
@@ -313,14 +314,13 @@ private:
};
// used in assert in selectInterestingSourceRegion()
-namespace {
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
/// the terminal, select the "interesting" region.
@@ -348,11 +348,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// correctly.
unsigned CaretStart = 0, CaretEnd = CaretLine.size();
for (; CaretStart != CaretEnd; ++CaretStart)
- if (!isspace(static_cast<unsigned char>(CaretLine[CaretStart])))
+ if (!isWhitespace(CaretLine[CaretStart]))
break;
for (; CaretEnd != CaretStart; --CaretEnd)
- if (!isspace(static_cast<unsigned char>(CaretLine[CaretEnd - 1])))
+ if (!isWhitespace(CaretLine[CaretEnd - 1]))
break;
// caret has already been inserted into CaretLine so the above whitespace
@@ -363,11 +363,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
if (!FixItInsertionLine.empty()) {
unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
for (; FixItStart != FixItEnd; ++FixItStart)
- if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItStart])))
+ if (!isWhitespace(FixItInsertionLine[FixItStart]))
break;
for (; FixItEnd != FixItStart; --FixItEnd)
- if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItEnd - 1])))
+ if (!isWhitespace(FixItInsertionLine[FixItEnd - 1]))
break;
CaretStart = std::min(FixItStart, CaretStart);
@@ -423,14 +423,13 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
// FIXME: Detect non-ASCII whitespace characters too.
- while (NewStart &&
- isspace(static_cast<unsigned char>(SourceLine[NewStart])))
+ while (NewStart && isWhitespace(SourceLine[NewStart]))
NewStart = map.startOfPreviousColumn(NewStart);
// Skip over this bit of "interesting" text.
while (NewStart) {
unsigned Prev = map.startOfPreviousColumn(NewStart);
- if (isspace(static_cast<unsigned char>(SourceLine[Prev])))
+ if (isWhitespace(SourceLine[Prev]))
break;
NewStart = Prev;
}
@@ -450,13 +449,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
// FIXME: Detect non-ASCII whitespace characters too.
- while (NewEnd < SourceLine.size() &&
- isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
NewEnd = map.startOfNextColumn(NewEnd);
// Skip over this bit of "interesting" text.
- while (NewEnd < SourceLine.size() &&
- !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
NewEnd = map.startOfNextColumn(NewEnd);
assert(map.byteToColumn(NewEnd) != -1);
@@ -517,7 +514,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
/// greater than or equal to Idx or, if no such character exists,
/// returns the end of the string.
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
- while (Idx < Length && isspace(Str[Idx]))
+ while (Idx < Length && isWhitespace(Str[Idx]))
++Idx;
return Idx;
}
@@ -562,7 +559,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str,
char EndPunct = findMatchingPunctuation(Str[Start]);
if (!EndPunct) {
// This is a normal word. Just find the first space character.
- while (End < Length && !isspace(Str[End]))
+ while (End < Length && !isWhitespace(Str[End]))
++End;
return End;
}
@@ -581,7 +578,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str,
}
// Find the first space character after the punctuation ended.
- while (End < Length && !isspace(Str[End]))
+ while (End < Length && !isWhitespace(Str[End]))
++End;
unsigned PunctWordLength = End - Start;
@@ -884,6 +881,178 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
OS << "In included file:\n";
}
+void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ if (DiagOpts->ShowLocation)
+ OS << "In module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
+ else
+ OS << "In module " << ModuleName << "':\n";
+}
+
+void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ if (DiagOpts->ShowLocation && PLoc.getFilename())
+ OS << "While building module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
+ else
+ OS << "While building module '" << ModuleName << "':\n";
+}
+
+/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
+static void highlightRange(const CharSourceRange &R,
+ unsigned LineNo, FileID FID,
+ const SourceColumnMap &map,
+ std::string &CaretLine,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (!R.isValid()) return;
+
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+
+ unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
+ if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
+ return; // No intersection.
+
+ unsigned EndLineNo = SM.getExpansionLineNumber(End);
+ if (EndLineNo < LineNo || SM.getFileID(End) != FID)
+ return; // No intersection.
+
+ // Compute the column number of the start.
+ unsigned StartColNo = 0;
+ if (StartLineNo == LineNo) {
+ StartColNo = SM.getExpansionColumnNumber(Begin);
+ if (StartColNo) --StartColNo; // Zero base the col #.
+ }
+
+ // Compute the column number of the end.
+ unsigned EndColNo = map.getSourceLine().size();
+ if (EndLineNo == LineNo) {
+ EndColNo = SM.getExpansionColumnNumber(End);
+ if (EndColNo) {
+ --EndColNo; // Zero base the col #.
+
+ // Add in the length of the token, so that we cover multi-char tokens if
+ // this is a token range.
+ if (R.isTokenRange())
+ EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
+ } else {
+ EndColNo = CaretLine.size();
+ }
+ }
+
+ assert(StartColNo <= EndColNo && "Invalid range!");
+
+ // Check that a token range does not highlight only whitespace.
+ if (R.isTokenRange()) {
+ // Pick the first non-whitespace column.
+ while (StartColNo < map.getSourceLine().size() &&
+ (map.getSourceLine()[StartColNo] == ' ' ||
+ map.getSourceLine()[StartColNo] == '\t'))
+ StartColNo = map.startOfNextColumn(StartColNo);
+
+ // Pick the last non-whitespace column.
+ if (EndColNo > map.getSourceLine().size())
+ EndColNo = map.getSourceLine().size();
+ while (EndColNo &&
+ (map.getSourceLine()[EndColNo-1] == ' ' ||
+ map.getSourceLine()[EndColNo-1] == '\t'))
+ EndColNo = map.startOfPreviousColumn(EndColNo);
+
+ // If the start/end passed each other, then we are trying to highlight a
+ // range that just exists in whitespace, which must be some sort of other
+ // bug.
+ assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ }
+
+ assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
+ assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
+
+ // Fill the range with ~'s.
+ StartColNo = map.byteToContainingColumn(StartColNo);
+ EndColNo = map.byteToContainingColumn(EndColNo);
+
+ assert(StartColNo <= EndColNo && "Invalid range!");
+ if (CaretLine.size() < EndColNo)
+ CaretLine.resize(EndColNo,' ');
+ std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
+}
+
+static std::string buildFixItInsertionLine(unsigned LineNo,
+ const SourceColumnMap &map,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM,
+ const DiagnosticOptions *DiagOpts) {
+ std::string FixItInsertionLine;
+ if (Hints.empty() || !DiagOpts->ShowFixits)
+ return FixItInsertionLine;
+ unsigned PrevHintEndCol = 0;
+
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ if (!I->CodeToInsert.empty()) {
+ // We have an insertion hint. Determine whether the inserted
+ // code contains no newlines and is on the same line as the caret.
+ std::pair<FileID, unsigned> HintLocInfo
+ = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
+ if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
+ StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
+ // Insert the new code into the line just below the code
+ // that the user wrote.
+ // Note: When modifying this function, be very careful about what is a
+ // "column" (printed width, platform-dependent) and what is a
+ // "byte offset" (SourceManager "column").
+ unsigned HintByteOffset
+ = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
+
+ // The hint must start inside the source or right at the end
+ assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
+ unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
+
+ // If we inserted a long previous hint, push this one forwards, and add
+ // an extra space to show that this is not part of the previous
+ // completion. This is sort of the best we can do when two hints appear
+ // to overlap.
+ //
+ // Note that if this hint is located immediately after the previous
+ // hint, no space will be added, since the location is more important.
+ if (HintCol < PrevHintEndCol)
+ HintCol = PrevHintEndCol + 1;
+
+ // FIXME: This function handles multibyte characters in the source, but
+ // not in the fixits. This assertion is intended to catch unintended
+ // use of multibyte characters in fixits. If we decide to do this, we'll
+ // have to track separate byte widths for the source and fixit lines.
+ assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) ==
+ I->CodeToInsert.size());
+
+ // This relies on one byte per column in our fixit hints.
+ // This should NOT use HintByteOffset, because the source might have
+ // Unicode characters in earlier columns.
+ unsigned LastColumnModified = HintCol + I->CodeToInsert.size();
+ if (LastColumnModified > FixItInsertionLine.size())
+ FixItInsertionLine.resize(LastColumnModified, ' ');
+
+ std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
+ FixItInsertionLine.begin() + HintCol);
+
+ PrevHintEndCol = LastColumnModified;
+ } else {
+ FixItInsertionLine.clear();
+ break;
+ }
+ }
+ }
+
+ expandTabs(FixItInsertionLine, DiagOpts->TabStop);
+
+ return FixItInsertionLine;
+}
+
/// \brief Emit a code snippet and caret line.
///
/// This routine emits a single line's code snippet and caret line..
@@ -924,18 +1093,26 @@ void TextDiagnostic::emitSnippetAndCaret(
unsigned LineNo = SM.getLineNumber(FID, FileOffset);
unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
+
+ // Arbitrarily stop showing snippets when the line is too long.
+ static const ptrdiff_t MaxLineLengthToPrint = 4096;
+ if (ColNo > MaxLineLengthToPrint)
+ return;
// Rewind from the current position to the start of the line.
const char *TokPtr = BufStart+FileOffset;
const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
-
// Compute the line end. Scan forward from the error position to the end of
// the line.
const char *LineEnd = TokPtr;
while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0')
++LineEnd;
+ // Arbitrarily stop showing snippets when the line is too long.
+ if (LineEnd - LineStart > MaxLineLengthToPrint)
+ return;
+
// Copy the line of code into an std::string for ease of manipulation.
std::string SourceLine(LineStart, LineEnd);
@@ -949,7 +1126,7 @@ void TextDiagnostic::emitSnippetAndCaret(
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
E = Ranges.end();
I != E; ++I)
- highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM);
+ highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
// Next, insert the caret itself.
ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
@@ -959,7 +1136,8 @@ void TextDiagnostic::emitSnippetAndCaret(
std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
sourceColMap,
- Hints, SM);
+ Hints, SM,
+ DiagOpts.getPtr());
// If the source line is too long for our terminal, select only the
// "interesting" source region within that line.
@@ -1041,157 +1219,6 @@ void TextDiagnostic::emitSnippet(StringRef line) {
OS << '\n';
}
-/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
-void TextDiagnostic::highlightRange(const CharSourceRange &R,
- unsigned LineNo, FileID FID,
- const SourceColumnMap &map,
- std::string &CaretLine,
- const SourceManager &SM) {
- if (!R.isValid()) return;
-
- SourceLocation Begin = R.getBegin();
- SourceLocation End = R.getEnd();
-
- unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
- if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
- return; // No intersection.
-
- unsigned EndLineNo = SM.getExpansionLineNumber(End);
- if (EndLineNo < LineNo || SM.getFileID(End) != FID)
- return; // No intersection.
-
- // Compute the column number of the start.
- unsigned StartColNo = 0;
- if (StartLineNo == LineNo) {
- StartColNo = SM.getExpansionColumnNumber(Begin);
- if (StartColNo) --StartColNo; // Zero base the col #.
- }
-
- // Compute the column number of the end.
- unsigned EndColNo = map.getSourceLine().size();
- if (EndLineNo == LineNo) {
- EndColNo = SM.getExpansionColumnNumber(End);
- if (EndColNo) {
- --EndColNo; // Zero base the col #.
-
- // Add in the length of the token, so that we cover multi-char tokens if
- // this is a token range.
- if (R.isTokenRange())
- EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
- } else {
- EndColNo = CaretLine.size();
- }
- }
-
- assert(StartColNo <= EndColNo && "Invalid range!");
-
- // Check that a token range does not highlight only whitespace.
- if (R.isTokenRange()) {
- // Pick the first non-whitespace column.
- while (StartColNo < map.getSourceLine().size() &&
- (map.getSourceLine()[StartColNo] == ' ' ||
- map.getSourceLine()[StartColNo] == '\t'))
- StartColNo = map.startOfNextColumn(StartColNo);
-
- // Pick the last non-whitespace column.
- if (EndColNo > map.getSourceLine().size())
- EndColNo = map.getSourceLine().size();
- while (EndColNo-1 &&
- (map.getSourceLine()[EndColNo-1] == ' ' ||
- map.getSourceLine()[EndColNo-1] == '\t'))
- EndColNo = map.startOfPreviousColumn(EndColNo);
-
- // If the start/end passed each other, then we are trying to highlight a
- // range that just exists in whitespace, which must be some sort of other
- // bug.
- assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
- }
-
- assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
- assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
-
- // Fill the range with ~'s.
- StartColNo = map.byteToContainingColumn(StartColNo);
- EndColNo = map.byteToContainingColumn(EndColNo);
-
- assert(StartColNo <= EndColNo && "Invalid range!");
- if (CaretLine.size() < EndColNo)
- CaretLine.resize(EndColNo,' ');
- std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
-}
-
-std::string TextDiagnostic::buildFixItInsertionLine(
- unsigned LineNo,
- const SourceColumnMap &map,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
-
- std::string FixItInsertionLine;
- if (Hints.empty() || !DiagOpts->ShowFixits)
- return FixItInsertionLine;
- unsigned PrevHintEndCol = 0;
-
- for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
- I != E; ++I) {
- if (!I->CodeToInsert.empty()) {
- // We have an insertion hint. Determine whether the inserted
- // code contains no newlines and is on the same line as the caret.
- std::pair<FileID, unsigned> HintLocInfo
- = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
- if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
- StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
- // Insert the new code into the line just below the code
- // that the user wrote.
- // Note: When modifying this function, be very careful about what is a
- // "column" (printed width, platform-dependent) and what is a
- // "byte offset" (SourceManager "column").
- unsigned HintByteOffset
- = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
-
- // The hint must start inside the source or right at the end
- assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
- unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
-
- // If we inserted a long previous hint, push this one forwards, and add
- // an extra space to show that this is not part of the previous
- // completion. This is sort of the best we can do when two hints appear
- // to overlap.
- //
- // Note that if this hint is located immediately after the previous
- // hint, no space will be added, since the location is more important.
- if (HintCol < PrevHintEndCol)
- HintCol = PrevHintEndCol + 1;
-
- // FIXME: This function handles multibyte characters in the source, but
- // not in the fixits. This assertion is intended to catch unintended
- // use of multibyte characters in fixits. If we decide to do this, we'll
- // have to track separate byte widths for the source and fixit lines.
- assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) ==
- I->CodeToInsert.size());
-
- // This relies on one byte per column in our fixit hints.
- // This should NOT use HintByteOffset, because the source might have
- // Unicode characters in earlier columns.
- unsigned LastColumnModified = HintCol + I->CodeToInsert.size();
- if (LastColumnModified > FixItInsertionLine.size())
- FixItInsertionLine.resize(LastColumnModified, ' ');
-
- std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
- FixItInsertionLine.begin() + HintCol);
-
- PrevHintEndCol = LastColumnModified;
- } else {
- FixItInsertionLine.clear();
- break;
- }
- }
- }
-
- expandTabs(FixItInsertionLine, DiagOpts->TabStop);
-
- return FixItInsertionLine;
-}
-
void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
const SourceManager &SM) {
if (!DiagOpts->ShowParseableFixits)
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index 57105f15a30a..039475a2e04f 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -42,17 +42,37 @@ 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,
- it->second.c_str()));
+ escapeDiag(it->second, Buf)));
for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it)
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning,
- it->second.c_str()));
+ escapeDiag(it->second, Buf)));
for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it)
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note,
- it->second.c_str()));
+ escapeDiag(it->second, Buf)));
}
DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const {
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index aa7a61a60f9e..010f649e6b73 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -17,10 +17,10 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/ADT/SmallString.h"
#include <algorithm>
using namespace clang;
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 1750946af497..82f6e916e58d 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -11,8 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/FileManager.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Lex/HeaderSearch.h"
@@ -20,7 +21,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
-#include <cctype>
using namespace clang;
typedef VerifyDiagnosticConsumer::Directive Directive;
@@ -234,7 +234,7 @@ public:
break;
if (!EnsureStartOfWord
// Check if string literal starts a new word.
- || P == Begin || isspace(P[-1])
+ || P == Begin || isWhitespace(P[-1])
// Or it could be preceeded by the start of a comment.
|| (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
&& P[-2] == '/'))
@@ -253,7 +253,7 @@ public:
// Skip zero or more whitespace.
void SkipWhitespace() {
- for (; C < End && isspace(*C); ++C)
+ for (; C < End && isWhitespace(*C); ++C)
;
}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index f789b7f3053f..b7547b9998e7 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -22,13 +22,13 @@
//
#include "clang/Frontend/Utils.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Lex/LexDiagnostic.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>
-#include <algorithm>
using namespace clang;
// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
@@ -48,13 +48,15 @@ static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
}
void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
- const DiagnosticOptions &Opts) {
+ const DiagnosticOptions &Opts,
+ bool ReportDiags) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
Diags.setShowOverloads(Opts.getShowOverloads());
Diags.setElideType(Opts.ElideType);
Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
+ Diags.setWarnOnSpellCheck(Opts.WarnOnSpellCheck);
Diags.setShowColors(Opts.ShowColors);
// Handle -ferror-limit
@@ -75,7 +77,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
else
Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);
- llvm::SmallVector<diag::kind, 10> _Diags;
+ SmallVector<diag::kind, 10> _Diags;
const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
Diags.getDiagnosticIDs();
// We parse the warning options twice. The first pass sets diagnostic state,
@@ -84,6 +86,12 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// conflicting options.
for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {
bool SetDiagnostic = (Report == 0);
+
+ // If we've set the diagnostic state and are not reporting diagnostics then
+ // we're done.
+ if (!SetDiagnostic && !ReportDiags)
+ break;
+
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
StringRef Opt = Opts.Warnings[i];
StringRef OrigOpt = Opts.Warnings[i];
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index c7c55b021145..b0d76da33425 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -13,24 +13,25 @@
//===----------------------------------------------------------------------===//
#include "clang/FrontendTool/Utils.h"
-#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
+ StringRef Action("unknown");
switch (CI.getFrontendOpts().ProgramAction) {
case ASTDeclList: return new ASTDeclListAction();
@@ -42,17 +43,26 @@ 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 PluginAction: {
for (FrontendPluginRegistry::iterator it =
@@ -74,19 +84,46 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case PrintDeclContext: return new DeclContextPrintAction();
case PrintPreamble: return new PrintPreambleAction();
case PrintPreprocessedInput: {
- if (CI.getPreprocessorOutputOpts().RewriteIncludes)
+ if (CI.getPreprocessorOutputOpts().RewriteIncludes) {
+#ifdef CLANG_ENABLE_REWRITER
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();
- case RunAnalysis: return new ento::AnalysisAction();
+#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();
+#else
+ case MigrateSource: Action = "MigrateSource"; break;
+#endif
+#ifdef CLANG_ENABLE_STATIC_ANALYZER
+ case RunAnalysis: return new ento::AnalysisAction();
+#else
+ case RunAnalysis: Action = "RunAnalysis"; break;
+#endif
case RunPreprocessorOnly: return new PreprocessOnlyAction();
}
+
+#if !defined(CLANG_ENABLE_ARCMT) || !defined(CLANG_ENABLE_STATIC_ANALYZER) \
+ || !defined(CLANG_ENABLE_REWRITER)
+ CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action;
+ return 0;
+#else
llvm_unreachable("Invalid program action!");
+#endif
}
static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
@@ -97,10 +134,13 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = CI.getFrontendOpts();
+#ifdef CLANG_ENABLE_REWRITER
if (FEOpts.FixAndRecompile) {
Act = new FixItRecompile(Act);
}
+#endif
+#ifdef CLANG_ENABLE_ARCMT
// Potentially wrap the base FE action in an ARC Migrate Tool action.
switch (FEOpts.ARCMTAction) {
case FrontendOptions::ARCMT_None:
@@ -124,6 +164,7 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals,
FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting);
}
+#endif
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
@@ -176,24 +217,24 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
}
+#ifdef CLANG_ENABLE_STATIC_ANALYZER
// Honor -analyzer-checker-help.
// This should happen AFTER plugins have been loaded!
if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
return 0;
}
+#endif
// If there were errors in processing arguments, don't do anything else.
- bool Success = false;
- if (!Clang->getDiagnostics().hasErrorOccurred()) {
- // Create and execute the frontend action.
- OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
- if (Act) {
- Success = Clang->ExecuteAction(*Act);
- if (Clang->getFrontendOpts().DisableFree)
- Act.take();
- }
- }
-
+ if (Clang->getDiagnostics().hasErrorOccurred())
+ return false;
+ // Create and execute the frontend action.
+ OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
+ if (!Act)
+ return false;
+ bool Success = Clang->ExecuteAction(*Act);
+ if (Clang->getFrontendOpts().DisableFree)
+ Act.take();
return Success;
}
diff --git a/lib/FrontendTool/Makefile b/lib/FrontendTool/Makefile
index c43213ff99d0..9ce4b767fe58 100644
--- a/lib/FrontendTool/Makefile
+++ b/lib/FrontendTool/Makefile
@@ -11,3 +11,18 @@ CLANG_LEVEL := ../..
LIBRARYNAME := clangFrontendTool
include $(CLANG_LEVEL)/Makefile
+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
+endif
+
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+ CXX.Flags += -DCLANG_ENABLE_STATIC_ANALYZER
+endif
+
+
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 25e4d903bb78..5e727a7b2e27 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -20,6 +20,8 @@ set(files
nmmintrin.h
pmmintrin.h
popcntintrin.h
+ prfchwintrin.h
+ rdseedintrin.h
rtmintrin.h
smmintrin.h
stdalign.h
@@ -27,6 +29,7 @@ set(files
stdbool.h
stddef.h
stdint.h
+ stdnoreturn.h
tgmath.h
tmmintrin.h
varargs.h
@@ -92,6 +95,13 @@ 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 create_symlink "${LLVM_BINARY_DIR}/bin/lib/clang" "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/clang")
+ endif()
+endif ()
+
install(FILES ${files} ${output_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/altivec.h b/lib/Headers/altivec.h
index 2bf53fb43b9b..74ce08aa6fea 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -37,41 +37,41 @@
#define __ATTRS_o_ai __attribute__((__overloadable__, __always_inline__))
static vector signed char __ATTRS_o_ai
-vec_perm(vector signed char a, vector signed char b, vector unsigned char c);
+vec_perm(vector signed char __a, vector signed char __b, vector unsigned char __c);
static vector unsigned char __ATTRS_o_ai
-vec_perm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned char c);
+vec_perm(vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned char __c);
static vector bool char __ATTRS_o_ai
-vec_perm(vector bool char a, vector bool char b, vector unsigned char c);
+vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c);
static vector short __ATTRS_o_ai
-vec_perm(vector short a, vector short b, vector unsigned char c);
+vec_perm(vector short __a, vector short __b, vector unsigned char __c);
static vector unsigned short __ATTRS_o_ai
-vec_perm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned char c);
+vec_perm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned char __c);
static vector bool short __ATTRS_o_ai
-vec_perm(vector bool short a, vector bool short b, vector unsigned char c);
+vec_perm(vector bool short __a, vector bool short __b, vector unsigned char __c);
static vector pixel __ATTRS_o_ai
-vec_perm(vector pixel a, vector pixel b, vector unsigned char c);
+vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c);
static vector int __ATTRS_o_ai
-vec_perm(vector int a, vector int b, vector unsigned char c);
+vec_perm(vector int __a, vector int __b, vector unsigned char __c);
static vector unsigned int __ATTRS_o_ai
-vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c);
+vec_perm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c);
static vector bool int __ATTRS_o_ai
-vec_perm(vector bool int a, vector bool int b, vector unsigned char c);
+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);
+vec_perm(vector float __a, vector float __b, vector unsigned char __c);
/* vec_abs */
@@ -80,29 +80,29 @@ vec_perm(vector float a, vector float b, vector unsigned char c);
#define __builtin_altivec_abs_v4si vec_abs
static vector signed char __ATTRS_o_ai
-vec_abs(vector signed char a)
+vec_abs(vector signed char __a)
{
- return __builtin_altivec_vmaxsb(a, -a);
+ return __builtin_altivec_vmaxsb(__a, -__a);
}
static vector signed short __ATTRS_o_ai
-vec_abs(vector signed short a)
+vec_abs(vector signed short __a)
{
- return __builtin_altivec_vmaxsh(a, -a);
+ return __builtin_altivec_vmaxsh(__a, -__a);
}
static vector signed int __ATTRS_o_ai
-vec_abs(vector signed int a)
+vec_abs(vector signed int __a)
{
- return __builtin_altivec_vmaxsw(a, -a);
+ return __builtin_altivec_vmaxsw(__a, -__a);
}
static vector float __ATTRS_o_ai
-vec_abs(vector float a)
+vec_abs(vector float __a)
{
- vector unsigned int res = (vector unsigned int)a
+ vector unsigned int __res = (vector unsigned int)__a
& (vector unsigned int)(0x7FFFFFFF);
- return (vector float)res;
+ return (vector float)__res;
}
/* vec_abss */
@@ -112,140 +112,140 @@ vec_abs(vector float a)
#define __builtin_altivec_abss_v4si vec_abss
static vector signed char __ATTRS_o_ai
-vec_abss(vector signed char a)
+vec_abss(vector signed char __a)
{
return __builtin_altivec_vmaxsb
- (a, __builtin_altivec_vsubsbs((vector signed char)(0), a));
+ (__a, __builtin_altivec_vsubsbs((vector signed char)(0), __a));
}
static vector signed short __ATTRS_o_ai
-vec_abss(vector signed short a)
+vec_abss(vector signed short __a)
{
return __builtin_altivec_vmaxsh
- (a, __builtin_altivec_vsubshs((vector signed short)(0), a));
+ (__a, __builtin_altivec_vsubshs((vector signed short)(0), __a));
}
static vector signed int __ATTRS_o_ai
-vec_abss(vector signed int a)
+vec_abss(vector signed int __a)
{
return __builtin_altivec_vmaxsw
- (a, __builtin_altivec_vsubsws((vector signed int)(0), a));
+ (__a, __builtin_altivec_vsubsws((vector signed int)(0), __a));
}
/* vec_add */
static vector signed char __ATTRS_o_ai
-vec_add(vector signed char a, vector signed char b)
+vec_add(vector signed char __a, vector signed char __b)
{
- return a + b;
+ return __a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_add(vector bool char a, vector signed char b)
+vec_add(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a + b;
+ return (vector signed char)__a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_add(vector signed char a, vector bool char b)
+vec_add(vector signed char __a, vector bool char __b)
{
- return a + (vector signed char)b;
+ return __a + (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_add(vector unsigned char a, vector unsigned char b)
+vec_add(vector unsigned char __a, vector unsigned char __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_add(vector bool char a, vector unsigned char b)
+vec_add(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a + b;
+ return (vector unsigned char)__a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_add(vector unsigned char a, vector bool char b)
+vec_add(vector unsigned char __a, vector bool char __b)
{
- return a + (vector unsigned char)b;
+ return __a + (vector unsigned char)__b;
}
static vector short __ATTRS_o_ai
-vec_add(vector short a, vector short b)
+vec_add(vector short __a, vector short __b)
{
- return a + b;
+ return __a + __b;
}
static vector short __ATTRS_o_ai
-vec_add(vector bool short a, vector short b)
+vec_add(vector bool short __a, vector short __b)
{
- return (vector short)a + b;
+ return (vector short)__a + __b;
}
static vector short __ATTRS_o_ai
-vec_add(vector short a, vector bool short b)
+vec_add(vector short __a, vector bool short __b)
{
- return a + (vector short)b;
+ return __a + (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_add(vector unsigned short a, vector unsigned short b)
+vec_add(vector unsigned short __a, vector unsigned short __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_add(vector bool short a, vector unsigned short b)
+vec_add(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a + b;
+ return (vector unsigned short)__a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_add(vector unsigned short a, vector bool short b)
+vec_add(vector unsigned short __a, vector bool short __b)
{
- return a + (vector unsigned short)b;
+ return __a + (vector unsigned short)__b;
}
static vector int __ATTRS_o_ai
-vec_add(vector int a, vector int b)
+vec_add(vector int __a, vector int __b)
{
- return a + b;
+ return __a + __b;
}
static vector int __ATTRS_o_ai
-vec_add(vector bool int a, vector int b)
+vec_add(vector bool int __a, vector int __b)
{
- return (vector int)a + b;
+ return (vector int)__a + __b;
}
static vector int __ATTRS_o_ai
-vec_add(vector int a, vector bool int b)
+vec_add(vector int __a, vector bool int __b)
{
- return a + (vector int)b;
+ return __a + (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_add(vector unsigned int a, vector unsigned int b)
+vec_add(vector unsigned int __a, vector unsigned int __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_add(vector bool int a, vector unsigned int b)
+vec_add(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a + b;
+ return (vector unsigned int)__a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_add(vector unsigned int a, vector bool int b)
+vec_add(vector unsigned int __a, vector bool int __b)
{
- return a + (vector unsigned int)b;
+ return __a + (vector unsigned int)__b;
}
static vector float __ATTRS_o_ai
-vec_add(vector float a, vector float b)
+vec_add(vector float __a, vector float __b)
{
- return a + b;
+ return __a + __b;
}
/* vec_vaddubm */
@@ -253,39 +253,39 @@ vec_add(vector float a, vector float b)
#define __builtin_altivec_vaddubm vec_vaddubm
static vector signed char __ATTRS_o_ai
-vec_vaddubm(vector signed char a, vector signed char b)
+vec_vaddubm(vector signed char __a, vector signed char __b)
{
- return a + b;
+ return __a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_vaddubm(vector bool char a, vector signed char b)
+vec_vaddubm(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a + b;
+ return (vector signed char)__a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_vaddubm(vector signed char a, vector bool char b)
+vec_vaddubm(vector signed char __a, vector bool char __b)
{
- return a + (vector signed char)b;
+ return __a + (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubm(vector unsigned char a, vector unsigned char b)
+vec_vaddubm(vector unsigned char __a, vector unsigned char __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubm(vector bool char a, vector unsigned char b)
+vec_vaddubm(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a + b;
+ return (vector unsigned char)__a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubm(vector unsigned char a, vector bool char b)
+vec_vaddubm(vector unsigned char __a, vector bool char __b)
{
- return a + (vector unsigned char)b;
+ return __a + (vector unsigned char)__b;
}
/* vec_vadduhm */
@@ -293,39 +293,39 @@ vec_vaddubm(vector unsigned char a, vector bool char b)
#define __builtin_altivec_vadduhm vec_vadduhm
static vector short __ATTRS_o_ai
-vec_vadduhm(vector short a, vector short b)
+vec_vadduhm(vector short __a, vector short __b)
{
- return a + b;
+ return __a + __b;
}
static vector short __ATTRS_o_ai
-vec_vadduhm(vector bool short a, vector short b)
+vec_vadduhm(vector bool short __a, vector short __b)
{
- return (vector short)a + b;
+ return (vector short)__a + __b;
}
static vector short __ATTRS_o_ai
-vec_vadduhm(vector short a, vector bool short b)
+vec_vadduhm(vector short __a, vector bool short __b)
{
- return a + (vector short)b;
+ return __a + (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhm(vector unsigned short a, vector unsigned short b)
+vec_vadduhm(vector unsigned short __a, vector unsigned short __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhm(vector bool short a, vector unsigned short b)
+vec_vadduhm(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a + b;
+ return (vector unsigned short)__a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhm(vector unsigned short a, vector bool short b)
+vec_vadduhm(vector unsigned short __a, vector bool short __b)
{
- return a + (vector unsigned short)b;
+ return __a + (vector unsigned short)__b;
}
/* vec_vadduwm */
@@ -333,39 +333,39 @@ vec_vadduhm(vector unsigned short a, vector bool short b)
#define __builtin_altivec_vadduwm vec_vadduwm
static vector int __ATTRS_o_ai
-vec_vadduwm(vector int a, vector int b)
+vec_vadduwm(vector int __a, vector int __b)
{
- return a + b;
+ return __a + __b;
}
static vector int __ATTRS_o_ai
-vec_vadduwm(vector bool int a, vector int b)
+vec_vadduwm(vector bool int __a, vector int __b)
{
- return (vector int)a + b;
+ return (vector int)__a + __b;
}
static vector int __ATTRS_o_ai
-vec_vadduwm(vector int a, vector bool int b)
+vec_vadduwm(vector int __a, vector bool int __b)
{
- return a + (vector int)b;
+ return __a + (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduwm(vector unsigned int a, vector unsigned int b)
+vec_vadduwm(vector unsigned int __a, vector unsigned int __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduwm(vector bool int a, vector unsigned int b)
+vec_vadduwm(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a + b;
+ return (vector unsigned int)__a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduwm(vector unsigned int a, vector bool int b)
+vec_vadduwm(vector unsigned int __a, vector bool int __b)
{
- return a + (vector unsigned int)b;
+ return __a + (vector unsigned int)__b;
}
/* vec_vaddfp */
@@ -373,255 +373,255 @@ vec_vadduwm(vector unsigned int a, vector bool int b)
#define __builtin_altivec_vaddfp vec_vaddfp
static vector float __attribute__((__always_inline__))
-vec_vaddfp(vector float a, vector float b)
+vec_vaddfp(vector float __a, vector float __b)
{
- return a + b;
+ return __a + __b;
}
/* vec_addc */
static vector unsigned int __attribute__((__always_inline__))
-vec_addc(vector unsigned int a, vector unsigned int b)
+vec_addc(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vaddcuw(a, b);
+ return __builtin_altivec_vaddcuw(__a, __b);
}
/* vec_vaddcuw */
static vector unsigned int __attribute__((__always_inline__))
-vec_vaddcuw(vector unsigned int a, vector unsigned int b)
+vec_vaddcuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vaddcuw(a, b);
+ return __builtin_altivec_vaddcuw(__a, __b);
}
/* vec_adds */
static vector signed char __ATTRS_o_ai
-vec_adds(vector signed char a, vector signed char b)
+vec_adds(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs(a, b);
+ return __builtin_altivec_vaddsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_adds(vector bool char a, vector signed char b)
+vec_adds(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs((vector signed char)a, b);
+ return __builtin_altivec_vaddsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_adds(vector signed char a, vector bool char b)
+vec_adds(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vaddsbs(a, (vector signed char)b);
+ return __builtin_altivec_vaddsbs(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_adds(vector unsigned char a, vector unsigned char b)
+vec_adds(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs(a, b);
+ return __builtin_altivec_vaddubs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_adds(vector bool char a, vector unsigned char b)
+vec_adds(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs((vector unsigned char)a, b);
+ return __builtin_altivec_vaddubs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_adds(vector unsigned char a, vector bool char b)
+vec_adds(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vaddubs(a, (vector unsigned char)b);
+ return __builtin_altivec_vaddubs(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_adds(vector short a, vector short b)
+vec_adds(vector short __a, vector short __b)
{
- return __builtin_altivec_vaddshs(a, b);
+ return __builtin_altivec_vaddshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_adds(vector bool short a, vector short b)
+vec_adds(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vaddshs((vector short)a, b);
+ return __builtin_altivec_vaddshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_adds(vector short a, vector bool short b)
+vec_adds(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vaddshs(a, (vector short)b);
+ return __builtin_altivec_vaddshs(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_adds(vector unsigned short a, vector unsigned short b)
+vec_adds(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs(a, b);
+ return __builtin_altivec_vadduhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_adds(vector bool short a, vector unsigned short b)
+vec_adds(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs((vector unsigned short)a, b);
+ return __builtin_altivec_vadduhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_adds(vector unsigned short a, vector bool short b)
+vec_adds(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vadduhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vadduhs(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_adds(vector int a, vector int b)
+vec_adds(vector int __a, vector int __b)
{
- return __builtin_altivec_vaddsws(a, b);
+ return __builtin_altivec_vaddsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_adds(vector bool int a, vector int b)
+vec_adds(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vaddsws((vector int)a, b);
+ return __builtin_altivec_vaddsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_adds(vector int a, vector bool int b)
+vec_adds(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vaddsws(a, (vector int)b);
+ return __builtin_altivec_vaddsws(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_adds(vector unsigned int a, vector unsigned int b)
+vec_adds(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws(a, b);
+ return __builtin_altivec_vadduws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_adds(vector bool int a, vector unsigned int b)
+vec_adds(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws((vector unsigned int)a, b);
+ return __builtin_altivec_vadduws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_adds(vector unsigned int a, vector bool int b)
+vec_adds(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vadduws(a, (vector unsigned int)b);
+ return __builtin_altivec_vadduws(__a, (vector unsigned int)__b);
}
/* vec_vaddsbs */
static vector signed char __ATTRS_o_ai
-vec_vaddsbs(vector signed char a, vector signed char b)
+vec_vaddsbs(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs(a, b);
+ return __builtin_altivec_vaddsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vaddsbs(vector bool char a, vector signed char b)
+vec_vaddsbs(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs((vector signed char)a, b);
+ return __builtin_altivec_vaddsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vaddsbs(vector signed char a, vector bool char b)
+vec_vaddsbs(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vaddsbs(a, (vector signed char)b);
+ return __builtin_altivec_vaddsbs(__a, (vector signed char)__b);
}
/* vec_vaddubs */
static vector unsigned char __ATTRS_o_ai
-vec_vaddubs(vector unsigned char a, vector unsigned char b)
+vec_vaddubs(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs(a, b);
+ return __builtin_altivec_vaddubs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubs(vector bool char a, vector unsigned char b)
+vec_vaddubs(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs((vector unsigned char)a, b);
+ return __builtin_altivec_vaddubs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubs(vector unsigned char a, vector bool char b)
+vec_vaddubs(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vaddubs(a, (vector unsigned char)b);
+ return __builtin_altivec_vaddubs(__a, (vector unsigned char)__b);
}
/* vec_vaddshs */
static vector short __ATTRS_o_ai
-vec_vaddshs(vector short a, vector short b)
+vec_vaddshs(vector short __a, vector short __b)
{
- return __builtin_altivec_vaddshs(a, b);
+ return __builtin_altivec_vaddshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vaddshs(vector bool short a, vector short b)
+vec_vaddshs(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vaddshs((vector short)a, b);
+ return __builtin_altivec_vaddshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vaddshs(vector short a, vector bool short b)
+vec_vaddshs(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vaddshs(a, (vector short)b);
+ return __builtin_altivec_vaddshs(__a, (vector short)__b);
}
/* vec_vadduhs */
static vector unsigned short __ATTRS_o_ai
-vec_vadduhs(vector unsigned short a, vector unsigned short b)
+vec_vadduhs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs(a, b);
+ return __builtin_altivec_vadduhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhs(vector bool short a, vector unsigned short b)
+vec_vadduhs(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs((vector unsigned short)a, b);
+ return __builtin_altivec_vadduhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhs(vector unsigned short a, vector bool short b)
+vec_vadduhs(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vadduhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vadduhs(__a, (vector unsigned short)__b);
}
/* vec_vaddsws */
static vector int __ATTRS_o_ai
-vec_vaddsws(vector int a, vector int b)
+vec_vaddsws(vector int __a, vector int __b)
{
- return __builtin_altivec_vaddsws(a, b);
+ return __builtin_altivec_vaddsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vaddsws(vector bool int a, vector int b)
+vec_vaddsws(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vaddsws((vector int)a, b);
+ return __builtin_altivec_vaddsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vaddsws(vector int a, vector bool int b)
+vec_vaddsws(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vaddsws(a, (vector int)b);
+ return __builtin_altivec_vaddsws(__a, (vector int)__b);
}
/* vec_vadduws */
static vector unsigned int __ATTRS_o_ai
-vec_vadduws(vector unsigned int a, vector unsigned int b)
+vec_vadduws(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws(a, b);
+ return __builtin_altivec_vadduws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduws(vector bool int a, vector unsigned int b)
+vec_vadduws(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws((vector unsigned int)a, b);
+ return __builtin_altivec_vadduws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduws(vector unsigned int a, vector bool int b)
+vec_vadduws(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vadduws(a, (vector unsigned int)b);
+ return __builtin_altivec_vadduws(__a, (vector unsigned int)__b);
}
/* vec_and */
@@ -629,299 +629,299 @@ vec_vadduws(vector unsigned int a, vector bool int b)
#define __builtin_altivec_vand vec_and
static vector signed char __ATTRS_o_ai
-vec_and(vector signed char a, vector signed char b)
+vec_and(vector signed char __a, vector signed char __b)
{
- return a & b;
+ return __a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_and(vector bool char a, vector signed char b)
+vec_and(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & b;
+ return (vector signed char)__a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_and(vector signed char a, vector bool char b)
+vec_and(vector signed char __a, vector bool char __b)
{
- return a & (vector signed char)b;
+ return __a & (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_and(vector unsigned char a, vector unsigned char b)
+vec_and(vector unsigned char __a, vector unsigned char __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_and(vector bool char a, vector unsigned char b)
+vec_and(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & b;
+ return (vector unsigned char)__a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_and(vector unsigned char a, vector bool char b)
+vec_and(vector unsigned char __a, vector bool char __b)
{
- return a & (vector unsigned char)b;
+ return __a & (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_and(vector bool char a, vector bool char b)
+vec_and(vector bool char __a, vector bool char __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_and(vector short a, vector short b)
+vec_and(vector short __a, vector short __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_and(vector bool short a, vector short b)
+vec_and(vector bool short __a, vector short __b)
{
- return (vector short)a & b;
+ return (vector short)__a & __b;
}
static vector short __ATTRS_o_ai
-vec_and(vector short a, vector bool short b)
+vec_and(vector short __a, vector bool short __b)
{
- return a & (vector short)b;
+ return __a & (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_and(vector unsigned short a, vector unsigned short b)
+vec_and(vector unsigned short __a, vector unsigned short __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_and(vector bool short a, vector unsigned short b)
+vec_and(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & b;
+ return (vector unsigned short)__a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_and(vector unsigned short a, vector bool short b)
+vec_and(vector unsigned short __a, vector bool short __b)
{
- return a & (vector unsigned short)b;
+ return __a & (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_and(vector bool short a, vector bool short b)
+vec_and(vector bool short __a, vector bool short __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_and(vector int a, vector int b)
+vec_and(vector int __a, vector int __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_and(vector bool int a, vector int b)
+vec_and(vector bool int __a, vector int __b)
{
- return (vector int)a & b;
+ return (vector int)__a & __b;
}
static vector int __ATTRS_o_ai
-vec_and(vector int a, vector bool int b)
+vec_and(vector int __a, vector bool int __b)
{
- return a & (vector int)b;
+ return __a & (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_and(vector unsigned int a, vector unsigned int b)
+vec_and(vector unsigned int __a, vector unsigned int __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_and(vector bool int a, vector unsigned int b)
+vec_and(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & b;
+ return (vector unsigned int)__a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_and(vector unsigned int a, vector bool int b)
+vec_and(vector unsigned int __a, vector bool int __b)
{
- return a & (vector unsigned int)b;
+ return __a & (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_and(vector bool int a, vector bool int b)
+vec_and(vector bool int __a, vector bool int __b)
{
- return a & b;
+ return __a & __b;
}
static vector float __ATTRS_o_ai
-vec_and(vector float a, vector float b)
+vec_and(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_and(vector bool int a, vector float b)
+vec_and(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_and(vector float a, vector bool int b)
+vec_and(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vand */
static vector signed char __ATTRS_o_ai
-vec_vand(vector signed char a, vector signed char b)
+vec_vand(vector signed char __a, vector signed char __b)
{
- return a & b;
+ return __a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_vand(vector bool char a, vector signed char b)
+vec_vand(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & b;
+ return (vector signed char)__a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_vand(vector signed char a, vector bool char b)
+vec_vand(vector signed char __a, vector bool char __b)
{
- return a & (vector signed char)b;
+ return __a & (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vand(vector unsigned char a, vector unsigned char b)
+vec_vand(vector unsigned char __a, vector unsigned char __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vand(vector bool char a, vector unsigned char b)
+vec_vand(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & b;
+ return (vector unsigned char)__a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vand(vector unsigned char a, vector bool char b)
+vec_vand(vector unsigned char __a, vector bool char __b)
{
- return a & (vector unsigned char)b;
+ return __a & (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vand(vector bool char a, vector bool char b)
+vec_vand(vector bool char __a, vector bool char __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_vand(vector short a, vector short b)
+vec_vand(vector short __a, vector short __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_vand(vector bool short a, vector short b)
+vec_vand(vector bool short __a, vector short __b)
{
- return (vector short)a & b;
+ return (vector short)__a & __b;
}
static vector short __ATTRS_o_ai
-vec_vand(vector short a, vector bool short b)
+vec_vand(vector short __a, vector bool short __b)
{
- return a & (vector short)b;
+ return __a & (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vand(vector unsigned short a, vector unsigned short b)
+vec_vand(vector unsigned short __a, vector unsigned short __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vand(vector bool short a, vector unsigned short b)
+vec_vand(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & b;
+ return (vector unsigned short)__a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vand(vector unsigned short a, vector bool short b)
+vec_vand(vector unsigned short __a, vector bool short __b)
{
- return a & (vector unsigned short)b;
+ return __a & (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vand(vector bool short a, vector bool short b)
+vec_vand(vector bool short __a, vector bool short __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_vand(vector int a, vector int b)
+vec_vand(vector int __a, vector int __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_vand(vector bool int a, vector int b)
+vec_vand(vector bool int __a, vector int __b)
{
- return (vector int)a & b;
+ return (vector int)__a & __b;
}
static vector int __ATTRS_o_ai
-vec_vand(vector int a, vector bool int b)
+vec_vand(vector int __a, vector bool int __b)
{
- return a & (vector int)b;
+ return __a & (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vand(vector unsigned int a, vector unsigned int b)
+vec_vand(vector unsigned int __a, vector unsigned int __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vand(vector bool int a, vector unsigned int b)
+vec_vand(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & b;
+ return (vector unsigned int)__a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vand(vector unsigned int a, vector bool int b)
+vec_vand(vector unsigned int __a, vector bool int __b)
{
- return a & (vector unsigned int)b;
+ return __a & (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vand(vector bool int a, vector bool int b)
+vec_vand(vector bool int __a, vector bool int __b)
{
- return a & b;
+ return __a & __b;
}
static vector float __ATTRS_o_ai
-vec_vand(vector float a, vector float b)
+vec_vand(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vand(vector bool int a, vector float b)
+vec_vand(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vand(vector float a, vector bool int b)
+vec_vand(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_andc */
@@ -929,703 +929,703 @@ vec_vand(vector float a, vector bool int b)
#define __builtin_altivec_vandc vec_andc
static vector signed char __ATTRS_o_ai
-vec_andc(vector signed char a, vector signed char b)
+vec_andc(vector signed char __a, vector signed char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_andc(vector bool char a, vector signed char b)
+vec_andc(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & ~b;
+ return (vector signed char)__a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_andc(vector signed char a, vector bool char b)
+vec_andc(vector signed char __a, vector bool char __b)
{
- return a & ~(vector signed char)b;
+ return __a & ~(vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_andc(vector unsigned char a, vector unsigned char b)
+vec_andc(vector unsigned char __a, vector unsigned char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_andc(vector bool char a, vector unsigned char b)
+vec_andc(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & ~b;
+ return (vector unsigned char)__a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_andc(vector unsigned char a, vector bool char b)
+vec_andc(vector unsigned char __a, vector bool char __b)
{
- return a & ~(vector unsigned char)b;
+ return __a & ~(vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_andc(vector bool char a, vector bool char b)
+vec_andc(vector bool char __a, vector bool char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_andc(vector short a, vector short b)
+vec_andc(vector short __a, vector short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_andc(vector bool short a, vector short b)
+vec_andc(vector bool short __a, vector short __b)
{
- return (vector short)a & ~b;
+ return (vector short)__a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_andc(vector short a, vector bool short b)
+vec_andc(vector short __a, vector bool short __b)
{
- return a & ~(vector short)b;
+ return __a & ~(vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_andc(vector unsigned short a, vector unsigned short b)
+vec_andc(vector unsigned short __a, vector unsigned short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_andc(vector bool short a, vector unsigned short b)
+vec_andc(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & ~b;
+ return (vector unsigned short)__a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_andc(vector unsigned short a, vector bool short b)
+vec_andc(vector unsigned short __a, vector bool short __b)
{
- return a & ~(vector unsigned short)b;
+ return __a & ~(vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_andc(vector bool short a, vector bool short b)
+vec_andc(vector bool short __a, vector bool short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_andc(vector int a, vector int b)
+vec_andc(vector int __a, vector int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_andc(vector bool int a, vector int b)
+vec_andc(vector bool int __a, vector int __b)
{
- return (vector int)a & ~b;
+ return (vector int)__a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_andc(vector int a, vector bool int b)
+vec_andc(vector int __a, vector bool int __b)
{
- return a & ~(vector int)b;
+ return __a & ~(vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_andc(vector unsigned int a, vector unsigned int b)
+vec_andc(vector unsigned int __a, vector unsigned int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_andc(vector bool int a, vector unsigned int b)
+vec_andc(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & ~b;
+ return (vector unsigned int)__a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_andc(vector unsigned int a, vector bool int b)
+vec_andc(vector unsigned int __a, vector bool int __b)
{
- return a & ~(vector unsigned int)b;
+ return __a & ~(vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_andc(vector bool int a, vector bool int b)
+vec_andc(vector bool int __a, vector bool int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector float __ATTRS_o_ai
-vec_andc(vector float a, vector float b)
+vec_andc(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_andc(vector bool int a, vector float b)
+vec_andc(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_andc(vector float a, vector bool int b)
+vec_andc(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vandc */
static vector signed char __ATTRS_o_ai
-vec_vandc(vector signed char a, vector signed char b)
+vec_vandc(vector signed char __a, vector signed char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_vandc(vector bool char a, vector signed char b)
+vec_vandc(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & ~b;
+ return (vector signed char)__a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_vandc(vector signed char a, vector bool char b)
+vec_vandc(vector signed char __a, vector bool char __b)
{
- return a & ~(vector signed char)b;
+ return __a & ~(vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vandc(vector unsigned char a, vector unsigned char b)
+vec_vandc(vector unsigned char __a, vector unsigned char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vandc(vector bool char a, vector unsigned char b)
+vec_vandc(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & ~b;
+ return (vector unsigned char)__a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vandc(vector unsigned char a, vector bool char b)
+vec_vandc(vector unsigned char __a, vector bool char __b)
{
- return a & ~(vector unsigned char)b;
+ return __a & ~(vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vandc(vector bool char a, vector bool char b)
+vec_vandc(vector bool char __a, vector bool char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_vandc(vector short a, vector short b)
+vec_vandc(vector short __a, vector short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_vandc(vector bool short a, vector short b)
+vec_vandc(vector bool short __a, vector short __b)
{
- return (vector short)a & ~b;
+ return (vector short)__a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_vandc(vector short a, vector bool short b)
+vec_vandc(vector short __a, vector bool short __b)
{
- return a & ~(vector short)b;
+ return __a & ~(vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vandc(vector unsigned short a, vector unsigned short b)
+vec_vandc(vector unsigned short __a, vector unsigned short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vandc(vector bool short a, vector unsigned short b)
+vec_vandc(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & ~b;
+ return (vector unsigned short)__a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vandc(vector unsigned short a, vector bool short b)
+vec_vandc(vector unsigned short __a, vector bool short __b)
{
- return a & ~(vector unsigned short)b;
+ return __a & ~(vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vandc(vector bool short a, vector bool short b)
+vec_vandc(vector bool short __a, vector bool short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_vandc(vector int a, vector int b)
+vec_vandc(vector int __a, vector int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_vandc(vector bool int a, vector int b)
+vec_vandc(vector bool int __a, vector int __b)
{
- return (vector int)a & ~b;
+ return (vector int)__a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_vandc(vector int a, vector bool int b)
+vec_vandc(vector int __a, vector bool int __b)
{
- return a & ~(vector int)b;
+ return __a & ~(vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vandc(vector unsigned int a, vector unsigned int b)
+vec_vandc(vector unsigned int __a, vector unsigned int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vandc(vector bool int a, vector unsigned int b)
+vec_vandc(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & ~b;
+ return (vector unsigned int)__a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vandc(vector unsigned int a, vector bool int b)
+vec_vandc(vector unsigned int __a, vector bool int __b)
{
- return a & ~(vector unsigned int)b;
+ return __a & ~(vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vandc(vector bool int a, vector bool int b)
+vec_vandc(vector bool int __a, vector bool int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector float __ATTRS_o_ai
-vec_vandc(vector float a, vector float b)
+vec_vandc(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vandc(vector bool int a, vector float b)
+vec_vandc(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vandc(vector float a, vector bool int b)
+vec_vandc(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_avg */
static vector signed char __ATTRS_o_ai
-vec_avg(vector signed char a, vector signed char b)
+vec_avg(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vavgsb(a, b);
+ return __builtin_altivec_vavgsb(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_avg(vector unsigned char a, vector unsigned char b)
+vec_avg(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vavgub(a, b);
+ return __builtin_altivec_vavgub(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_avg(vector short a, vector short b)
+vec_avg(vector short __a, vector short __b)
{
- return __builtin_altivec_vavgsh(a, b);
+ return __builtin_altivec_vavgsh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_avg(vector unsigned short a, vector unsigned short b)
+vec_avg(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vavguh(a, b);
+ return __builtin_altivec_vavguh(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_avg(vector int a, vector int b)
+vec_avg(vector int __a, vector int __b)
{
- return __builtin_altivec_vavgsw(a, b);
+ return __builtin_altivec_vavgsw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_avg(vector unsigned int a, vector unsigned int b)
+vec_avg(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vavguw(a, b);
+ return __builtin_altivec_vavguw(__a, __b);
}
/* vec_vavgsb */
static vector signed char __attribute__((__always_inline__))
-vec_vavgsb(vector signed char a, vector signed char b)
+vec_vavgsb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vavgsb(a, b);
+ return __builtin_altivec_vavgsb(__a, __b);
}
/* vec_vavgub */
static vector unsigned char __attribute__((__always_inline__))
-vec_vavgub(vector unsigned char a, vector unsigned char b)
+vec_vavgub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vavgub(a, b);
+ return __builtin_altivec_vavgub(__a, __b);
}
/* vec_vavgsh */
static vector short __attribute__((__always_inline__))
-vec_vavgsh(vector short a, vector short b)
+vec_vavgsh(vector short __a, vector short __b)
{
- return __builtin_altivec_vavgsh(a, b);
+ return __builtin_altivec_vavgsh(__a, __b);
}
/* vec_vavguh */
static vector unsigned short __attribute__((__always_inline__))
-vec_vavguh(vector unsigned short a, vector unsigned short b)
+vec_vavguh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vavguh(a, b);
+ return __builtin_altivec_vavguh(__a, __b);
}
/* vec_vavgsw */
static vector int __attribute__((__always_inline__))
-vec_vavgsw(vector int a, vector int b)
+vec_vavgsw(vector int __a, vector int __b)
{
- return __builtin_altivec_vavgsw(a, b);
+ return __builtin_altivec_vavgsw(__a, __b);
}
/* vec_vavguw */
static vector unsigned int __attribute__((__always_inline__))
-vec_vavguw(vector unsigned int a, vector unsigned int b)
+vec_vavguw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vavguw(a, b);
+ return __builtin_altivec_vavguw(__a, __b);
}
/* vec_ceil */
static vector float __attribute__((__always_inline__))
-vec_ceil(vector float a)
+vec_ceil(vector float __a)
{
- return __builtin_altivec_vrfip(a);
+ return __builtin_altivec_vrfip(__a);
}
/* vec_vrfip */
static vector float __attribute__((__always_inline__))
-vec_vrfip(vector float a)
+vec_vrfip(vector float __a)
{
- return __builtin_altivec_vrfip(a);
+ return __builtin_altivec_vrfip(__a);
}
/* vec_cmpb */
static vector int __attribute__((__always_inline__))
-vec_cmpb(vector float a, vector float b)
+vec_cmpb(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp(a, b);
+ return __builtin_altivec_vcmpbfp(__a, __b);
}
/* vec_vcmpbfp */
static vector int __attribute__((__always_inline__))
-vec_vcmpbfp(vector float a, vector float b)
+vec_vcmpbfp(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp(a, b);
+ return __builtin_altivec_vcmpbfp(__a, __b);
}
/* vec_cmpeq */
static vector bool char __ATTRS_o_ai
-vec_cmpeq(vector signed char a, vector signed char b)
+vec_cmpeq(vector signed char __a, vector signed char __b)
{
return (vector bool char)
- __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb((vector char)__a, (vector char)__b);
}
static vector bool char __ATTRS_o_ai
-vec_cmpeq(vector unsigned char a, vector unsigned char b)
+vec_cmpeq(vector unsigned char __a, vector unsigned char __b)
{
return (vector bool char)
- __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb((vector char)__a, (vector char)__b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpeq(vector short a, vector short b)
+vec_cmpeq(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpequh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpequh(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpeq(vector unsigned short a, vector unsigned short b)
+vec_cmpeq(vector unsigned short __a, vector unsigned short __b)
{
return (vector bool short)
- __builtin_altivec_vcmpequh((vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh((vector short)__a, (vector short)__b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpeq(vector int a, vector int b)
+vec_cmpeq(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpequw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpequw(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpeq(vector unsigned int a, vector unsigned int b)
+vec_cmpeq(vector unsigned int __a, vector unsigned int __b)
{
return (vector bool int)
- __builtin_altivec_vcmpequw((vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpeq(vector float a, vector float b)
+vec_cmpeq(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpeqfp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpeqfp(__a, __b);
}
/* vec_cmpge */
static vector bool int __attribute__((__always_inline__))
-vec_cmpge(vector float a, vector float b)
+vec_cmpge(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgefp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgefp(__a, __b);
}
/* vec_vcmpgefp */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgefp(vector float a, vector float b)
+vec_vcmpgefp(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgefp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgefp(__a, __b);
}
/* vec_cmpgt */
static vector bool char __ATTRS_o_ai
-vec_cmpgt(vector signed char a, vector signed char b)
+vec_cmpgt(vector signed char __a, vector signed char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtsb(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtsb(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_cmpgt(vector unsigned char a, vector unsigned char b)
+vec_cmpgt(vector unsigned char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtub(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtub(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpgt(vector short a, vector short b)
+vec_cmpgt(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtsh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtsh(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpgt(vector unsigned short a, vector unsigned short b)
+vec_cmpgt(vector unsigned short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtuh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtuh(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpgt(vector int a, vector int b)
+vec_cmpgt(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtsw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtsw(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpgt(vector unsigned int a, vector unsigned int b)
+vec_cmpgt(vector unsigned int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtuw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtuw(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpgt(vector float a, vector float b)
+vec_cmpgt(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtfp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtfp(__a, __b);
}
/* vec_vcmpgtsb */
static vector bool char __attribute__((__always_inline__))
-vec_vcmpgtsb(vector signed char a, vector signed char b)
+vec_vcmpgtsb(vector signed char __a, vector signed char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtsb(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtsb(__a, __b);
}
/* vec_vcmpgtub */
static vector bool char __attribute__((__always_inline__))
-vec_vcmpgtub(vector unsigned char a, vector unsigned char b)
+vec_vcmpgtub(vector unsigned char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtub(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtub(__a, __b);
}
/* vec_vcmpgtsh */
static vector bool short __attribute__((__always_inline__))
-vec_vcmpgtsh(vector short a, vector short b)
+vec_vcmpgtsh(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtsh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtsh(__a, __b);
}
/* vec_vcmpgtuh */
static vector bool short __attribute__((__always_inline__))
-vec_vcmpgtuh(vector unsigned short a, vector unsigned short b)
+vec_vcmpgtuh(vector unsigned short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtuh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtuh(__a, __b);
}
/* vec_vcmpgtsw */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgtsw(vector int a, vector int b)
+vec_vcmpgtsw(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtsw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtsw(__a, __b);
}
/* vec_vcmpgtuw */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgtuw(vector unsigned int a, vector unsigned int b)
+vec_vcmpgtuw(vector unsigned int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtuw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtuw(__a, __b);
}
/* vec_vcmpgtfp */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgtfp(vector float a, vector float b)
+vec_vcmpgtfp(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtfp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtfp(__a, __b);
}
/* vec_cmple */
static vector bool int __attribute__((__always_inline__))
-vec_cmple(vector float a, vector float b)
+vec_cmple(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgefp(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgefp(__b, __a);
}
/* vec_cmplt */
static vector bool char __ATTRS_o_ai
-vec_cmplt(vector signed char a, vector signed char b)
+vec_cmplt(vector signed char __a, vector signed char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtsb(b, a);
+ return (vector bool char)__builtin_altivec_vcmpgtsb(__b, __a);
}
static vector bool char __ATTRS_o_ai
-vec_cmplt(vector unsigned char a, vector unsigned char b)
+vec_cmplt(vector unsigned char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtub(b, a);
+ return (vector bool char)__builtin_altivec_vcmpgtub(__b, __a);
}
static vector bool short __ATTRS_o_ai
-vec_cmplt(vector short a, vector short b)
+vec_cmplt(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtsh(b, a);
+ return (vector bool short)__builtin_altivec_vcmpgtsh(__b, __a);
}
static vector bool short __ATTRS_o_ai
-vec_cmplt(vector unsigned short a, vector unsigned short b)
+vec_cmplt(vector unsigned short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtuh(b, a);
+ return (vector bool short)__builtin_altivec_vcmpgtuh(__b, __a);
}
static vector bool int __ATTRS_o_ai
-vec_cmplt(vector int a, vector int b)
+vec_cmplt(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtsw(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgtsw(__b, __a);
}
static vector bool int __ATTRS_o_ai
-vec_cmplt(vector unsigned int a, vector unsigned int b)
+vec_cmplt(vector unsigned int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtuw(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgtuw(__b, __a);
}
static vector bool int __ATTRS_o_ai
-vec_cmplt(vector float a, vector float b)
+vec_cmplt(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtfp(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgtfp(__b, __a);
}
/* vec_ctf */
static vector float __ATTRS_o_ai
-vec_ctf(vector int a, int b)
+vec_ctf(vector int __a, int __b)
{
- return __builtin_altivec_vcfsx(a, b);
+ return __builtin_altivec_vcfsx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ctf(vector unsigned int a, int b)
+vec_ctf(vector unsigned int __a, int __b)
{
- return __builtin_altivec_vcfux((vector int)a, b);
+ return __builtin_altivec_vcfux((vector int)__a, __b);
}
/* vec_vcfsx */
static vector float __attribute__((__always_inline__))
-vec_vcfsx(vector int a, int b)
+vec_vcfsx(vector int __a, int __b)
{
- return __builtin_altivec_vcfsx(a, b);
+ return __builtin_altivec_vcfsx(__a, __b);
}
/* vec_vcfux */
static vector float __attribute__((__always_inline__))
-vec_vcfux(vector unsigned int a, int b)
+vec_vcfux(vector unsigned int __a, int __b)
{
- return __builtin_altivec_vcfux((vector int)a, b);
+ return __builtin_altivec_vcfux((vector int)__a, __b);
}
/* vec_cts */
static vector int __attribute__((__always_inline__))
-vec_cts(vector float a, int b)
+vec_cts(vector float __a, int __b)
{
- return __builtin_altivec_vctsxs(a, b);
+ return __builtin_altivec_vctsxs(__a, __b);
}
/* vec_vctsxs */
static vector int __attribute__((__always_inline__))
-vec_vctsxs(vector float a, int b)
+vec_vctsxs(vector float __a, int __b)
{
- return __builtin_altivec_vctsxs(a, b);
+ return __builtin_altivec_vctsxs(__a, __b);
}
/* vec_ctu */
static vector unsigned int __attribute__((__always_inline__))
-vec_ctu(vector float a, int b)
+vec_ctu(vector float __a, int __b)
{
- return __builtin_altivec_vctuxs(a, b);
+ return __builtin_altivec_vctuxs(__a, __b);
}
/* vec_vctuxs */
static vector unsigned int __attribute__((__always_inline__))
-vec_vctuxs(vector float a, int b)
+vec_vctuxs(vector float __a, int __b)
{
- return __builtin_altivec_vctuxs(a, b);
+ return __builtin_altivec_vctuxs(__a, __b);
}
/* vec_dss */
static void __attribute__((__always_inline__))
-vec_dss(int a)
+vec_dss(int __a)
{
- __builtin_altivec_dss(a);
+ __builtin_altivec_dss(__a);
}
/* vec_dssall */
@@ -1639,1066 +1639,1066 @@ vec_dssall(void)
/* vec_dst */
static void __attribute__((__always_inline__))
-vec_dst(const void *a, int b, int c)
+vec_dst(const void *__a, int __b, int __c)
{
- __builtin_altivec_dst(a, b, c);
+ __builtin_altivec_dst(__a, __b, __c);
}
/* vec_dstst */
static void __attribute__((__always_inline__))
-vec_dstst(const void *a, int b, int c)
+vec_dstst(const void *__a, int __b, int __c)
{
- __builtin_altivec_dstst(a, b, c);
+ __builtin_altivec_dstst(__a, __b, __c);
}
/* vec_dststt */
static void __attribute__((__always_inline__))
-vec_dststt(const void *a, int b, int c)
+vec_dststt(const void *__a, int __b, int __c)
{
- __builtin_altivec_dststt(a, b, c);
+ __builtin_altivec_dststt(__a, __b, __c);
}
/* vec_dstt */
static void __attribute__((__always_inline__))
-vec_dstt(const void *a, int b, int c)
+vec_dstt(const void *__a, int __b, int __c)
{
- __builtin_altivec_dstt(a, b, c);
+ __builtin_altivec_dstt(__a, __b, __c);
}
/* vec_expte */
static vector float __attribute__((__always_inline__))
-vec_expte(vector float a)
+vec_expte(vector float __a)
{
- return __builtin_altivec_vexptefp(a);
+ return __builtin_altivec_vexptefp(__a);
}
/* vec_vexptefp */
static vector float __attribute__((__always_inline__))
-vec_vexptefp(vector float a)
+vec_vexptefp(vector float __a)
{
- return __builtin_altivec_vexptefp(a);
+ return __builtin_altivec_vexptefp(__a);
}
/* vec_floor */
static vector float __attribute__((__always_inline__))
-vec_floor(vector float a)
+vec_floor(vector float __a)
{
- return __builtin_altivec_vrfim(a);
+ return __builtin_altivec_vrfim(__a);
}
/* vec_vrfim */
static vector float __attribute__((__always_inline__))
-vec_vrfim(vector float a)
+vec_vrfim(vector float __a)
{
- return __builtin_altivec_vrfim(a);
+ return __builtin_altivec_vrfim(__a);
}
/* vec_ld */
static vector signed char __ATTRS_o_ai
-vec_ld(int a, const vector signed char *b)
+vec_ld(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_ld(int a, const signed char *b)
+vec_ld(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ld(int a, const vector unsigned char *b)
+vec_ld(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ld(int a, const unsigned char *b)
+vec_ld(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_ld(int a, const vector bool char *b)
+vec_ld(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvx(a, b);
+ return (vector bool char)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ld(int a, const vector short *b)
+vec_ld(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ld(int a, const short *b)
+vec_ld(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ld(int a, const vector unsigned short *b)
+vec_ld(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ld(int a, const unsigned short *b)
+vec_ld(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_ld(int a, const vector bool short *b)
+vec_ld(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvx(a, b);
+ return (vector bool short)__builtin_altivec_lvx(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_ld(int a, const vector pixel *b)
+vec_ld(int __a, const vector pixel *__b)
{
- return (vector pixel)__builtin_altivec_lvx(a, b);
+ return (vector pixel)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ld(int a, const vector int *b)
+vec_ld(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ld(int a, const int *b)
+vec_ld(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ld(int a, const vector unsigned int *b)
+vec_ld(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ld(int a, const unsigned int *b)
+vec_ld(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_ld(int a, const vector bool int *b)
+vec_ld(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvx(a, b);
+ return (vector bool int)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ld(int a, const vector float *b)
+vec_ld(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ld(int a, const float *b)
+vec_ld(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
/* vec_lvx */
static vector signed char __ATTRS_o_ai
-vec_lvx(int a, const vector signed char *b)
+vec_lvx(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_lvx(int a, const signed char *b)
+vec_lvx(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvx(int a, const vector unsigned char *b)
+vec_lvx(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvx(int a, const unsigned char *b)
+vec_lvx(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_lvx(int a, const vector bool char *b)
+vec_lvx(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvx(a, b);
+ return (vector bool char)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvx(int a, const vector short *b)
+vec_lvx(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvx(int a, const short *b)
+vec_lvx(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvx(int a, const vector unsigned short *b)
+vec_lvx(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvx(int a, const unsigned short *b)
+vec_lvx(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_lvx(int a, const vector bool short *b)
+vec_lvx(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvx(a, b);
+ return (vector bool short)__builtin_altivec_lvx(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_lvx(int a, const vector pixel *b)
+vec_lvx(int __a, const vector pixel *__b)
{
- return (vector pixel)__builtin_altivec_lvx(a, b);
+ return (vector pixel)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvx(int a, const vector int *b)
+vec_lvx(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvx(int a, const int *b)
+vec_lvx(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvx(int a, const vector unsigned int *b)
+vec_lvx(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvx(int a, const unsigned int *b)
+vec_lvx(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_lvx(int a, const vector bool int *b)
+vec_lvx(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvx(a, b);
+ return (vector bool int)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvx(int a, const vector float *b)
+vec_lvx(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvx(int a, const float *b)
+vec_lvx(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
/* vec_lde */
static vector signed char __ATTRS_o_ai
-vec_lde(int a, const vector signed char *b)
+vec_lde(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvebx(a, b);
+ return (vector signed char)__builtin_altivec_lvebx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lde(int a, const vector unsigned char *b)
+vec_lde(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvebx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvebx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lde(int a, const vector short *b)
+vec_lde(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvehx(a, b);
+ return (vector short)__builtin_altivec_lvehx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lde(int a, const vector unsigned short *b)
+vec_lde(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvehx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvehx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lde(int a, const vector int *b)
+vec_lde(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvewx(a, b);
+ return (vector int)__builtin_altivec_lvewx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lde(int a, const vector unsigned int *b)
+vec_lde(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvewx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvewx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lde(int a, const vector float *b)
+vec_lde(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvewx(a, b);
+ return (vector float)__builtin_altivec_lvewx(__a, __b);
}
/* vec_lvebx */
static vector signed char __ATTRS_o_ai
-vec_lvebx(int a, const vector signed char *b)
+vec_lvebx(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvebx(a, b);
+ return (vector signed char)__builtin_altivec_lvebx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvebx(int a, const vector unsigned char *b)
+vec_lvebx(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvebx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvebx(__a, __b);
}
/* vec_lvehx */
static vector short __ATTRS_o_ai
-vec_lvehx(int a, const vector short *b)
+vec_lvehx(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvehx(a, b);
+ return (vector short)__builtin_altivec_lvehx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvehx(int a, const vector unsigned short *b)
+vec_lvehx(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvehx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvehx(__a, __b);
}
/* vec_lvewx */
static vector int __ATTRS_o_ai
-vec_lvewx(int a, const vector int *b)
+vec_lvewx(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvewx(a, b);
+ return (vector int)__builtin_altivec_lvewx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvewx(int a, const vector unsigned int *b)
+vec_lvewx(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvewx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvewx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvewx(int a, const vector float *b)
+vec_lvewx(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvewx(a, b);
+ return (vector float)__builtin_altivec_lvewx(__a, __b);
}
/* vec_ldl */
static vector signed char __ATTRS_o_ai
-vec_ldl(int a, const vector signed char *b)
+vec_ldl(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_ldl(int a, const signed char *b)
+vec_ldl(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ldl(int a, const vector unsigned char *b)
+vec_ldl(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ldl(int a, const unsigned char *b)
+vec_ldl(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_ldl(int a, const vector bool char *b)
+vec_ldl(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvxl(a, b);
+ return (vector bool char)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ldl(int a, const vector short *b)
+vec_ldl(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ldl(int a, const short *b)
+vec_ldl(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ldl(int a, const vector unsigned short *b)
+vec_ldl(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ldl(int a, const unsigned short *b)
+vec_ldl(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_ldl(int a, const vector bool short *b)
+vec_ldl(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvxl(a, b);
+ return (vector bool short)__builtin_altivec_lvxl(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_ldl(int a, const vector pixel *b)
+vec_ldl(int __a, const vector pixel *__b)
{
- return (vector pixel short)__builtin_altivec_lvxl(a, b);
+ return (vector pixel short)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ldl(int a, const vector int *b)
+vec_ldl(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ldl(int a, const int *b)
+vec_ldl(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ldl(int a, const vector unsigned int *b)
+vec_ldl(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ldl(int a, const unsigned int *b)
+vec_ldl(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_ldl(int a, const vector bool int *b)
+vec_ldl(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvxl(a, b);
+ return (vector bool int)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ldl(int a, const vector float *b)
+vec_ldl(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ldl(int a, const float *b)
+vec_ldl(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
/* vec_lvxl */
static vector signed char __ATTRS_o_ai
-vec_lvxl(int a, const vector signed char *b)
+vec_lvxl(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_lvxl(int a, const signed char *b)
+vec_lvxl(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvxl(int a, const vector unsigned char *b)
+vec_lvxl(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvxl(int a, const unsigned char *b)
+vec_lvxl(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_lvxl(int a, const vector bool char *b)
+vec_lvxl(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvxl(a, b);
+ return (vector bool char)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvxl(int a, const vector short *b)
+vec_lvxl(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvxl(int a, const short *b)
+vec_lvxl(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvxl(int a, const vector unsigned short *b)
+vec_lvxl(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvxl(int a, const unsigned short *b)
+vec_lvxl(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_lvxl(int a, const vector bool short *b)
+vec_lvxl(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvxl(a, b);
+ return (vector bool short)__builtin_altivec_lvxl(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_lvxl(int a, const vector pixel *b)
+vec_lvxl(int __a, const vector pixel *__b)
{
- return (vector pixel)__builtin_altivec_lvxl(a, b);
+ return (vector pixel)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvxl(int a, const vector int *b)
+vec_lvxl(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvxl(int a, const int *b)
+vec_lvxl(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvxl(int a, const vector unsigned int *b)
+vec_lvxl(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvxl(int a, const unsigned int *b)
+vec_lvxl(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_lvxl(int a, const vector bool int *b)
+vec_lvxl(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvxl(a, b);
+ return (vector bool int)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvxl(int a, const vector float *b)
+vec_lvxl(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvxl(int a, const float *b)
+vec_lvxl(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
/* vec_loge */
static vector float __attribute__((__always_inline__))
-vec_loge(vector float a)
+vec_loge(vector float __a)
{
- return __builtin_altivec_vlogefp(a);
+ return __builtin_altivec_vlogefp(__a);
}
/* vec_vlogefp */
static vector float __attribute__((__always_inline__))
-vec_vlogefp(vector float a)
+vec_vlogefp(vector float __a)
{
- return __builtin_altivec_vlogefp(a);
+ return __builtin_altivec_vlogefp(__a);
}
/* vec_lvsl */
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const signed char *b)
+vec_lvsl(int __a, const signed char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const unsigned char *b)
+vec_lvsl(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const short *b)
+vec_lvsl(int __a, const short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const unsigned short *b)
+vec_lvsl(int __a, const unsigned short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const int *b)
+vec_lvsl(int __a, const int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const unsigned int *b)
+vec_lvsl(int __a, const unsigned int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const float *b)
+vec_lvsl(int __a, const float *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
/* vec_lvsr */
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const signed char *b)
+vec_lvsr(int __a, const signed char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const unsigned char *b)
+vec_lvsr(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const short *b)
+vec_lvsr(int __a, const short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const unsigned short *b)
+vec_lvsr(int __a, const unsigned short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const int *b)
+vec_lvsr(int __a, const int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const unsigned int *b)
+vec_lvsr(int __a, const unsigned int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const float *b)
+vec_lvsr(int __a, const float *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
/* vec_madd */
static vector float __attribute__((__always_inline__))
-vec_madd(vector float a, vector float b, vector float c)
+vec_madd(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vmaddfp(a, b, c);
+ return __builtin_altivec_vmaddfp(__a, __b, __c);
}
/* vec_vmaddfp */
static vector float __attribute__((__always_inline__))
-vec_vmaddfp(vector float a, vector float b, vector float c)
+vec_vmaddfp(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vmaddfp(a, b, c);
+ return __builtin_altivec_vmaddfp(__a, __b, __c);
}
/* vec_madds */
static vector signed short __attribute__((__always_inline__))
-vec_madds(vector signed short a, vector signed short b, vector signed short c)
+vec_madds(vector signed short __a, vector signed short __b, vector signed short __c)
{
- return __builtin_altivec_vmhaddshs(a, b, c);
+ return __builtin_altivec_vmhaddshs(__a, __b, __c);
}
/* vec_vmhaddshs */
static vector signed short __attribute__((__always_inline__))
-vec_vmhaddshs(vector signed short a,
- vector signed short b,
- vector signed short c)
+vec_vmhaddshs(vector signed short __a,
+ vector signed short __b,
+ vector signed short __c)
{
- return __builtin_altivec_vmhaddshs(a, b, c);
+ return __builtin_altivec_vmhaddshs(__a, __b, __c);
}
/* vec_max */
static vector signed char __ATTRS_o_ai
-vec_max(vector signed char a, vector signed char b)
+vec_max(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb(a, b);
+ return __builtin_altivec_vmaxsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_max(vector bool char a, vector signed char b)
+vec_max(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb((vector signed char)a, b);
+ return __builtin_altivec_vmaxsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_max(vector signed char a, vector bool char b)
+vec_max(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxsb(a, (vector signed char)b);
+ return __builtin_altivec_vmaxsb(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_max(vector unsigned char a, vector unsigned char b)
+vec_max(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub(a, b);
+ return __builtin_altivec_vmaxub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_max(vector bool char a, vector unsigned char b)
+vec_max(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub((vector unsigned char)a, b);
+ return __builtin_altivec_vmaxub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_max(vector unsigned char a, vector bool char b)
+vec_max(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxub(a, (vector unsigned char)b);
+ return __builtin_altivec_vmaxub(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_max(vector short a, vector short b)
+vec_max(vector short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh(a, b);
+ return __builtin_altivec_vmaxsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_max(vector bool short a, vector short b)
+vec_max(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh((vector short)a, b);
+ return __builtin_altivec_vmaxsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_max(vector short a, vector bool short b)
+vec_max(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxsh(a, (vector short)b);
+ return __builtin_altivec_vmaxsh(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_max(vector unsigned short a, vector unsigned short b)
+vec_max(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh(a, b);
+ return __builtin_altivec_vmaxuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_max(vector bool short a, vector unsigned short b)
+vec_max(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh((vector unsigned short)a, b);
+ return __builtin_altivec_vmaxuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_max(vector unsigned short a, vector bool short b)
+vec_max(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vmaxuh(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_max(vector int a, vector int b)
+vec_max(vector int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw(a, b);
+ return __builtin_altivec_vmaxsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_max(vector bool int a, vector int b)
+vec_max(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw((vector int)a, b);
+ return __builtin_altivec_vmaxsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_max(vector int a, vector bool int b)
+vec_max(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxsw(a, (vector int)b);
+ return __builtin_altivec_vmaxsw(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_max(vector unsigned int a, vector unsigned int b)
+vec_max(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw(a, b);
+ return __builtin_altivec_vmaxuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_max(vector bool int a, vector unsigned int b)
+vec_max(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw((vector unsigned int)a, b);
+ return __builtin_altivec_vmaxuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_max(vector unsigned int a, vector bool int b)
+vec_max(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vmaxuw(__a, (vector unsigned int)__b);
}
static vector float __ATTRS_o_ai
-vec_max(vector float a, vector float b)
+vec_max(vector float __a, vector float __b)
{
- return __builtin_altivec_vmaxfp(a, b);
+ return __builtin_altivec_vmaxfp(__a, __b);
}
/* vec_vmaxsb */
static vector signed char __ATTRS_o_ai
-vec_vmaxsb(vector signed char a, vector signed char b)
+vec_vmaxsb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb(a, b);
+ return __builtin_altivec_vmaxsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vmaxsb(vector bool char a, vector signed char b)
+vec_vmaxsb(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb((vector signed char)a, b);
+ return __builtin_altivec_vmaxsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vmaxsb(vector signed char a, vector bool char b)
+vec_vmaxsb(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxsb(a, (vector signed char)b);
+ return __builtin_altivec_vmaxsb(__a, (vector signed char)__b);
}
/* vec_vmaxub */
static vector unsigned char __ATTRS_o_ai
-vec_vmaxub(vector unsigned char a, vector unsigned char b)
+vec_vmaxub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub(a, b);
+ return __builtin_altivec_vmaxub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vmaxub(vector bool char a, vector unsigned char b)
+vec_vmaxub(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub((vector unsigned char)a, b);
+ return __builtin_altivec_vmaxub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vmaxub(vector unsigned char a, vector bool char b)
+vec_vmaxub(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxub(a, (vector unsigned char)b);
+ return __builtin_altivec_vmaxub(__a, (vector unsigned char)__b);
}
/* vec_vmaxsh */
static vector short __ATTRS_o_ai
-vec_vmaxsh(vector short a, vector short b)
+vec_vmaxsh(vector short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh(a, b);
+ return __builtin_altivec_vmaxsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vmaxsh(vector bool short a, vector short b)
+vec_vmaxsh(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh((vector short)a, b);
+ return __builtin_altivec_vmaxsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vmaxsh(vector short a, vector bool short b)
+vec_vmaxsh(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxsh(a, (vector short)b);
+ return __builtin_altivec_vmaxsh(__a, (vector short)__b);
}
/* vec_vmaxuh */
static vector unsigned short __ATTRS_o_ai
-vec_vmaxuh(vector unsigned short a, vector unsigned short b)
+vec_vmaxuh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh(a, b);
+ return __builtin_altivec_vmaxuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vmaxuh(vector bool short a, vector unsigned short b)
+vec_vmaxuh(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh((vector unsigned short)a, b);
+ return __builtin_altivec_vmaxuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vmaxuh(vector unsigned short a, vector bool short b)
+vec_vmaxuh(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vmaxuh(__a, (vector unsigned short)__b);
}
/* vec_vmaxsw */
static vector int __ATTRS_o_ai
-vec_vmaxsw(vector int a, vector int b)
+vec_vmaxsw(vector int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw(a, b);
+ return __builtin_altivec_vmaxsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vmaxsw(vector bool int a, vector int b)
+vec_vmaxsw(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw((vector int)a, b);
+ return __builtin_altivec_vmaxsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vmaxsw(vector int a, vector bool int b)
+vec_vmaxsw(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxsw(a, (vector int)b);
+ return __builtin_altivec_vmaxsw(__a, (vector int)__b);
}
/* vec_vmaxuw */
static vector unsigned int __ATTRS_o_ai
-vec_vmaxuw(vector unsigned int a, vector unsigned int b)
+vec_vmaxuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw(a, b);
+ return __builtin_altivec_vmaxuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vmaxuw(vector bool int a, vector unsigned int b)
+vec_vmaxuw(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw((vector unsigned int)a, b);
+ return __builtin_altivec_vmaxuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vmaxuw(vector unsigned int a, vector bool int b)
+vec_vmaxuw(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vmaxuw(__a, (vector unsigned int)__b);
}
/* vec_vmaxfp */
static vector float __attribute__((__always_inline__))
-vec_vmaxfp(vector float a, vector float b)
+vec_vmaxfp(vector float __a, vector float __b)
{
- return __builtin_altivec_vmaxfp(a, b);
+ return __builtin_altivec_vmaxfp(__a, __b);
}
/* vec_mergeh */
static vector signed char __ATTRS_o_ai
-vec_mergeh(vector signed char a, vector signed char b)
+vec_mergeh(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector unsigned char __ATTRS_o_ai
-vec_mergeh(vector unsigned char a, vector unsigned char b)
+vec_mergeh(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector bool char __ATTRS_o_ai
-vec_mergeh(vector bool char a, vector bool char b)
+vec_mergeh(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector short __ATTRS_o_ai
-vec_mergeh(vector short a, vector short b)
+vec_mergeh(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector unsigned short __ATTRS_o_ai
-vec_mergeh(vector unsigned short a, vector unsigned short b)
+vec_mergeh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector bool short __ATTRS_o_ai
-vec_mergeh(vector bool short a, vector bool short b)
+vec_mergeh(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector pixel __ATTRS_o_ai
-vec_mergeh(vector pixel a, vector pixel b)
+vec_mergeh(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector int __ATTRS_o_ai
-vec_mergeh(vector int a, vector int b)
+vec_mergeh(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector unsigned int __ATTRS_o_ai
-vec_mergeh(vector unsigned int a, vector unsigned int b)
+vec_mergeh(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector bool int __ATTRS_o_ai
-vec_mergeh(vector bool int a, vector bool int b)
+vec_mergeh(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector float __ATTRS_o_ai
-vec_mergeh(vector float a, vector float b)
+vec_mergeh(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
@@ -2708,25 +2708,25 @@ vec_mergeh(vector float a, vector float b)
#define __builtin_altivec_vmrghb vec_vmrghb
static vector signed char __ATTRS_o_ai
-vec_vmrghb(vector signed char a, vector signed char b)
+vec_vmrghb(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector unsigned char __ATTRS_o_ai
-vec_vmrghb(vector unsigned char a, vector unsigned char b)
+vec_vmrghb(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector bool char __ATTRS_o_ai
-vec_vmrghb(vector bool char a, vector bool char b)
+vec_vmrghb(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
@@ -2736,33 +2736,33 @@ vec_vmrghb(vector bool char a, vector bool char b)
#define __builtin_altivec_vmrghh vec_vmrghh
static vector short __ATTRS_o_ai
-vec_vmrghh(vector short a, vector short b)
+vec_vmrghh(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector unsigned short __ATTRS_o_ai
-vec_vmrghh(vector unsigned short a, vector unsigned short b)
+vec_vmrghh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector bool short __ATTRS_o_ai
-vec_vmrghh(vector bool short a, vector bool short b)
+vec_vmrghh(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector pixel __ATTRS_o_ai
-vec_vmrghh(vector pixel a, vector pixel b)
+vec_vmrghh(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
@@ -2772,33 +2772,33 @@ vec_vmrghh(vector pixel a, vector pixel b)
#define __builtin_altivec_vmrghw vec_vmrghw
static vector int __ATTRS_o_ai
-vec_vmrghw(vector int a, vector int b)
+vec_vmrghw(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector unsigned int __ATTRS_o_ai
-vec_vmrghw(vector unsigned int a, vector unsigned int b)
+vec_vmrghw(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector bool int __ATTRS_o_ai
-vec_vmrghw(vector bool int a, vector bool int b)
+vec_vmrghw(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector float __ATTRS_o_ai
-vec_vmrghw(vector float a, vector float b)
+vec_vmrghw(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
@@ -2806,89 +2806,89 @@ vec_vmrghw(vector float a, vector float b)
/* vec_mergel */
static vector signed char __ATTRS_o_ai
-vec_mergel(vector signed char a, vector signed char b)
+vec_mergel(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector unsigned char __ATTRS_o_ai
-vec_mergel(vector unsigned char a, vector unsigned char b)
+vec_mergel(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector bool char __ATTRS_o_ai
-vec_mergel(vector bool char a, vector bool char b)
+vec_mergel(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector short __ATTRS_o_ai
-vec_mergel(vector short a, vector short b)
+vec_mergel(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector unsigned short __ATTRS_o_ai
-vec_mergel(vector unsigned short a, vector unsigned short b)
+vec_mergel(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector bool short __ATTRS_o_ai
-vec_mergel(vector bool short a, vector bool short b)
+vec_mergel(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector pixel __ATTRS_o_ai
-vec_mergel(vector pixel a, vector pixel b)
+vec_mergel(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector int __ATTRS_o_ai
-vec_mergel(vector int a, vector int b)
+vec_mergel(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector unsigned int __ATTRS_o_ai
-vec_mergel(vector unsigned int a, vector unsigned int b)
+vec_mergel(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector bool int __ATTRS_o_ai
-vec_mergel(vector bool int a, vector bool int b)
+vec_mergel(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector float __ATTRS_o_ai
-vec_mergel(vector float a, vector float b)
+vec_mergel(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
@@ -2898,25 +2898,25 @@ vec_mergel(vector float a, vector float b)
#define __builtin_altivec_vmrglb vec_vmrglb
static vector signed char __ATTRS_o_ai
-vec_vmrglb(vector signed char a, vector signed char b)
+vec_vmrglb(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector unsigned char __ATTRS_o_ai
-vec_vmrglb(vector unsigned char a, vector unsigned char b)
+vec_vmrglb(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector bool char __ATTRS_o_ai
-vec_vmrglb(vector bool char a, vector bool char b)
+vec_vmrglb(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
@@ -2926,33 +2926,33 @@ vec_vmrglb(vector bool char a, vector bool char b)
#define __builtin_altivec_vmrglh vec_vmrglh
static vector short __ATTRS_o_ai
-vec_vmrglh(vector short a, vector short b)
+vec_vmrglh(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector unsigned short __ATTRS_o_ai
-vec_vmrglh(vector unsigned short a, vector unsigned short b)
+vec_vmrglh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector bool short __ATTRS_o_ai
-vec_vmrglh(vector bool short a, vector bool short b)
+vec_vmrglh(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector pixel __ATTRS_o_ai
-vec_vmrglh(vector pixel a, vector pixel b)
+vec_vmrglh(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
@@ -2962,33 +2962,33 @@ vec_vmrglh(vector pixel a, vector pixel b)
#define __builtin_altivec_vmrglw vec_vmrglw
static vector int __ATTRS_o_ai
-vec_vmrglw(vector int a, vector int b)
+vec_vmrglw(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector unsigned int __ATTRS_o_ai
-vec_vmrglw(vector unsigned int a, vector unsigned int b)
+vec_vmrglw(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector bool int __ATTRS_o_ai
-vec_vmrglw(vector bool int a, vector bool int b)
+vec_vmrglw(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector float __ATTRS_o_ai
-vec_vmrglw(vector float a, vector float b)
+vec_vmrglw(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
@@ -3004,245 +3004,245 @@ vec_mfvscr(void)
/* vec_min */
static vector signed char __ATTRS_o_ai
-vec_min(vector signed char a, vector signed char b)
+vec_min(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb(a, b);
+ return __builtin_altivec_vminsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_min(vector bool char a, vector signed char b)
+vec_min(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb((vector signed char)a, b);
+ return __builtin_altivec_vminsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_min(vector signed char a, vector bool char b)
+vec_min(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vminsb(a, (vector signed char)b);
+ return __builtin_altivec_vminsb(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_min(vector unsigned char a, vector unsigned char b)
+vec_min(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub(a, b);
+ return __builtin_altivec_vminub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_min(vector bool char a, vector unsigned char b)
+vec_min(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub((vector unsigned char)a, b);
+ return __builtin_altivec_vminub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_min(vector unsigned char a, vector bool char b)
+vec_min(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vminub(a, (vector unsigned char)b);
+ return __builtin_altivec_vminub(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_min(vector short a, vector short b)
+vec_min(vector short __a, vector short __b)
{
- return __builtin_altivec_vminsh(a, b);
+ return __builtin_altivec_vminsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_min(vector bool short a, vector short b)
+vec_min(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vminsh((vector short)a, b);
+ return __builtin_altivec_vminsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_min(vector short a, vector bool short b)
+vec_min(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vminsh(a, (vector short)b);
+ return __builtin_altivec_vminsh(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_min(vector unsigned short a, vector unsigned short b)
+vec_min(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh(a, b);
+ return __builtin_altivec_vminuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_min(vector bool short a, vector unsigned short b)
+vec_min(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh((vector unsigned short)a, b);
+ return __builtin_altivec_vminuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_min(vector unsigned short a, vector bool short b)
+vec_min(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vminuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vminuh(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_min(vector int a, vector int b)
+vec_min(vector int __a, vector int __b)
{
- return __builtin_altivec_vminsw(a, b);
+ return __builtin_altivec_vminsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_min(vector bool int a, vector int b)
+vec_min(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vminsw((vector int)a, b);
+ return __builtin_altivec_vminsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_min(vector int a, vector bool int b)
+vec_min(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vminsw(a, (vector int)b);
+ return __builtin_altivec_vminsw(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_min(vector unsigned int a, vector unsigned int b)
+vec_min(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw(a, b);
+ return __builtin_altivec_vminuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_min(vector bool int a, vector unsigned int b)
+vec_min(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw((vector unsigned int)a, b);
+ return __builtin_altivec_vminuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_min(vector unsigned int a, vector bool int b)
+vec_min(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vminuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vminuw(__a, (vector unsigned int)__b);
}
static vector float __ATTRS_o_ai
-vec_min(vector float a, vector float b)
+vec_min(vector float __a, vector float __b)
{
- return __builtin_altivec_vminfp(a, b);
+ return __builtin_altivec_vminfp(__a, __b);
}
/* vec_vminsb */
static vector signed char __ATTRS_o_ai
-vec_vminsb(vector signed char a, vector signed char b)
+vec_vminsb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb(a, b);
+ return __builtin_altivec_vminsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vminsb(vector bool char a, vector signed char b)
+vec_vminsb(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb((vector signed char)a, b);
+ return __builtin_altivec_vminsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vminsb(vector signed char a, vector bool char b)
+vec_vminsb(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vminsb(a, (vector signed char)b);
+ return __builtin_altivec_vminsb(__a, (vector signed char)__b);
}
/* vec_vminub */
static vector unsigned char __ATTRS_o_ai
-vec_vminub(vector unsigned char a, vector unsigned char b)
+vec_vminub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub(a, b);
+ return __builtin_altivec_vminub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vminub(vector bool char a, vector unsigned char b)
+vec_vminub(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub((vector unsigned char)a, b);
+ return __builtin_altivec_vminub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vminub(vector unsigned char a, vector bool char b)
+vec_vminub(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vminub(a, (vector unsigned char)b);
+ return __builtin_altivec_vminub(__a, (vector unsigned char)__b);
}
/* vec_vminsh */
static vector short __ATTRS_o_ai
-vec_vminsh(vector short a, vector short b)
+vec_vminsh(vector short __a, vector short __b)
{
- return __builtin_altivec_vminsh(a, b);
+ return __builtin_altivec_vminsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vminsh(vector bool short a, vector short b)
+vec_vminsh(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vminsh((vector short)a, b);
+ return __builtin_altivec_vminsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vminsh(vector short a, vector bool short b)
+vec_vminsh(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vminsh(a, (vector short)b);
+ return __builtin_altivec_vminsh(__a, (vector short)__b);
}
/* vec_vminuh */
static vector unsigned short __ATTRS_o_ai
-vec_vminuh(vector unsigned short a, vector unsigned short b)
+vec_vminuh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh(a, b);
+ return __builtin_altivec_vminuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vminuh(vector bool short a, vector unsigned short b)
+vec_vminuh(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh((vector unsigned short)a, b);
+ return __builtin_altivec_vminuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vminuh(vector unsigned short a, vector bool short b)
+vec_vminuh(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vminuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vminuh(__a, (vector unsigned short)__b);
}
/* vec_vminsw */
static vector int __ATTRS_o_ai
-vec_vminsw(vector int a, vector int b)
+vec_vminsw(vector int __a, vector int __b)
{
- return __builtin_altivec_vminsw(a, b);
+ return __builtin_altivec_vminsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vminsw(vector bool int a, vector int b)
+vec_vminsw(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vminsw((vector int)a, b);
+ return __builtin_altivec_vminsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vminsw(vector int a, vector bool int b)
+vec_vminsw(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vminsw(a, (vector int)b);
+ return __builtin_altivec_vminsw(__a, (vector int)__b);
}
/* vec_vminuw */
static vector unsigned int __ATTRS_o_ai
-vec_vminuw(vector unsigned int a, vector unsigned int b)
+vec_vminuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw(a, b);
+ return __builtin_altivec_vminuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vminuw(vector bool int a, vector unsigned int b)
+vec_vminuw(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw((vector unsigned int)a, b);
+ return __builtin_altivec_vminuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vminuw(vector unsigned int a, vector bool int b)
+vec_vminuw(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vminuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vminuw(__a, (vector unsigned int)__b);
}
/* vec_vminfp */
static vector float __attribute__((__always_inline__))
-vec_vminfp(vector float a, vector float b)
+vec_vminfp(vector float __a, vector float __b)
{
- return __builtin_altivec_vminfp(a, b);
+ return __builtin_altivec_vminfp(__a, __b);
}
/* vec_mladd */
@@ -3250,371 +3250,371 @@ vec_vminfp(vector float a, vector float b)
#define __builtin_altivec_vmladduhm vec_mladd
static vector short __ATTRS_o_ai
-vec_mladd(vector short a, vector short b, vector short c)
+vec_mladd(vector short __a, vector short __b, vector short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
static vector short __ATTRS_o_ai
-vec_mladd(vector short a, vector unsigned short b, vector unsigned short c)
+vec_mladd(vector short __a, vector unsigned short __b, vector unsigned short __c)
{
- return a * (vector short)b + (vector short)c;
+ return __a * (vector short)__b + (vector short)__c;
}
static vector short __ATTRS_o_ai
-vec_mladd(vector unsigned short a, vector short b, vector short c)
+vec_mladd(vector unsigned short __a, vector short __b, vector short __c)
{
- return (vector short)a * b + c;
+ return (vector short)__a * __b + __c;
}
static vector unsigned short __ATTRS_o_ai
-vec_mladd(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_mladd(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
/* vec_vmladduhm */
static vector short __ATTRS_o_ai
-vec_vmladduhm(vector short a, vector short b, vector short c)
+vec_vmladduhm(vector short __a, vector short __b, vector short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
static vector short __ATTRS_o_ai
-vec_vmladduhm(vector short a, vector unsigned short b, vector unsigned short c)
+vec_vmladduhm(vector short __a, vector unsigned short __b, vector unsigned short __c)
{
- return a * (vector short)b + (vector short)c;
+ return __a * (vector short)__b + (vector short)__c;
}
static vector short __ATTRS_o_ai
-vec_vmladduhm(vector unsigned short a, vector short b, vector short c)
+vec_vmladduhm(vector unsigned short __a, vector short __b, vector short __c)
{
- return (vector short)a * b + c;
+ return (vector short)__a * __b + __c;
}
static vector unsigned short __ATTRS_o_ai
-vec_vmladduhm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_vmladduhm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
/* vec_mradds */
static vector short __attribute__((__always_inline__))
-vec_mradds(vector short a, vector short b, vector short c)
+vec_mradds(vector short __a, vector short __b, vector short __c)
{
- return __builtin_altivec_vmhraddshs(a, b, c);
+ return __builtin_altivec_vmhraddshs(__a, __b, __c);
}
/* vec_vmhraddshs */
static vector short __attribute__((__always_inline__))
-vec_vmhraddshs(vector short a, vector short b, vector short c)
+vec_vmhraddshs(vector short __a, vector short __b, vector short __c)
{
- return __builtin_altivec_vmhraddshs(a, b, c);
+ return __builtin_altivec_vmhraddshs(__a, __b, __c);
}
/* vec_msum */
static vector int __ATTRS_o_ai
-vec_msum(vector signed char a, vector unsigned char b, vector int c)
+vec_msum(vector signed char __a, vector unsigned char __b, vector int __c)
{
- return __builtin_altivec_vmsummbm(a, b, c);
+ return __builtin_altivec_vmsummbm(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_msum(vector unsigned char a, vector unsigned char b, vector unsigned int c)
+vec_msum(vector unsigned char __a, vector unsigned char __b, vector unsigned int __c)
{
- return __builtin_altivec_vmsumubm(a, b, c);
+ return __builtin_altivec_vmsumubm(__a, __b, __c);
}
static vector int __ATTRS_o_ai
-vec_msum(vector short a, vector short b, vector int c)
+vec_msum(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshm(a, b, c);
+ return __builtin_altivec_vmsumshm(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_msum(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_msum(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhm(a, b, c);
+ return __builtin_altivec_vmsumuhm(__a, __b, __c);
}
/* vec_vmsummbm */
static vector int __attribute__((__always_inline__))
-vec_vmsummbm(vector signed char a, vector unsigned char b, vector int c)
+vec_vmsummbm(vector signed char __a, vector unsigned char __b, vector int __c)
{
- return __builtin_altivec_vmsummbm(a, b, c);
+ return __builtin_altivec_vmsummbm(__a, __b, __c);
}
/* vec_vmsumubm */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmsumubm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned int c)
+vec_vmsumubm(vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumubm(a, b, c);
+ return __builtin_altivec_vmsumubm(__a, __b, __c);
}
/* vec_vmsumshm */
static vector int __attribute__((__always_inline__))
-vec_vmsumshm(vector short a, vector short b, vector int c)
+vec_vmsumshm(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshm(a, b, c);
+ return __builtin_altivec_vmsumshm(__a, __b, __c);
}
/* vec_vmsumuhm */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmsumuhm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_vmsumuhm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhm(a, b, c);
+ return __builtin_altivec_vmsumuhm(__a, __b, __c);
}
/* vec_msums */
static vector int __ATTRS_o_ai
-vec_msums(vector short a, vector short b, vector int c)
+vec_msums(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshs(a, b, c);
+ return __builtin_altivec_vmsumshs(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_msums(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_msums(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhs(a, b, c);
+ return __builtin_altivec_vmsumuhs(__a, __b, __c);
}
/* vec_vmsumshs */
static vector int __attribute__((__always_inline__))
-vec_vmsumshs(vector short a, vector short b, vector int c)
+vec_vmsumshs(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshs(a, b, c);
+ return __builtin_altivec_vmsumshs(__a, __b, __c);
}
/* vec_vmsumuhs */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmsumuhs(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_vmsumuhs(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhs(a, b, c);
+ return __builtin_altivec_vmsumuhs(__a, __b, __c);
}
/* vec_mtvscr */
static void __ATTRS_o_ai
-vec_mtvscr(vector signed char a)
+vec_mtvscr(vector signed char __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector unsigned char a)
+vec_mtvscr(vector unsigned char __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector bool char a)
+vec_mtvscr(vector bool char __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector short a)
+vec_mtvscr(vector short __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector unsigned short a)
+vec_mtvscr(vector unsigned short __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector bool short a)
+vec_mtvscr(vector bool short __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector pixel a)
+vec_mtvscr(vector pixel __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector int a)
+vec_mtvscr(vector int __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector unsigned int a)
+vec_mtvscr(vector unsigned int __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector bool int a)
+vec_mtvscr(vector bool int __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector float a)
+vec_mtvscr(vector float __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
/* vec_mule */
static vector short __ATTRS_o_ai
-vec_mule(vector signed char a, vector signed char b)
+vec_mule(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulesb(a, b);
+ return __builtin_altivec_vmulesb(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_mule(vector unsigned char a, vector unsigned char b)
+vec_mule(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuleub(a, b);
+ return __builtin_altivec_vmuleub(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_mule(vector short a, vector short b)
+vec_mule(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulesh(a, b);
+ return __builtin_altivec_vmulesh(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_mule(vector unsigned short a, vector unsigned short b)
+vec_mule(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmuleuh(a, b);
+ return __builtin_altivec_vmuleuh(__a, __b);
}
/* vec_vmulesb */
static vector short __attribute__((__always_inline__))
-vec_vmulesb(vector signed char a, vector signed char b)
+vec_vmulesb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulesb(a, b);
+ return __builtin_altivec_vmulesb(__a, __b);
}
/* vec_vmuleub */
static vector unsigned short __attribute__((__always_inline__))
-vec_vmuleub(vector unsigned char a, vector unsigned char b)
+vec_vmuleub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuleub(a, b);
+ return __builtin_altivec_vmuleub(__a, __b);
}
/* vec_vmulesh */
static vector int __attribute__((__always_inline__))
-vec_vmulesh(vector short a, vector short b)
+vec_vmulesh(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulesh(a, b);
+ return __builtin_altivec_vmulesh(__a, __b);
}
/* vec_vmuleuh */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmuleuh(vector unsigned short a, vector unsigned short b)
+vec_vmuleuh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmuleuh(a, b);
+ return __builtin_altivec_vmuleuh(__a, __b);
}
/* vec_mulo */
static vector short __ATTRS_o_ai
-vec_mulo(vector signed char a, vector signed char b)
+vec_mulo(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulosb(a, b);
+ return __builtin_altivec_vmulosb(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_mulo(vector unsigned char a, vector unsigned char b)
+vec_mulo(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuloub(a, b);
+ return __builtin_altivec_vmuloub(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_mulo(vector short a, vector short b)
+vec_mulo(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulosh(a, b);
+ return __builtin_altivec_vmulosh(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_mulo(vector unsigned short a, vector unsigned short b)
+vec_mulo(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmulouh(a, b);
+ return __builtin_altivec_vmulouh(__a, __b);
}
/* vec_vmulosb */
static vector short __attribute__((__always_inline__))
-vec_vmulosb(vector signed char a, vector signed char b)
+vec_vmulosb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulosb(a, b);
+ return __builtin_altivec_vmulosb(__a, __b);
}
/* vec_vmuloub */
static vector unsigned short __attribute__((__always_inline__))
-vec_vmuloub(vector unsigned char a, vector unsigned char b)
+vec_vmuloub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuloub(a, b);
+ return __builtin_altivec_vmuloub(__a, __b);
}
/* vec_vmulosh */
static vector int __attribute__((__always_inline__))
-vec_vmulosh(vector short a, vector short b)
+vec_vmulosh(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulosh(a, b);
+ return __builtin_altivec_vmulosh(__a, __b);
}
/* vec_vmulouh */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmulouh(vector unsigned short a, vector unsigned short b)
+vec_vmulouh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmulouh(a, b);
+ return __builtin_altivec_vmulouh(__a, __b);
}
/* vec_nmsub */
static vector float __attribute__((__always_inline__))
-vec_nmsub(vector float a, vector float b, vector float c)
+vec_nmsub(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vnmsubfp(a, b, c);
+ return __builtin_altivec_vnmsubfp(__a, __b, __c);
}
/* vec_vnmsubfp */
static vector float __attribute__((__always_inline__))
-vec_vnmsubfp(vector float a, vector float b, vector float c)
+vec_vnmsubfp(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vnmsubfp(a, b, c);
+ return __builtin_altivec_vnmsubfp(__a, __b, __c);
}
/* vec_nor */
@@ -3622,127 +3622,127 @@ vec_vnmsubfp(vector float a, vector float b, vector float c)
#define __builtin_altivec_vnor vec_nor
static vector signed char __ATTRS_o_ai
-vec_nor(vector signed char a, vector signed char b)
+vec_nor(vector signed char __a, vector signed char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_nor(vector unsigned char a, vector unsigned char b)
+vec_nor(vector unsigned char __a, vector unsigned char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool char __ATTRS_o_ai
-vec_nor(vector bool char a, vector bool char b)
+vec_nor(vector bool char __a, vector bool char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector short __ATTRS_o_ai
-vec_nor(vector short a, vector short b)
+vec_nor(vector short __a, vector short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_nor(vector unsigned short a, vector unsigned short b)
+vec_nor(vector unsigned short __a, vector unsigned short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool short __ATTRS_o_ai
-vec_nor(vector bool short a, vector bool short b)
+vec_nor(vector bool short __a, vector bool short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector int __ATTRS_o_ai
-vec_nor(vector int a, vector int b)
+vec_nor(vector int __a, vector int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_nor(vector unsigned int a, vector unsigned int b)
+vec_nor(vector unsigned int __a, vector unsigned int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool int __ATTRS_o_ai
-vec_nor(vector bool int a, vector bool int b)
+vec_nor(vector bool int __a, vector bool int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector float __ATTRS_o_ai
-vec_nor(vector float a, vector float b)
+vec_nor(vector float __a, vector float __b)
{
- vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b);
- return (vector float)res;
+ vector unsigned int __res = ~((vector unsigned int)__a | (vector unsigned int)__b);
+ return (vector float)__res;
}
/* vec_vnor */
static vector signed char __ATTRS_o_ai
-vec_vnor(vector signed char a, vector signed char b)
+vec_vnor(vector signed char __a, vector signed char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vnor(vector unsigned char a, vector unsigned char b)
+vec_vnor(vector unsigned char __a, vector unsigned char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool char __ATTRS_o_ai
-vec_vnor(vector bool char a, vector bool char b)
+vec_vnor(vector bool char __a, vector bool char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector short __ATTRS_o_ai
-vec_vnor(vector short a, vector short b)
+vec_vnor(vector short __a, vector short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vnor(vector unsigned short a, vector unsigned short b)
+vec_vnor(vector unsigned short __a, vector unsigned short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool short __ATTRS_o_ai
-vec_vnor(vector bool short a, vector bool short b)
+vec_vnor(vector bool short __a, vector bool short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector int __ATTRS_o_ai
-vec_vnor(vector int a, vector int b)
+vec_vnor(vector int __a, vector int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vnor(vector unsigned int a, vector unsigned int b)
+vec_vnor(vector unsigned int __a, vector unsigned int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool int __ATTRS_o_ai
-vec_vnor(vector bool int a, vector bool int b)
+vec_vnor(vector bool int __a, vector bool int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector float __ATTRS_o_ai
-vec_vnor(vector float a, vector float b)
+vec_vnor(vector float __a, vector float __b)
{
- vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b);
- return (vector float)res;
+ vector unsigned int __res = ~((vector unsigned int)__a | (vector unsigned int)__b);
+ return (vector float)__res;
}
/* vec_or */
@@ -3750,347 +3750,347 @@ vec_vnor(vector float a, vector float b)
#define __builtin_altivec_vor vec_or
static vector signed char __ATTRS_o_ai
-vec_or(vector signed char a, vector signed char b)
+vec_or(vector signed char __a, vector signed char __b)
{
- return a | b;
+ return __a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_or(vector bool char a, vector signed char b)
+vec_or(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a | b;
+ return (vector signed char)__a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_or(vector signed char a, vector bool char b)
+vec_or(vector signed char __a, vector bool char __b)
{
- return a | (vector signed char)b;
+ return __a | (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_or(vector unsigned char a, vector unsigned char b)
+vec_or(vector unsigned char __a, vector unsigned char __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_or(vector bool char a, vector unsigned char b)
+vec_or(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a | b;
+ return (vector unsigned char)__a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_or(vector unsigned char a, vector bool char b)
+vec_or(vector unsigned char __a, vector bool char __b)
{
- return a | (vector unsigned char)b;
+ return __a | (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_or(vector bool char a, vector bool char b)
+vec_or(vector bool char __a, vector bool char __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_or(vector short a, vector short b)
+vec_or(vector short __a, vector short __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_or(vector bool short a, vector short b)
+vec_or(vector bool short __a, vector short __b)
{
- return (vector short)a | b;
+ return (vector short)__a | __b;
}
static vector short __ATTRS_o_ai
-vec_or(vector short a, vector bool short b)
+vec_or(vector short __a, vector bool short __b)
{
- return a | (vector short)b;
+ return __a | (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_or(vector unsigned short a, vector unsigned short b)
+vec_or(vector unsigned short __a, vector unsigned short __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_or(vector bool short a, vector unsigned short b)
+vec_or(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a | b;
+ return (vector unsigned short)__a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_or(vector unsigned short a, vector bool short b)
+vec_or(vector unsigned short __a, vector bool short __b)
{
- return a | (vector unsigned short)b;
+ return __a | (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_or(vector bool short a, vector bool short b)
+vec_or(vector bool short __a, vector bool short __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_or(vector int a, vector int b)
+vec_or(vector int __a, vector int __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_or(vector bool int a, vector int b)
+vec_or(vector bool int __a, vector int __b)
{
- return (vector int)a | b;
+ return (vector int)__a | __b;
}
static vector int __ATTRS_o_ai
-vec_or(vector int a, vector bool int b)
+vec_or(vector int __a, vector bool int __b)
{
- return a | (vector int)b;
+ return __a | (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_or(vector unsigned int a, vector unsigned int b)
+vec_or(vector unsigned int __a, vector unsigned int __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_or(vector bool int a, vector unsigned int b)
+vec_or(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a | b;
+ return (vector unsigned int)__a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_or(vector unsigned int a, vector bool int b)
+vec_or(vector unsigned int __a, vector bool int __b)
{
- return a | (vector unsigned int)b;
+ return __a | (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_or(vector bool int a, vector bool int b)
+vec_or(vector bool int __a, vector bool int __b)
{
- return a | b;
+ return __a | __b;
}
static vector float __ATTRS_o_ai
-vec_or(vector float a, vector float b)
+vec_or(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_or(vector bool int a, vector float b)
+vec_or(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_or(vector float a, vector bool int b)
+vec_or(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vor */
static vector signed char __ATTRS_o_ai
-vec_vor(vector signed char a, vector signed char b)
+vec_vor(vector signed char __a, vector signed char __b)
{
- return a | b;
+ return __a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_vor(vector bool char a, vector signed char b)
+vec_vor(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a | b;
+ return (vector signed char)__a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_vor(vector signed char a, vector bool char b)
+vec_vor(vector signed char __a, vector bool char __b)
{
- return a | (vector signed char)b;
+ return __a | (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vor(vector unsigned char a, vector unsigned char b)
+vec_vor(vector unsigned char __a, vector unsigned char __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vor(vector bool char a, vector unsigned char b)
+vec_vor(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a | b;
+ return (vector unsigned char)__a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vor(vector unsigned char a, vector bool char b)
+vec_vor(vector unsigned char __a, vector bool char __b)
{
- return a | (vector unsigned char)b;
+ return __a | (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vor(vector bool char a, vector bool char b)
+vec_vor(vector bool char __a, vector bool char __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_vor(vector short a, vector short b)
+vec_vor(vector short __a, vector short __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_vor(vector bool short a, vector short b)
+vec_vor(vector bool short __a, vector short __b)
{
- return (vector short)a | b;
+ return (vector short)__a | __b;
}
static vector short __ATTRS_o_ai
-vec_vor(vector short a, vector bool short b)
+vec_vor(vector short __a, vector bool short __b)
{
- return a | (vector short)b;
+ return __a | (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vor(vector unsigned short a, vector unsigned short b)
+vec_vor(vector unsigned short __a, vector unsigned short __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vor(vector bool short a, vector unsigned short b)
+vec_vor(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a | b;
+ return (vector unsigned short)__a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vor(vector unsigned short a, vector bool short b)
+vec_vor(vector unsigned short __a, vector bool short __b)
{
- return a | (vector unsigned short)b;
+ return __a | (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vor(vector bool short a, vector bool short b)
+vec_vor(vector bool short __a, vector bool short __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_vor(vector int a, vector int b)
+vec_vor(vector int __a, vector int __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_vor(vector bool int a, vector int b)
+vec_vor(vector bool int __a, vector int __b)
{
- return (vector int)a | b;
+ return (vector int)__a | __b;
}
static vector int __ATTRS_o_ai
-vec_vor(vector int a, vector bool int b)
+vec_vor(vector int __a, vector bool int __b)
{
- return a | (vector int)b;
+ return __a | (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vor(vector unsigned int a, vector unsigned int b)
+vec_vor(vector unsigned int __a, vector unsigned int __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vor(vector bool int a, vector unsigned int b)
+vec_vor(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a | b;
+ return (vector unsigned int)__a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vor(vector unsigned int a, vector bool int b)
+vec_vor(vector unsigned int __a, vector bool int __b)
{
- return a | (vector unsigned int)b;
+ return __a | (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vor(vector bool int a, vector bool int b)
+vec_vor(vector bool int __a, vector bool int __b)
{
- return a | b;
+ return __a | __b;
}
static vector float __ATTRS_o_ai
-vec_vor(vector float a, vector float b)
+vec_vor(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vor(vector bool int a, vector float b)
+vec_vor(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vor(vector float a, vector bool int b)
+vec_vor(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_pack */
static vector signed char __ATTRS_o_ai
-vec_pack(vector signed short a, vector signed short b)
+vec_pack(vector signed short __a, vector signed short __b)
{
- return (vector signed char)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector unsigned char __ATTRS_o_ai
-vec_pack(vector unsigned short a, vector unsigned short b)
+vec_pack(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned char)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector bool char __ATTRS_o_ai
-vec_pack(vector bool short a, vector bool short b)
+vec_pack(vector bool short __a, vector bool short __b)
{
- return (vector bool char)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector short __ATTRS_o_ai
-vec_pack(vector int a, vector int b)
+vec_pack(vector int __a, vector int __b)
{
- return (vector short)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector unsigned short __ATTRS_o_ai
-vec_pack(vector unsigned int a, vector unsigned int b)
+vec_pack(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned short)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector bool short __ATTRS_o_ai
-vec_pack(vector bool int a, vector bool int b)
+vec_pack(vector bool int __a, vector bool int __b)
{
- return (vector bool short)vec_perm(a, b, (vector unsigned char)
+ 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));
}
@@ -4100,25 +4100,25 @@ vec_pack(vector bool int a, vector bool int b)
#define __builtin_altivec_vpkuhum vec_vpkuhum
static vector signed char __ATTRS_o_ai
-vec_vpkuhum(vector signed short a, vector signed short b)
+vec_vpkuhum(vector signed short __a, vector signed short __b)
{
- return (vector signed char)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector unsigned char __ATTRS_o_ai
-vec_vpkuhum(vector unsigned short a, vector unsigned short b)
+vec_vpkuhum(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned char)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector bool char __ATTRS_o_ai
-vec_vpkuhum(vector bool short a, vector bool short b)
+vec_vpkuhum(vector bool short __a, vector bool short __b)
{
- return (vector bool char)vec_perm(a, b, (vector unsigned char)
+ 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));
}
@@ -4128,25 +4128,25 @@ vec_vpkuhum(vector bool short a, vector bool short b)
#define __builtin_altivec_vpkuwum vec_vpkuwum
static vector short __ATTRS_o_ai
-vec_vpkuwum(vector int a, vector int b)
+vec_vpkuwum(vector int __a, vector int __b)
{
- return (vector short)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector unsigned short __ATTRS_o_ai
-vec_vpkuwum(vector unsigned int a, vector unsigned int b)
+vec_vpkuwum(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned short)vec_perm(a, b, (vector unsigned char)
+ 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));
}
static vector bool short __ATTRS_o_ai
-vec_vpkuwum(vector bool int a, vector bool int b)
+vec_vpkuwum(vector bool int __a, vector bool int __b)
{
- return (vector bool short)vec_perm(a, b, (vector unsigned char)
+ 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));
}
@@ -4154,421 +4154,421 @@ vec_vpkuwum(vector bool int a, vector bool int b)
/* vec_packpx */
static vector pixel __attribute__((__always_inline__))
-vec_packpx(vector unsigned int a, vector unsigned int b)
+vec_packpx(vector unsigned int __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vpkpx(a, b);
+ return (vector pixel)__builtin_altivec_vpkpx(__a, __b);
}
/* vec_vpkpx */
static vector pixel __attribute__((__always_inline__))
-vec_vpkpx(vector unsigned int a, vector unsigned int b)
+vec_vpkpx(vector unsigned int __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vpkpx(a, b);
+ return (vector pixel)__builtin_altivec_vpkpx(__a, __b);
}
/* vec_packs */
static vector signed char __ATTRS_o_ai
-vec_packs(vector short a, vector short b)
+vec_packs(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshss(a, b);
+ return __builtin_altivec_vpkshss(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_packs(vector unsigned short a, vector unsigned short b)
+vec_packs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
static vector signed short __ATTRS_o_ai
-vec_packs(vector int a, vector int b)
+vec_packs(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswss(a, b);
+ return __builtin_altivec_vpkswss(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_packs(vector unsigned int a, vector unsigned int b)
+vec_packs(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_vpkshss */
static vector signed char __attribute__((__always_inline__))
-vec_vpkshss(vector short a, vector short b)
+vec_vpkshss(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshss(a, b);
+ return __builtin_altivec_vpkshss(__a, __b);
}
/* vec_vpkuhus */
static vector unsigned char __attribute__((__always_inline__))
-vec_vpkuhus(vector unsigned short a, vector unsigned short b)
+vec_vpkuhus(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
/* vec_vpkswss */
static vector signed short __attribute__((__always_inline__))
-vec_vpkswss(vector int a, vector int b)
+vec_vpkswss(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswss(a, b);
+ return __builtin_altivec_vpkswss(__a, __b);
}
/* vec_vpkuwus */
static vector unsigned short __attribute__((__always_inline__))
-vec_vpkuwus(vector unsigned int a, vector unsigned int b)
+vec_vpkuwus(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_packsu */
static vector unsigned char __ATTRS_o_ai
-vec_packsu(vector short a, vector short b)
+vec_packsu(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshus(a, b);
+ return __builtin_altivec_vpkshus(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_packsu(vector unsigned short a, vector unsigned short b)
+vec_packsu(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_packsu(vector int a, vector int b)
+vec_packsu(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswus(a, b);
+ return __builtin_altivec_vpkswus(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_packsu(vector unsigned int a, vector unsigned int b)
+vec_packsu(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_vpkshus */
static vector unsigned char __ATTRS_o_ai
-vec_vpkshus(vector short a, vector short b)
+vec_vpkshus(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshus(a, b);
+ return __builtin_altivec_vpkshus(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vpkshus(vector unsigned short a, vector unsigned short b)
+vec_vpkshus(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
/* vec_vpkswus */
static vector unsigned short __ATTRS_o_ai
-vec_vpkswus(vector int a, vector int b)
+vec_vpkswus(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswus(a, b);
+ return __builtin_altivec_vpkswus(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vpkswus(vector unsigned int a, vector unsigned int b)
+vec_vpkswus(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_perm */
vector signed char __ATTRS_o_ai
-vec_perm(vector signed char a, vector signed char b, vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector unsigned char __ATTRS_o_ai
-vec_perm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector bool char __ATTRS_o_ai
-vec_perm(vector bool char a, vector bool char b, vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector short __ATTRS_o_ai
-vec_perm(vector short a, vector short b, vector unsigned char c)
+vec_perm(vector short __a, vector short __b, vector unsigned char __c)
{
return (vector short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector unsigned short __ATTRS_o_ai
-vec_perm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector bool short __ATTRS_o_ai
-vec_perm(vector bool short a, vector bool short b, vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector pixel __ATTRS_o_ai
-vec_perm(vector pixel a, vector pixel b, vector unsigned char c)
+vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c)
{
return (vector pixel)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector int __ATTRS_o_ai
-vec_perm(vector int a, vector int b, vector unsigned char c)
+vec_perm(vector int __a, vector int __b, vector unsigned char __c)
{
- return (vector int)__builtin_altivec_vperm_4si(a, b, c);
+ return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c);
}
vector unsigned int __ATTRS_o_ai
-vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector bool int __ATTRS_o_ai
-vec_perm(vector bool int a, vector bool int b, vector unsigned char c)
+vec_perm(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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector float __ATTRS_o_ai
-vec_perm(vector float a, vector float b, vector unsigned char c)
+vec_perm(vector float __a, vector float __b, vector unsigned char __c)
{
return (vector float)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
/* vec_vperm */
static vector signed char __ATTRS_o_ai
-vec_vperm(vector signed char a, vector signed char b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector unsigned char __ATTRS_o_ai
-vec_vperm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector bool char __ATTRS_o_ai
-vec_vperm(vector bool char a, vector bool char b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector short __ATTRS_o_ai
-vec_vperm(vector short a, vector short b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector unsigned short __ATTRS_o_ai
-vec_vperm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector bool short __ATTRS_o_ai
-vec_vperm(vector bool short a, vector bool short b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector pixel __ATTRS_o_ai
-vec_vperm(vector pixel a, vector pixel b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector int __ATTRS_o_ai
-vec_vperm(vector int a, vector int b, vector unsigned char c)
+vec_vperm(vector int __a, vector int __b, vector unsigned char __c)
{
- return (vector int)__builtin_altivec_vperm_4si(a, b, c);
+ return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector bool int __ATTRS_o_ai
-vec_vperm(vector bool int a, vector bool int b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector float __ATTRS_o_ai
-vec_vperm(vector float a, vector float b, vector unsigned char c)
+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);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
/* vec_re */
static vector float __attribute__((__always_inline__))
-vec_re(vector float a)
+vec_re(vector float __a)
{
- return __builtin_altivec_vrefp(a);
+ return __builtin_altivec_vrefp(__a);
}
/* vec_vrefp */
static vector float __attribute__((__always_inline__))
-vec_vrefp(vector float a)
+vec_vrefp(vector float __a)
{
- return __builtin_altivec_vrefp(a);
+ return __builtin_altivec_vrefp(__a);
}
/* vec_rl */
static vector signed char __ATTRS_o_ai
-vec_rl(vector signed char a, vector unsigned char b)
+vec_rl(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vrlb((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_rl(vector unsigned char a, vector unsigned char b)
+vec_rl(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vrlb((vector char)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_rl(vector short a, vector unsigned short b)
+vec_rl(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vrlh(a, b);
+ return __builtin_altivec_vrlh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_rl(vector unsigned short a, vector unsigned short b)
+vec_rl(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vrlh((vector short)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_rl(vector int a, vector unsigned int b)
+vec_rl(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vrlw(a, b);
+ return __builtin_altivec_vrlw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_rl(vector unsigned int a, vector unsigned int b)
+vec_rl(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vrlw((vector int)__a, __b);
}
/* vec_vrlb */
static vector signed char __ATTRS_o_ai
-vec_vrlb(vector signed char a, vector unsigned char b)
+vec_vrlb(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vrlb((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vrlb(vector unsigned char a, vector unsigned char b)
+vec_vrlb(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vrlb((vector char)__a, __b);
}
/* vec_vrlh */
static vector short __ATTRS_o_ai
-vec_vrlh(vector short a, vector unsigned short b)
+vec_vrlh(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vrlh(a, b);
+ return __builtin_altivec_vrlh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vrlh(vector unsigned short a, vector unsigned short b)
+vec_vrlh(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vrlh((vector short)__a, __b);
}
/* vec_vrlw */
static vector int __ATTRS_o_ai
-vec_vrlw(vector int a, vector unsigned int b)
+vec_vrlw(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vrlw(a, b);
+ return __builtin_altivec_vrlw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vrlw(vector unsigned int a, vector unsigned int b)
+vec_vrlw(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vrlw((vector int)__a, __b);
}
/* vec_round */
static vector float __attribute__((__always_inline__))
-vec_round(vector float a)
+vec_round(vector float __a)
{
- return __builtin_altivec_vrfin(a);
+ return __builtin_altivec_vrfin(__a);
}
/* vec_vrfin */
static vector float __attribute__((__always_inline__))
-vec_vrfin(vector float a)
+vec_vrfin(vector float __a)
{
- return __builtin_altivec_vrfin(a);
+ return __builtin_altivec_vrfin(__a);
}
/* vec_rsqrte */
static __vector float __attribute__((__always_inline__))
-vec_rsqrte(vector float a)
+vec_rsqrte(vector float __a)
{
- return __builtin_altivec_vrsqrtefp(a);
+ return __builtin_altivec_vrsqrtefp(__a);
}
/* vec_vrsqrtefp */
static __vector float __attribute__((__always_inline__))
-vec_vrsqrtefp(vector float a)
+vec_vrsqrtefp(vector float __a)
{
- return __builtin_altivec_vrsqrtefp(a);
+ return __builtin_altivec_vrsqrtefp(__a);
}
/* vec_sel */
@@ -4576,295 +4576,295 @@ vec_vrsqrtefp(vector float a)
#define __builtin_altivec_vsel_4si vec_sel
static vector signed char __ATTRS_o_ai
-vec_sel(vector signed char a, vector signed char b, vector unsigned char c)
+vec_sel(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector signed char __ATTRS_o_ai
-vec_sel(vector signed char a, vector signed char b, vector bool char c)
+vec_sel(vector signed char __a, vector signed char __b, vector bool char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector unsigned char __ATTRS_o_ai
-vec_sel(vector unsigned char a, vector unsigned char b, vector unsigned char c)
+vec_sel(vector unsigned char __a, vector unsigned char __b, vector unsigned char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned char __ATTRS_o_ai
-vec_sel(vector unsigned char a, vector unsigned char b, vector bool char c)
+vec_sel(vector unsigned char __a, vector unsigned char __b, vector bool char __c)
{
- return (a & ~(vector unsigned char)c) | (b & (vector unsigned char)c);
+ return (__a & ~(vector unsigned char)__c) | (__b & (vector unsigned char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_sel(vector bool char a, vector bool char b, vector unsigned char c)
+vec_sel(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
- return (a & ~(vector bool char)c) | (b & (vector bool char)c);
+ return (__a & ~(vector bool char)__c) | (__b & (vector bool char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_sel(vector bool char a, vector bool char b, vector bool char c)
+vec_sel(vector bool char __a, vector bool char __b, vector bool char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector short __ATTRS_o_ai
-vec_sel(vector short a, vector short b, vector unsigned short c)
+vec_sel(vector short __a, vector short __b, vector unsigned short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector short __ATTRS_o_ai
-vec_sel(vector short a, vector short b, vector bool short c)
+vec_sel(vector short __a, vector short __b, vector bool short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector unsigned short __ATTRS_o_ai
-vec_sel(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_sel(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned short __ATTRS_o_ai
-vec_sel(vector unsigned short a, vector unsigned short b, vector bool short c)
+vec_sel(vector unsigned short __a, vector unsigned short __b, vector bool short __c)
{
- return (a & ~(vector unsigned short)c) | (b & (vector unsigned short)c);
+ return (__a & ~(vector unsigned short)__c) | (__b & (vector unsigned short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_sel(vector bool short a, vector bool short b, vector unsigned short c)
+vec_sel(vector bool short __a, vector bool short __b, vector unsigned short __c)
{
- return (a & ~(vector bool short)c) | (b & (vector bool short)c);
+ return (__a & ~(vector bool short)__c) | (__b & (vector bool short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_sel(vector bool short a, vector bool short b, vector bool short c)
+vec_sel(vector bool short __a, vector bool short __b, vector bool short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector int __ATTRS_o_ai
-vec_sel(vector int a, vector int b, vector unsigned int c)
+vec_sel(vector int __a, vector int __b, vector unsigned int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector int __ATTRS_o_ai
-vec_sel(vector int a, vector int b, vector bool int c)
+vec_sel(vector int __a, vector int __b, vector bool int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector unsigned int __ATTRS_o_ai
-vec_sel(vector unsigned int a, vector unsigned int b, vector unsigned int c)
+vec_sel(vector unsigned int __a, vector unsigned int __b, vector unsigned int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_sel(vector unsigned int a, vector unsigned int b, vector bool int c)
+vec_sel(vector unsigned int __a, vector unsigned int __b, vector bool int __c)
{
- return (a & ~(vector unsigned int)c) | (b & (vector unsigned int)c);
+ return (__a & ~(vector unsigned int)__c) | (__b & (vector unsigned int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_sel(vector bool int a, vector bool int b, vector unsigned int c)
+vec_sel(vector bool int __a, vector bool int __b, vector unsigned int __c)
{
- return (a & ~(vector bool int)c) | (b & (vector bool int)c);
+ return (__a & ~(vector bool int)__c) | (__b & (vector bool int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_sel(vector bool int a, vector bool int b, vector bool int c)
+vec_sel(vector bool int __a, vector bool int __b, vector bool int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector float __ATTRS_o_ai
-vec_sel(vector float a, vector float b, vector unsigned int c)
+vec_sel(vector float __a, vector float __b, vector unsigned int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_sel(vector float a, vector float b, vector bool int c)
+vec_sel(vector float __a, vector float __b, vector bool int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
/* vec_vsel */
static vector signed char __ATTRS_o_ai
-vec_vsel(vector signed char a, vector signed char b, vector unsigned char c)
+vec_vsel(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector signed char __ATTRS_o_ai
-vec_vsel(vector signed char a, vector signed char b, vector bool char c)
+vec_vsel(vector signed char __a, vector signed char __b, vector bool char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsel(vector unsigned char a, vector unsigned char b, vector unsigned char c)
+vec_vsel(vector unsigned char __a, vector unsigned char __b, vector unsigned char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsel(vector unsigned char a, vector unsigned char b, vector bool char c)
+vec_vsel(vector unsigned char __a, vector unsigned char __b, vector bool char __c)
{
- return (a & ~(vector unsigned char)c) | (b & (vector unsigned char)c);
+ return (__a & ~(vector unsigned char)__c) | (__b & (vector unsigned char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_vsel(vector bool char a, vector bool char b, vector unsigned char c)
+vec_vsel(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
- return (a & ~(vector bool char)c) | (b & (vector bool char)c);
+ return (__a & ~(vector bool char)__c) | (__b & (vector bool char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_vsel(vector bool char a, vector bool char b, vector bool char c)
+vec_vsel(vector bool char __a, vector bool char __b, vector bool char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector short __ATTRS_o_ai
-vec_vsel(vector short a, vector short b, vector unsigned short c)
+vec_vsel(vector short __a, vector short __b, vector unsigned short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector short __ATTRS_o_ai
-vec_vsel(vector short a, vector short b, vector bool short c)
+vec_vsel(vector short __a, vector short __b, vector bool short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsel(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_vsel(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsel(vector unsigned short a, vector unsigned short b, vector bool short c)
+vec_vsel(vector unsigned short __a, vector unsigned short __b, vector bool short __c)
{
- return (a & ~(vector unsigned short)c) | (b & (vector unsigned short)c);
+ return (__a & ~(vector unsigned short)__c) | (__b & (vector unsigned short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_vsel(vector bool short a, vector bool short b, vector unsigned short c)
+vec_vsel(vector bool short __a, vector bool short __b, vector unsigned short __c)
{
- return (a & ~(vector bool short)c) | (b & (vector bool short)c);
+ return (__a & ~(vector bool short)__c) | (__b & (vector bool short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_vsel(vector bool short a, vector bool short b, vector bool short c)
+vec_vsel(vector bool short __a, vector bool short __b, vector bool short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector int __ATTRS_o_ai
-vec_vsel(vector int a, vector int b, vector unsigned int c)
+vec_vsel(vector int __a, vector int __b, vector unsigned int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector int __ATTRS_o_ai
-vec_vsel(vector int a, vector int b, vector bool int c)
+vec_vsel(vector int __a, vector int __b, vector bool int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsel(vector unsigned int a, vector unsigned int b, vector unsigned int c)
+vec_vsel(vector unsigned int __a, vector unsigned int __b, vector unsigned int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsel(vector unsigned int a, vector unsigned int b, vector bool int c)
+vec_vsel(vector unsigned int __a, vector unsigned int __b, vector bool int __c)
{
- return (a & ~(vector unsigned int)c) | (b & (vector unsigned int)c);
+ return (__a & ~(vector unsigned int)__c) | (__b & (vector unsigned int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_vsel(vector bool int a, vector bool int b, vector unsigned int c)
+vec_vsel(vector bool int __a, vector bool int __b, vector unsigned int __c)
{
- return (a & ~(vector bool int)c) | (b & (vector bool int)c);
+ return (__a & ~(vector bool int)__c) | (__b & (vector bool int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_vsel(vector bool int a, vector bool int b, vector bool int c)
+vec_vsel(vector bool int __a, vector bool int __b, vector bool int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector float __ATTRS_o_ai
-vec_vsel(vector float a, vector float b, vector unsigned int c)
+vec_vsel(vector float __a, vector float __b, vector unsigned int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vsel(vector float a, vector float b, vector bool int c)
+vec_vsel(vector float __a, vector float __b, vector bool int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
/* vec_sl */
static vector signed char __ATTRS_o_ai
-vec_sl(vector signed char a, vector unsigned char b)
+vec_sl(vector signed char __a, vector unsigned char __b)
{
- return a << (vector signed char)b;
+ return __a << (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sl(vector unsigned char a, vector unsigned char b)
+vec_sl(vector unsigned char __a, vector unsigned char __b)
{
- return a << b;
+ return __a << __b;
}
static vector short __ATTRS_o_ai
-vec_sl(vector short a, vector unsigned short b)
+vec_sl(vector short __a, vector unsigned short __b)
{
- return a << (vector short)b;
+ return __a << (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sl(vector unsigned short a, vector unsigned short b)
+vec_sl(vector unsigned short __a, vector unsigned short __b)
{
- return a << b;
+ return __a << __b;
}
static vector int __ATTRS_o_ai
-vec_sl(vector int a, vector unsigned int b)
+vec_sl(vector int __a, vector unsigned int __b)
{
- return a << (vector int)b;
+ return __a << (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sl(vector unsigned int a, vector unsigned int b)
+vec_sl(vector unsigned int __a, vector unsigned int __b)
{
- return a << b;
+ return __a << __b;
}
/* vec_vslb */
@@ -4872,15 +4872,15 @@ vec_sl(vector unsigned int a, vector unsigned int b)
#define __builtin_altivec_vslb vec_vslb
static vector signed char __ATTRS_o_ai
-vec_vslb(vector signed char a, vector unsigned char b)
+vec_vslb(vector signed char __a, vector unsigned char __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vslb(vector unsigned char a, vector unsigned char b)
+vec_vslb(vector unsigned char __a, vector unsigned char __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
/* vec_vslh */
@@ -4888,15 +4888,15 @@ vec_vslb(vector unsigned char a, vector unsigned char b)
#define __builtin_altivec_vslh vec_vslh
static vector short __ATTRS_o_ai
-vec_vslh(vector short a, vector unsigned short b)
+vec_vslh(vector short __a, vector unsigned short __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vslh(vector unsigned short a, vector unsigned short b)
+vec_vslh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
/* vec_vslw */
@@ -4904,15 +4904,15 @@ vec_vslh(vector unsigned short a, vector unsigned short b)
#define __builtin_altivec_vslw vec_vslw
static vector int __ATTRS_o_ai
-vec_vslw(vector int a, vector unsigned int b)
+vec_vslw(vector int __a, vector unsigned int __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vslw(vector unsigned int a, vector unsigned int b)
+vec_vslw(vector unsigned int __a, vector unsigned int __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
/* vec_sld */
@@ -4920,825 +4920,825 @@ vec_vslw(vector unsigned int a, vector unsigned int b)
#define __builtin_altivec_vsldoi_4si vec_sld
static vector signed char __ATTRS_o_ai
-vec_sld(vector signed char a, vector signed char b, unsigned char c)
+vec_sld(vector signed char __a, vector signed char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned char __ATTRS_o_ai
-vec_sld(vector unsigned char a, vector unsigned char b, unsigned char c)
+vec_sld(vector unsigned char __a, vector unsigned char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector short __ATTRS_o_ai
-vec_sld(vector short a, vector short b, unsigned char c)
+vec_sld(vector short __a, vector short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned short __ATTRS_o_ai
-vec_sld(vector unsigned short a, vector unsigned short b, unsigned char c)
+vec_sld(vector unsigned short __a, vector unsigned short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector pixel __ATTRS_o_ai
-vec_sld(vector pixel a, vector pixel b, unsigned char c)
+vec_sld(vector pixel __a, vector pixel __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector int __ATTRS_o_ai
-vec_sld(vector int a, vector int b, unsigned char c)
+vec_sld(vector int __a, vector int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned int __ATTRS_o_ai
-vec_sld(vector unsigned int a, vector unsigned int b, unsigned char c)
+vec_sld(vector unsigned int __a, vector unsigned int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector float __ATTRS_o_ai
-vec_sld(vector float a, vector float b, unsigned char c)
+vec_sld(vector float __a, vector float __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
/* vec_vsldoi */
static vector signed char __ATTRS_o_ai
-vec_vsldoi(vector signed char a, vector signed char b, unsigned char c)
+vec_vsldoi(vector signed char __a, vector signed char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned char __ATTRS_o_ai
-vec_vsldoi(vector unsigned char a, vector unsigned char b, unsigned char c)
+vec_vsldoi(vector unsigned char __a, vector unsigned char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector short __ATTRS_o_ai
-vec_vsldoi(vector short a, vector short b, unsigned char c)
+vec_vsldoi(vector short __a, vector short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned short __ATTRS_o_ai
-vec_vsldoi(vector unsigned short a, vector unsigned short b, unsigned char c)
+vec_vsldoi(vector unsigned short __a, vector unsigned short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector pixel __ATTRS_o_ai
-vec_vsldoi(vector pixel a, vector pixel b, unsigned char c)
+vec_vsldoi(vector pixel __a, vector pixel __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector int __ATTRS_o_ai
-vec_vsldoi(vector int a, vector int b, unsigned char c)
+vec_vsldoi(vector int __a, vector int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned int __ATTRS_o_ai
-vec_vsldoi(vector unsigned int a, vector unsigned int b, unsigned char c)
+vec_vsldoi(vector unsigned int __a, vector unsigned int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector float __ATTRS_o_ai
-vec_vsldoi(vector float a, vector float b, unsigned char c)
+vec_vsldoi(vector float __a, vector float __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
/* vec_sll */
static vector signed char __ATTRS_o_ai
-vec_sll(vector signed char a, vector unsigned char b)
+vec_sll(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_sll(vector signed char a, vector unsigned short b)
+vec_sll(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_sll(vector signed char a, vector unsigned int b)
+vec_sll(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sll(vector unsigned char a, vector unsigned char b)
+vec_sll(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sll(vector unsigned char a, vector unsigned short b)
+vec_sll(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sll(vector unsigned char a, vector unsigned int b)
+vec_sll(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_sll(vector bool char a, vector unsigned char b)
+vec_sll(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_sll(vector bool char a, vector unsigned short b)
+vec_sll(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_sll(vector bool char a, vector unsigned int b)
+vec_sll(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sll(vector short a, vector unsigned char b)
+vec_sll(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sll(vector short a, vector unsigned short b)
+vec_sll(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sll(vector short a, vector unsigned int b)
+vec_sll(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sll(vector unsigned short a, vector unsigned char b)
+vec_sll(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sll(vector unsigned short a, vector unsigned short b)
+vec_sll(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sll(vector unsigned short a, vector unsigned int b)
+vec_sll(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_sll(vector bool short a, vector unsigned char b)
+vec_sll(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_sll(vector bool short a, vector unsigned short b)
+vec_sll(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_sll(vector bool short a, vector unsigned int b)
+vec_sll(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sll(vector pixel a, vector unsigned char b)
+vec_sll(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sll(vector pixel a, vector unsigned short b)
+vec_sll(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sll(vector pixel a, vector unsigned int b)
+vec_sll(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sll(vector int a, vector unsigned char b)
+vec_sll(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sll(vector int a, vector unsigned short b)
+vec_sll(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sll(vector int a, vector unsigned int b)
+vec_sll(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sll(vector unsigned int a, vector unsigned char b)
+vec_sll(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sll(vector unsigned int a, vector unsigned short b)
+vec_sll(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sll(vector unsigned int a, vector unsigned int b)
+vec_sll(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_sll(vector bool int a, vector unsigned char b)
+vec_sll(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_sll(vector bool int a, vector unsigned short b)
+vec_sll(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_sll(vector bool int a, vector unsigned int b)
+vec_sll(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
/* vec_vsl */
static vector signed char __ATTRS_o_ai
-vec_vsl(vector signed char a, vector unsigned char b)
+vec_vsl(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsl(vector signed char a, vector unsigned short b)
+vec_vsl(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsl(vector signed char a, vector unsigned int b)
+vec_vsl(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsl(vector unsigned char a, vector unsigned char b)
+vec_vsl(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsl(vector unsigned char a, vector unsigned short b)
+vec_vsl(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsl(vector unsigned char a, vector unsigned int b)
+vec_vsl(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsl(vector bool char a, vector unsigned char b)
+vec_vsl(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsl(vector bool char a, vector unsigned short b)
+vec_vsl(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsl(vector bool char a, vector unsigned int b)
+vec_vsl(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsl(vector short a, vector unsigned char b)
+vec_vsl(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsl(vector short a, vector unsigned short b)
+vec_vsl(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsl(vector short a, vector unsigned int b)
+vec_vsl(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsl(vector unsigned short a, vector unsigned char b)
+vec_vsl(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsl(vector unsigned short a, vector unsigned short b)
+vec_vsl(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsl(vector unsigned short a, vector unsigned int b)
+vec_vsl(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsl(vector bool short a, vector unsigned char b)
+vec_vsl(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsl(vector bool short a, vector unsigned short b)
+vec_vsl(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsl(vector bool short a, vector unsigned int b)
+vec_vsl(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsl(vector pixel a, vector unsigned char b)
+vec_vsl(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsl(vector pixel a, vector unsigned short b)
+vec_vsl(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsl(vector pixel a, vector unsigned int b)
+vec_vsl(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsl(vector int a, vector unsigned char b)
+vec_vsl(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsl(vector int a, vector unsigned short b)
+vec_vsl(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsl(vector int a, vector unsigned int b)
+vec_vsl(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsl(vector unsigned int a, vector unsigned char b)
+vec_vsl(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsl(vector unsigned int a, vector unsigned short b)
+vec_vsl(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsl(vector unsigned int a, vector unsigned int b)
+vec_vsl(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsl(vector bool int a, vector unsigned char b)
+vec_vsl(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsl(vector bool int a, vector unsigned short b)
+vec_vsl(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsl(vector bool int a, vector unsigned int b)
+vec_vsl(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
/* vec_slo */
static vector signed char __ATTRS_o_ai
-vec_slo(vector signed char a, vector signed char b)
+vec_slo(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_slo(vector signed char a, vector unsigned char b)
+vec_slo(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_slo(vector unsigned char a, vector signed char b)
+vec_slo(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_slo(vector unsigned char a, vector unsigned char b)
+vec_slo(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_slo(vector short a, vector signed char b)
+vec_slo(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_slo(vector short a, vector unsigned char b)
+vec_slo(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_slo(vector unsigned short a, vector signed char b)
+vec_slo(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_slo(vector unsigned short a, vector unsigned char b)
+vec_slo(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_slo(vector pixel a, vector signed char b)
+vec_slo(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_slo(vector pixel a, vector unsigned char b)
+vec_slo(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_slo(vector int a, vector signed char b)
+vec_slo(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_slo(vector int a, vector unsigned char b)
+vec_slo(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_slo(vector unsigned int a, vector signed char b)
+vec_slo(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_slo(vector unsigned int a, vector unsigned char b)
+vec_slo(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_slo(vector float a, vector signed char b)
+vec_slo(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_slo(vector float a, vector unsigned char b)
+vec_slo(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
/* vec_vslo */
static vector signed char __ATTRS_o_ai
-vec_vslo(vector signed char a, vector signed char b)
+vec_vslo(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vslo(vector signed char a, vector unsigned char b)
+vec_vslo(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vslo(vector unsigned char a, vector signed char b)
+vec_vslo(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vslo(vector unsigned char a, vector unsigned char b)
+vec_vslo(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vslo(vector short a, vector signed char b)
+vec_vslo(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vslo(vector short a, vector unsigned char b)
+vec_vslo(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vslo(vector unsigned short a, vector signed char b)
+vec_vslo(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vslo(vector unsigned short a, vector unsigned char b)
+vec_vslo(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vslo(vector pixel a, vector signed char b)
+vec_vslo(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vslo(vector pixel a, vector unsigned char b)
+vec_vslo(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vslo(vector int a, vector signed char b)
+vec_vslo(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vslo(vector int a, vector unsigned char b)
+vec_vslo(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vslo(vector unsigned int a, vector signed char b)
+vec_vslo(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vslo(vector unsigned int a, vector unsigned char b)
+vec_vslo(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vslo(vector float a, vector signed char b)
+vec_vslo(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vslo(vector float a, vector unsigned char b)
+vec_vslo(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
/* vec_splat */
static vector signed char __ATTRS_o_ai
-vec_splat(vector signed char a, unsigned char b)
+vec_splat(vector signed char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_splat(vector unsigned char a, unsigned char b)
+vec_splat(vector unsigned char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector bool char __ATTRS_o_ai
-vec_splat(vector bool char a, unsigned char b)
+vec_splat(vector bool char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector short __ATTRS_o_ai
-vec_splat(vector short a, unsigned char b)
+vec_splat(vector short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector unsigned short __ATTRS_o_ai
-vec_splat(vector unsigned short a, unsigned char b)
+vec_splat(vector unsigned short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector bool short __ATTRS_o_ai
-vec_splat(vector bool short a, unsigned char b)
+vec_splat(vector bool short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector pixel __ATTRS_o_ai
-vec_splat(vector pixel a, unsigned char b)
+vec_splat(vector pixel __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector int __ATTRS_o_ai
-vec_splat(vector int a, unsigned char b)
+vec_splat(vector int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector unsigned int __ATTRS_o_ai
-vec_splat(vector unsigned int a, unsigned char b)
+vec_splat(vector unsigned int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector bool int __ATTRS_o_ai
-vec_splat(vector bool int a, unsigned char b)
+vec_splat(vector bool int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector float __ATTRS_o_ai
-vec_splat(vector float a, unsigned char b)
+vec_splat(vector float __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
/* vec_vspltb */
@@ -5746,21 +5746,21 @@ vec_splat(vector float a, unsigned char b)
#define __builtin_altivec_vspltb vec_vspltb
static vector signed char __ATTRS_o_ai
-vec_vspltb(vector signed char a, unsigned char b)
+vec_vspltb(vector signed char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_vspltb(vector unsigned char a, unsigned char b)
+vec_vspltb(vector unsigned char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector bool char __ATTRS_o_ai
-vec_vspltb(vector bool char a, unsigned char b)
+vec_vspltb(vector bool char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
/* vec_vsplth */
@@ -5768,39 +5768,39 @@ vec_vspltb(vector bool char a, unsigned char b)
#define __builtin_altivec_vsplth vec_vsplth
static vector short __ATTRS_o_ai
-vec_vsplth(vector short a, unsigned char b)
+vec_vsplth(vector short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector unsigned short __ATTRS_o_ai
-vec_vsplth(vector unsigned short a, unsigned char b)
+vec_vsplth(vector unsigned short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector bool short __ATTRS_o_ai
-vec_vsplth(vector bool short a, unsigned char b)
+vec_vsplth(vector bool short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector pixel __ATTRS_o_ai
-vec_vsplth(vector pixel a, unsigned char b)
+vec_vsplth(vector pixel __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
/* vec_vspltw */
@@ -5808,39 +5808,39 @@ vec_vsplth(vector pixel a, unsigned char b)
#define __builtin_altivec_vspltw vec_vspltw
static vector int __ATTRS_o_ai
-vec_vspltw(vector int a, unsigned char b)
+vec_vspltw(vector int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector unsigned int __ATTRS_o_ai
-vec_vspltw(vector unsigned int a, unsigned char b)
+vec_vspltw(vector unsigned int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector bool int __ATTRS_o_ai
-vec_vspltw(vector bool int a, unsigned char b)
+vec_vspltw(vector bool int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector float __ATTRS_o_ai
-vec_vspltw(vector float a, unsigned char b)
+vec_vspltw(vector float __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
/* vec_splat_s8 */
@@ -5849,18 +5849,18 @@ vec_vspltw(vector float a, unsigned char b)
// FIXME: parameter should be treated as 5-bit signed literal
static vector signed char __ATTRS_o_ai
-vec_splat_s8(signed char a)
+vec_splat_s8(signed char __a)
{
- return (vector signed char)(a);
+ return (vector signed char)(__a);
}
/* vec_vspltisb */
// FIXME: parameter should be treated as 5-bit signed literal
static vector signed char __ATTRS_o_ai
-vec_vspltisb(signed char a)
+vec_vspltisb(signed char __a)
{
- return (vector signed char)(a);
+ return (vector signed char)(__a);
}
/* vec_splat_s16 */
@@ -5869,18 +5869,18 @@ vec_vspltisb(signed char a)
// FIXME: parameter should be treated as 5-bit signed literal
static vector short __ATTRS_o_ai
-vec_splat_s16(signed char a)
+vec_splat_s16(signed char __a)
{
- return (vector short)(a);
+ return (vector short)(__a);
}
/* vec_vspltish */
// FIXME: parameter should be treated as 5-bit signed literal
static vector short __ATTRS_o_ai
-vec_vspltish(signed char a)
+vec_vspltish(signed char __a)
{
- return (vector short)(a);
+ return (vector short)(__a);
}
/* vec_splat_s32 */
@@ -5889,83 +5889,83 @@ vec_vspltish(signed char a)
// FIXME: parameter should be treated as 5-bit signed literal
static vector int __ATTRS_o_ai
-vec_splat_s32(signed char a)
+vec_splat_s32(signed char __a)
{
- return (vector int)(a);
+ return (vector int)(__a);
}
/* vec_vspltisw */
// FIXME: parameter should be treated as 5-bit signed literal
static vector int __ATTRS_o_ai
-vec_vspltisw(signed char a)
+vec_vspltisw(signed char __a)
{
- return (vector int)(a);
+ return (vector int)(__a);
}
/* vec_splat_u8 */
// FIXME: parameter should be treated as 5-bit signed literal
static vector unsigned char __ATTRS_o_ai
-vec_splat_u8(unsigned char a)
+vec_splat_u8(unsigned char __a)
{
- return (vector unsigned char)(a);
+ return (vector unsigned char)(__a);
}
/* vec_splat_u16 */
// FIXME: parameter should be treated as 5-bit signed literal
static vector unsigned short __ATTRS_o_ai
-vec_splat_u16(signed char a)
+vec_splat_u16(signed char __a)
{
- return (vector unsigned short)(a);
+ return (vector unsigned short)(__a);
}
/* vec_splat_u32 */
// FIXME: parameter should be treated as 5-bit signed literal
static vector unsigned int __ATTRS_o_ai
-vec_splat_u32(signed char a)
+vec_splat_u32(signed char __a)
{
- return (vector unsigned int)(a);
+ return (vector unsigned int)(__a);
}
/* vec_sr */
static vector signed char __ATTRS_o_ai
-vec_sr(vector signed char a, vector unsigned char b)
+vec_sr(vector signed char __a, vector unsigned char __b)
{
- return a >> (vector signed char)b;
+ return __a >> (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sr(vector unsigned char a, vector unsigned char b)
+vec_sr(vector unsigned char __a, vector unsigned char __b)
{
- return a >> b;
+ return __a >> __b;
}
static vector short __ATTRS_o_ai
-vec_sr(vector short a, vector unsigned short b)
+vec_sr(vector short __a, vector unsigned short __b)
{
- return a >> (vector short)b;
+ return __a >> (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sr(vector unsigned short a, vector unsigned short b)
+vec_sr(vector unsigned short __a, vector unsigned short __b)
{
- return a >> b;
+ return __a >> __b;
}
static vector int __ATTRS_o_ai
-vec_sr(vector int a, vector unsigned int b)
+vec_sr(vector int __a, vector unsigned int __b)
{
- return a >> (vector int)b;
+ return __a >> (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sr(vector unsigned int a, vector unsigned int b)
+vec_sr(vector unsigned int __a, vector unsigned int __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_vsrb */
@@ -5973,15 +5973,15 @@ vec_sr(vector unsigned int a, vector unsigned int b)
#define __builtin_altivec_vsrb vec_vsrb
static vector signed char __ATTRS_o_ai
-vec_vsrb(vector signed char a, vector unsigned char b)
+vec_vsrb(vector signed char __a, vector unsigned char __b)
{
- return a >> (vector signed char)b;
+ return __a >> (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsrb(vector unsigned char a, vector unsigned char b)
+vec_vsrb(vector unsigned char __a, vector unsigned char __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_vsrh */
@@ -5989,15 +5989,15 @@ vec_vsrb(vector unsigned char a, vector unsigned char b)
#define __builtin_altivec_vsrh vec_vsrh
static vector short __ATTRS_o_ai
-vec_vsrh(vector short a, vector unsigned short b)
+vec_vsrh(vector short __a, vector unsigned short __b)
{
- return a >> (vector short)b;
+ return __a >> (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsrh(vector unsigned short a, vector unsigned short b)
+vec_vsrh(vector unsigned short __a, vector unsigned short __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_vsrw */
@@ -6005,1631 +6005,1631 @@ vec_vsrh(vector unsigned short a, vector unsigned short b)
#define __builtin_altivec_vsrw vec_vsrw
static vector int __ATTRS_o_ai
-vec_vsrw(vector int a, vector unsigned int b)
+vec_vsrw(vector int __a, vector unsigned int __b)
{
- return a >> (vector int)b;
+ return __a >> (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsrw(vector unsigned int a, vector unsigned int b)
+vec_vsrw(vector unsigned int __a, vector unsigned int __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_sra */
static vector signed char __ATTRS_o_ai
-vec_sra(vector signed char a, vector unsigned char b)
+vec_sra(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vsrab((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sra(vector unsigned char a, vector unsigned char b)
+vec_sra(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vsrab((vector char)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_sra(vector short a, vector unsigned short b)
+vec_sra(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsrah(a, (vector unsigned short)b);
+ return __builtin_altivec_vsrah(__a, (vector unsigned short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sra(vector unsigned short a, vector unsigned short b)
+vec_sra(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vsrah((vector short)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_sra(vector int a, vector unsigned int b)
+vec_sra(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsraw(a, b);
+ return __builtin_altivec_vsraw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sra(vector unsigned int a, vector unsigned int b)
+vec_sra(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vsraw((vector int)__a, __b);
}
/* vec_vsrab */
static vector signed char __ATTRS_o_ai
-vec_vsrab(vector signed char a, vector unsigned char b)
+vec_vsrab(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vsrab((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsrab(vector unsigned char a, vector unsigned char b)
+vec_vsrab(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vsrab((vector char)__a, __b);
}
/* vec_vsrah */
static vector short __ATTRS_o_ai
-vec_vsrah(vector short a, vector unsigned short b)
+vec_vsrah(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsrah(a, (vector unsigned short)b);
+ return __builtin_altivec_vsrah(__a, (vector unsigned short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsrah(vector unsigned short a, vector unsigned short b)
+vec_vsrah(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vsrah((vector short)__a, __b);
}
/* vec_vsraw */
static vector int __ATTRS_o_ai
-vec_vsraw(vector int a, vector unsigned int b)
+vec_vsraw(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsraw(a, b);
+ return __builtin_altivec_vsraw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsraw(vector unsigned int a, vector unsigned int b)
+vec_vsraw(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vsraw((vector int)__a, __b);
}
/* vec_srl */
static vector signed char __ATTRS_o_ai
-vec_srl(vector signed char a, vector unsigned char b)
+vec_srl(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_srl(vector signed char a, vector unsigned short b)
+vec_srl(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_srl(vector signed char a, vector unsigned int b)
+vec_srl(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_srl(vector unsigned char a, vector unsigned char b)
+vec_srl(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_srl(vector unsigned char a, vector unsigned short b)
+vec_srl(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_srl(vector unsigned char a, vector unsigned int b)
+vec_srl(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_srl(vector bool char a, vector unsigned char b)
+vec_srl(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_srl(vector bool char a, vector unsigned short b)
+vec_srl(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_srl(vector bool char a, vector unsigned int b)
+vec_srl(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_srl(vector short a, vector unsigned char b)
+vec_srl(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_srl(vector short a, vector unsigned short b)
+vec_srl(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_srl(vector short a, vector unsigned int b)
+vec_srl(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_srl(vector unsigned short a, vector unsigned char b)
+vec_srl(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_srl(vector unsigned short a, vector unsigned short b)
+vec_srl(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_srl(vector unsigned short a, vector unsigned int b)
+vec_srl(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_srl(vector bool short a, vector unsigned char b)
+vec_srl(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_srl(vector bool short a, vector unsigned short b)
+vec_srl(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_srl(vector bool short a, vector unsigned int b)
+vec_srl(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_srl(vector pixel a, vector unsigned char b)
+vec_srl(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_srl(vector pixel a, vector unsigned short b)
+vec_srl(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_srl(vector pixel a, vector unsigned int b)
+vec_srl(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_srl(vector int a, vector unsigned char b)
+vec_srl(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_srl(vector int a, vector unsigned short b)
+vec_srl(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_srl(vector int a, vector unsigned int b)
+vec_srl(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_srl(vector unsigned int a, vector unsigned char b)
+vec_srl(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_srl(vector unsigned int a, vector unsigned short b)
+vec_srl(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_srl(vector unsigned int a, vector unsigned int b)
+vec_srl(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_srl(vector bool int a, vector unsigned char b)
+vec_srl(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_srl(vector bool int a, vector unsigned short b)
+vec_srl(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_srl(vector bool int a, vector unsigned int b)
+vec_srl(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
/* vec_vsr */
static vector signed char __ATTRS_o_ai
-vec_vsr(vector signed char a, vector unsigned char b)
+vec_vsr(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsr(vector signed char a, vector unsigned short b)
+vec_vsr(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsr(vector signed char a, vector unsigned int b)
+vec_vsr(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsr(vector unsigned char a, vector unsigned char b)
+vec_vsr(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsr(vector unsigned char a, vector unsigned short b)
+vec_vsr(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsr(vector unsigned char a, vector unsigned int b)
+vec_vsr(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsr(vector bool char a, vector unsigned char b)
+vec_vsr(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsr(vector bool char a, vector unsigned short b)
+vec_vsr(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsr(vector bool char a, vector unsigned int b)
+vec_vsr(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsr(vector short a, vector unsigned char b)
+vec_vsr(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsr(vector short a, vector unsigned short b)
+vec_vsr(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsr(vector short a, vector unsigned int b)
+vec_vsr(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsr(vector unsigned short a, vector unsigned char b)
+vec_vsr(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsr(vector unsigned short a, vector unsigned short b)
+vec_vsr(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsr(vector unsigned short a, vector unsigned int b)
+vec_vsr(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsr(vector bool short a, vector unsigned char b)
+vec_vsr(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsr(vector bool short a, vector unsigned short b)
+vec_vsr(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsr(vector bool short a, vector unsigned int b)
+vec_vsr(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsr(vector pixel a, vector unsigned char b)
+vec_vsr(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsr(vector pixel a, vector unsigned short b)
+vec_vsr(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsr(vector pixel a, vector unsigned int b)
+vec_vsr(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsr(vector int a, vector unsigned char b)
+vec_vsr(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsr(vector int a, vector unsigned short b)
+vec_vsr(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsr(vector int a, vector unsigned int b)
+vec_vsr(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsr(vector unsigned int a, vector unsigned char b)
+vec_vsr(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsr(vector unsigned int a, vector unsigned short b)
+vec_vsr(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsr(vector unsigned int a, vector unsigned int b)
+vec_vsr(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsr(vector bool int a, vector unsigned char b)
+vec_vsr(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsr(vector bool int a, vector unsigned short b)
+vec_vsr(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsr(vector bool int a, vector unsigned int b)
+vec_vsr(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
/* vec_sro */
static vector signed char __ATTRS_o_ai
-vec_sro(vector signed char a, vector signed char b)
+vec_sro(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_sro(vector signed char a, vector unsigned char b)
+vec_sro(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sro(vector unsigned char a, vector signed char b)
+vec_sro(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sro(vector unsigned char a, vector unsigned char b)
+vec_sro(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sro(vector short a, vector signed char b)
+vec_sro(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sro(vector short a, vector unsigned char b)
+vec_sro(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sro(vector unsigned short a, vector signed char b)
+vec_sro(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sro(vector unsigned short a, vector unsigned char b)
+vec_sro(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sro(vector pixel a, vector signed char b)
+vec_sro(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sro(vector pixel a, vector unsigned char b)
+vec_sro(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sro(vector int a, vector signed char b)
+vec_sro(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sro(vector int a, vector unsigned char b)
+vec_sro(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sro(vector unsigned int a, vector signed char b)
+vec_sro(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sro(vector unsigned int a, vector unsigned char b)
+vec_sro(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_sro(vector float a, vector signed char b)
+vec_sro(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_sro(vector float a, vector unsigned char b)
+vec_sro(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
/* vec_vsro */
static vector signed char __ATTRS_o_ai
-vec_vsro(vector signed char a, vector signed char b)
+vec_vsro(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsro(vector signed char a, vector unsigned char b)
+vec_vsro(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsro(vector unsigned char a, vector signed char b)
+vec_vsro(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsro(vector unsigned char a, vector unsigned char b)
+vec_vsro(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsro(vector short a, vector signed char b)
+vec_vsro(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsro(vector short a, vector unsigned char b)
+vec_vsro(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsro(vector unsigned short a, vector signed char b)
+vec_vsro(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsro(vector unsigned short a, vector unsigned char b)
+vec_vsro(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsro(vector pixel a, vector signed char b)
+vec_vsro(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsro(vector pixel a, vector unsigned char b)
+vec_vsro(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsro(vector int a, vector signed char b)
+vec_vsro(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsro(vector int a, vector unsigned char b)
+vec_vsro(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsro(vector unsigned int a, vector signed char b)
+vec_vsro(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsro(vector unsigned int a, vector unsigned char b)
+vec_vsro(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vsro(vector float a, vector signed char b)
+vec_vsro(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vsro(vector float a, vector unsigned char b)
+vec_vsro(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
/* vec_st */
static void __ATTRS_o_ai
-vec_st(vector signed char a, int b, vector signed char *c)
+vec_st(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector signed char a, int b, signed char *c)
+vec_st(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned char a, int b, vector unsigned char *c)
+vec_st(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned char a, int b, unsigned char *c)
+vec_st(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool char a, int b, signed char *c)
+vec_st(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool char a, int b, unsigned char *c)
+vec_st(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool char a, int b, vector bool char *c)
+vec_st(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector short a, int b, vector short *c)
+vec_st(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector short a, int b, short *c)
+vec_st(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned short a, int b, vector unsigned short *c)
+vec_st(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned short a, int b, unsigned short *c)
+vec_st(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool short a, int b, short *c)
+vec_st(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool short a, int b, unsigned short *c)
+vec_st(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool short a, int b, vector bool short *c)
+vec_st(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector pixel a, int b, short *c)
+vec_st(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector pixel a, int b, unsigned short *c)
+vec_st(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector pixel a, int b, vector pixel *c)
+vec_st(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector int a, int b, vector int *c)
+vec_st(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector int a, int b, int *c)
+vec_st(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned int a, int b, vector unsigned int *c)
+vec_st(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned int a, int b, unsigned int *c)
+vec_st(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool int a, int b, int *c)
+vec_st(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool int a, int b, unsigned int *c)
+vec_st(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool int a, int b, vector bool int *c)
+vec_st(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector float a, int b, vector float *c)
+vec_st(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector float a, int b, float *c)
+vec_st(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
/* vec_stvx */
static void __ATTRS_o_ai
-vec_stvx(vector signed char a, int b, vector signed char *c)
+vec_stvx(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector signed char a, int b, signed char *c)
+vec_stvx(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvx(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned char a, int b, unsigned char *c)
+vec_stvx(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool char a, int b, signed char *c)
+vec_stvx(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool char a, int b, unsigned char *c)
+vec_stvx(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool char a, int b, vector bool char *c)
+vec_stvx(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector short a, int b, vector short *c)
+vec_stvx(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector short a, int b, short *c)
+vec_stvx(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvx(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned short a, int b, unsigned short *c)
+vec_stvx(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool short a, int b, short *c)
+vec_stvx(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool short a, int b, unsigned short *c)
+vec_stvx(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool short a, int b, vector bool short *c)
+vec_stvx(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector pixel a, int b, short *c)
+vec_stvx(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector pixel a, int b, unsigned short *c)
+vec_stvx(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector pixel a, int b, vector pixel *c)
+vec_stvx(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector int a, int b, vector int *c)
+vec_stvx(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector int a, int b, int *c)
+vec_stvx(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvx(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned int a, int b, unsigned int *c)
+vec_stvx(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool int a, int b, int *c)
+vec_stvx(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool int a, int b, unsigned int *c)
+vec_stvx(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool int a, int b, vector bool int *c)
+vec_stvx(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector float a, int b, vector float *c)
+vec_stvx(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector float a, int b, float *c)
+vec_stvx(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
/* vec_ste */
static void __ATTRS_o_ai
-vec_ste(vector signed char a, int b, signed char *c)
+vec_ste(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector unsigned char a, int b, unsigned char *c)
+vec_ste(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool char a, int b, signed char *c)
+vec_ste(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool char a, int b, unsigned char *c)
+vec_ste(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector short a, int b, short *c)
+vec_ste(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx(a, b, c);
+ __builtin_altivec_stvehx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector unsigned short a, int b, unsigned short *c)
+vec_ste(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool short a, int b, short *c)
+vec_ste(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool short a, int b, unsigned short *c)
+vec_ste(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector pixel a, int b, short *c)
+vec_ste(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector pixel a, int b, unsigned short *c)
+vec_ste(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector int a, int b, int *c)
+vec_ste(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx(a, b, c);
+ __builtin_altivec_stvewx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector unsigned int a, int b, unsigned int *c)
+vec_ste(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool int a, int b, int *c)
+vec_ste(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool int a, int b, unsigned int *c)
+vec_ste(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector float a, int b, float *c)
+vec_ste(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
/* vec_stvebx */
static void __ATTRS_o_ai
-vec_stvebx(vector signed char a, int b, signed char *c)
+vec_stvebx(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvebx(vector unsigned char a, int b, unsigned char *c)
+vec_stvebx(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvebx(vector bool char a, int b, signed char *c)
+vec_stvebx(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvebx(vector bool char a, int b, unsigned char *c)
+vec_stvebx(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
/* vec_stvehx */
static void __ATTRS_o_ai
-vec_stvehx(vector short a, int b, short *c)
+vec_stvehx(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx(a, b, c);
+ __builtin_altivec_stvehx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector unsigned short a, int b, unsigned short *c)
+vec_stvehx(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector bool short a, int b, short *c)
+vec_stvehx(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector bool short a, int b, unsigned short *c)
+vec_stvehx(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector pixel a, int b, short *c)
+vec_stvehx(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector pixel a, int b, unsigned short *c)
+vec_stvehx(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
/* vec_stvewx */
static void __ATTRS_o_ai
-vec_stvewx(vector int a, int b, int *c)
+vec_stvewx(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx(a, b, c);
+ __builtin_altivec_stvewx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector unsigned int a, int b, unsigned int *c)
+vec_stvewx(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector bool int a, int b, int *c)
+vec_stvewx(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector bool int a, int b, unsigned int *c)
+vec_stvewx(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector float a, int b, float *c)
+vec_stvewx(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
/* vec_stl */
static void __ATTRS_o_ai
-vec_stl(vector signed char a, int b, vector signed char *c)
+vec_stl(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector signed char a, int b, signed char *c)
+vec_stl(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned char a, int b, unsigned char *c)
+vec_stl(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool char a, int b, signed char *c)
+vec_stl(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool char a, int b, unsigned char *c)
+vec_stl(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool char a, int b, vector bool char *c)
+vec_stl(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector short a, int b, vector short *c)
+vec_stl(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector short a, int b, short *c)
+vec_stl(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned short a, int b, unsigned short *c)
+vec_stl(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool short a, int b, short *c)
+vec_stl(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool short a, int b, unsigned short *c)
+vec_stl(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool short a, int b, vector bool short *c)
+vec_stl(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector pixel a, int b, short *c)
+vec_stl(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector pixel a, int b, unsigned short *c)
+vec_stl(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector pixel a, int b, vector pixel *c)
+vec_stl(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector int a, int b, vector int *c)
+vec_stl(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector int a, int b, int *c)
+vec_stl(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned int a, int b, unsigned int *c)
+vec_stl(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool int a, int b, int *c)
+vec_stl(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool int a, int b, unsigned int *c)
+vec_stl(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool int a, int b, vector bool int *c)
+vec_stl(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector float a, int b, vector float *c)
+vec_stl(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector float a, int b, float *c)
+vec_stl(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
/* vec_stvxl */
static void __ATTRS_o_ai
-vec_stvxl(vector signed char a, int b, vector signed char *c)
+vec_stvxl(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector signed char a, int b, signed char *c)
+vec_stvxl(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvxl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned char a, int b, unsigned char *c)
+vec_stvxl(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool char a, int b, signed char *c)
+vec_stvxl(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool char a, int b, unsigned char *c)
+vec_stvxl(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool char a, int b, vector bool char *c)
+vec_stvxl(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector short a, int b, vector short *c)
+vec_stvxl(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector short a, int b, short *c)
+vec_stvxl(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvxl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned short a, int b, unsigned short *c)
+vec_stvxl(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool short a, int b, short *c)
+vec_stvxl(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool short a, int b, unsigned short *c)
+vec_stvxl(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool short a, int b, vector bool short *c)
+vec_stvxl(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector pixel a, int b, short *c)
+vec_stvxl(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector pixel a, int b, unsigned short *c)
+vec_stvxl(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector pixel a, int b, vector pixel *c)
+vec_stvxl(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector int a, int b, vector int *c)
+vec_stvxl(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector int a, int b, int *c)
+vec_stvxl(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvxl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned int a, int b, unsigned int *c)
+vec_stvxl(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool int a, int b, int *c)
+vec_stvxl(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool int a, int b, unsigned int *c)
+vec_stvxl(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool int a, int b, vector bool int *c)
+vec_stvxl(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector float a, int b, vector float *c)
+vec_stvxl(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector float a, int b, float *c)
+vec_stvxl(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
/* vec_sub */
static vector signed char __ATTRS_o_ai
-vec_sub(vector signed char a, vector signed char b)
+vec_sub(vector signed char __a, vector signed char __b)
{
- return a - b;
+ return __a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_sub(vector bool char a, vector signed char b)
+vec_sub(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a - b;
+ return (vector signed char)__a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_sub(vector signed char a, vector bool char b)
+vec_sub(vector signed char __a, vector bool char __b)
{
- return a - (vector signed char)b;
+ return __a - (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sub(vector unsigned char a, vector unsigned char b)
+vec_sub(vector unsigned char __a, vector unsigned char __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sub(vector bool char a, vector unsigned char b)
+vec_sub(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a - b;
+ return (vector unsigned char)__a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sub(vector unsigned char a, vector bool char b)
+vec_sub(vector unsigned char __a, vector bool char __b)
{
- return a - (vector unsigned char)b;
+ return __a - (vector unsigned char)__b;
}
static vector short __ATTRS_o_ai
-vec_sub(vector short a, vector short b)
+vec_sub(vector short __a, vector short __b)
{
- return a - b;
+ return __a - __b;
}
static vector short __ATTRS_o_ai
-vec_sub(vector bool short a, vector short b)
+vec_sub(vector bool short __a, vector short __b)
{
- return (vector short)a - b;
+ return (vector short)__a - __b;
}
static vector short __ATTRS_o_ai
-vec_sub(vector short a, vector bool short b)
+vec_sub(vector short __a, vector bool short __b)
{
- return a - (vector short)b;
+ return __a - (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sub(vector unsigned short a, vector unsigned short b)
+vec_sub(vector unsigned short __a, vector unsigned short __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sub(vector bool short a, vector unsigned short b)
+vec_sub(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a - b;
+ return (vector unsigned short)__a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sub(vector unsigned short a, vector bool short b)
+vec_sub(vector unsigned short __a, vector bool short __b)
{
- return a - (vector unsigned short)b;
+ return __a - (vector unsigned short)__b;
}
static vector int __ATTRS_o_ai
-vec_sub(vector int a, vector int b)
+vec_sub(vector int __a, vector int __b)
{
- return a - b;
+ return __a - __b;
}
static vector int __ATTRS_o_ai
-vec_sub(vector bool int a, vector int b)
+vec_sub(vector bool int __a, vector int __b)
{
- return (vector int)a - b;
+ return (vector int)__a - __b;
}
static vector int __ATTRS_o_ai
-vec_sub(vector int a, vector bool int b)
+vec_sub(vector int __a, vector bool int __b)
{
- return a - (vector int)b;
+ return __a - (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sub(vector unsigned int a, vector unsigned int b)
+vec_sub(vector unsigned int __a, vector unsigned int __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sub(vector bool int a, vector unsigned int b)
+vec_sub(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a - b;
+ return (vector unsigned int)__a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sub(vector unsigned int a, vector bool int b)
+vec_sub(vector unsigned int __a, vector bool int __b)
{
- return a - (vector unsigned int)b;
+ return __a - (vector unsigned int)__b;
}
static vector float __ATTRS_o_ai
-vec_sub(vector float a, vector float b)
+vec_sub(vector float __a, vector float __b)
{
- return a - b;
+ return __a - __b;
}
/* vec_vsububm */
@@ -7637,39 +7637,39 @@ vec_sub(vector float a, vector float b)
#define __builtin_altivec_vsububm vec_vsububm
static vector signed char __ATTRS_o_ai
-vec_vsububm(vector signed char a, vector signed char b)
+vec_vsububm(vector signed char __a, vector signed char __b)
{
- return a - b;
+ return __a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_vsububm(vector bool char a, vector signed char b)
+vec_vsububm(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a - b;
+ return (vector signed char)__a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_vsububm(vector signed char a, vector bool char b)
+vec_vsububm(vector signed char __a, vector bool char __b)
{
- return a - (vector signed char)b;
+ return __a - (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububm(vector unsigned char a, vector unsigned char b)
+vec_vsububm(vector unsigned char __a, vector unsigned char __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububm(vector bool char a, vector unsigned char b)
+vec_vsububm(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a - b;
+ return (vector unsigned char)__a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububm(vector unsigned char a, vector bool char b)
+vec_vsububm(vector unsigned char __a, vector bool char __b)
{
- return a - (vector unsigned char)b;
+ return __a - (vector unsigned char)__b;
}
/* vec_vsubuhm */
@@ -7677,39 +7677,39 @@ vec_vsububm(vector unsigned char a, vector bool char b)
#define __builtin_altivec_vsubuhm vec_vsubuhm
static vector short __ATTRS_o_ai
-vec_vsubuhm(vector short a, vector short b)
+vec_vsubuhm(vector short __a, vector short __b)
{
- return a - b;
+ return __a - __b;
}
static vector short __ATTRS_o_ai
-vec_vsubuhm(vector bool short a, vector short b)
+vec_vsubuhm(vector bool short __a, vector short __b)
{
- return (vector short)a - b;
+ return (vector short)__a - __b;
}
static vector short __ATTRS_o_ai
-vec_vsubuhm(vector short a, vector bool short b)
+vec_vsubuhm(vector short __a, vector bool short __b)
{
- return a - (vector short)b;
+ return __a - (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhm(vector unsigned short a, vector unsigned short b)
+vec_vsubuhm(vector unsigned short __a, vector unsigned short __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhm(vector bool short a, vector unsigned short b)
+vec_vsubuhm(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a - b;
+ return (vector unsigned short)__a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhm(vector unsigned short a, vector bool short b)
+vec_vsubuhm(vector unsigned short __a, vector bool short __b)
{
- return a - (vector unsigned short)b;
+ return __a - (vector unsigned short)__b;
}
/* vec_vsubuwm */
@@ -7717,39 +7717,39 @@ vec_vsubuhm(vector unsigned short a, vector bool short b)
#define __builtin_altivec_vsubuwm vec_vsubuwm
static vector int __ATTRS_o_ai
-vec_vsubuwm(vector int a, vector int b)
+vec_vsubuwm(vector int __a, vector int __b)
{
- return a - b;
+ return __a - __b;
}
static vector int __ATTRS_o_ai
-vec_vsubuwm(vector bool int a, vector int b)
+vec_vsubuwm(vector bool int __a, vector int __b)
{
- return (vector int)a - b;
+ return (vector int)__a - __b;
}
static vector int __ATTRS_o_ai
-vec_vsubuwm(vector int a, vector bool int b)
+vec_vsubuwm(vector int __a, vector bool int __b)
{
- return a - (vector int)b;
+ return __a - (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuwm(vector unsigned int a, vector unsigned int b)
+vec_vsubuwm(vector unsigned int __a, vector unsigned int __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuwm(vector bool int a, vector unsigned int b)
+vec_vsubuwm(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a - b;
+ return (vector unsigned int)__a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuwm(vector unsigned int a, vector bool int b)
+vec_vsubuwm(vector unsigned int __a, vector bool int __b)
{
- return a - (vector unsigned int)b;
+ return __a - (vector unsigned int)__b;
}
/* vec_vsubfp */
@@ -7757,479 +7757,479 @@ vec_vsubuwm(vector unsigned int a, vector bool int b)
#define __builtin_altivec_vsubfp vec_vsubfp
static vector float __attribute__((__always_inline__))
-vec_vsubfp(vector float a, vector float b)
+vec_vsubfp(vector float __a, vector float __b)
{
- return a - b;
+ return __a - __b;
}
/* vec_subc */
static vector unsigned int __attribute__((__always_inline__))
-vec_subc(vector unsigned int a, vector unsigned int b)
+vec_subc(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubcuw(a, b);
+ return __builtin_altivec_vsubcuw(__a, __b);
}
/* vec_vsubcuw */
static vector unsigned int __attribute__((__always_inline__))
-vec_vsubcuw(vector unsigned int a, vector unsigned int b)
+vec_vsubcuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubcuw(a, b);
+ return __builtin_altivec_vsubcuw(__a, __b);
}
/* vec_subs */
static vector signed char __ATTRS_o_ai
-vec_subs(vector signed char a, vector signed char b)
+vec_subs(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs(a, b);
+ return __builtin_altivec_vsubsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_subs(vector bool char a, vector signed char b)
+vec_subs(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs((vector signed char)a, b);
+ return __builtin_altivec_vsubsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_subs(vector signed char a, vector bool char b)
+vec_subs(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vsubsbs(a, (vector signed char)b);
+ return __builtin_altivec_vsubsbs(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_subs(vector unsigned char a, vector unsigned char b)
+vec_subs(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs(a, b);
+ return __builtin_altivec_vsububs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_subs(vector bool char a, vector unsigned char b)
+vec_subs(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs((vector unsigned char)a, b);
+ return __builtin_altivec_vsububs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_subs(vector unsigned char a, vector bool char b)
+vec_subs(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vsububs(a, (vector unsigned char)b);
+ return __builtin_altivec_vsububs(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_subs(vector short a, vector short b)
+vec_subs(vector short __a, vector short __b)
{
- return __builtin_altivec_vsubshs(a, b);
+ return __builtin_altivec_vsubshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_subs(vector bool short a, vector short b)
+vec_subs(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vsubshs((vector short)a, b);
+ return __builtin_altivec_vsubshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_subs(vector short a, vector bool short b)
+vec_subs(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vsubshs(a, (vector short)b);
+ return __builtin_altivec_vsubshs(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_subs(vector unsigned short a, vector unsigned short b)
+vec_subs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs(a, b);
+ return __builtin_altivec_vsubuhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_subs(vector bool short a, vector unsigned short b)
+vec_subs(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs((vector unsigned short)a, b);
+ return __builtin_altivec_vsubuhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_subs(vector unsigned short a, vector bool short b)
+vec_subs(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vsubuhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vsubuhs(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_subs(vector int a, vector int b)
+vec_subs(vector int __a, vector int __b)
{
- return __builtin_altivec_vsubsws(a, b);
+ return __builtin_altivec_vsubsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_subs(vector bool int a, vector int b)
+vec_subs(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vsubsws((vector int)a, b);
+ return __builtin_altivec_vsubsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_subs(vector int a, vector bool int b)
+vec_subs(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vsubsws(a, (vector int)b);
+ return __builtin_altivec_vsubsws(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_subs(vector unsigned int a, vector unsigned int b)
+vec_subs(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws(a, b);
+ return __builtin_altivec_vsubuws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_subs(vector bool int a, vector unsigned int b)
+vec_subs(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws((vector unsigned int)a, b);
+ return __builtin_altivec_vsubuws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_subs(vector unsigned int a, vector bool int b)
+vec_subs(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vsubuws(a, (vector unsigned int)b);
+ return __builtin_altivec_vsubuws(__a, (vector unsigned int)__b);
}
/* vec_vsubsbs */
static vector signed char __ATTRS_o_ai
-vec_vsubsbs(vector signed char a, vector signed char b)
+vec_vsubsbs(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs(a, b);
+ return __builtin_altivec_vsubsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vsubsbs(vector bool char a, vector signed char b)
+vec_vsubsbs(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs((vector signed char)a, b);
+ return __builtin_altivec_vsubsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vsubsbs(vector signed char a, vector bool char b)
+vec_vsubsbs(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vsubsbs(a, (vector signed char)b);
+ return __builtin_altivec_vsubsbs(__a, (vector signed char)__b);
}
/* vec_vsububs */
static vector unsigned char __ATTRS_o_ai
-vec_vsububs(vector unsigned char a, vector unsigned char b)
+vec_vsububs(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs(a, b);
+ return __builtin_altivec_vsububs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububs(vector bool char a, vector unsigned char b)
+vec_vsububs(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs((vector unsigned char)a, b);
+ return __builtin_altivec_vsububs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububs(vector unsigned char a, vector bool char b)
+vec_vsububs(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vsububs(a, (vector unsigned char)b);
+ return __builtin_altivec_vsububs(__a, (vector unsigned char)__b);
}
/* vec_vsubshs */
static vector short __ATTRS_o_ai
-vec_vsubshs(vector short a, vector short b)
+vec_vsubshs(vector short __a, vector short __b)
{
- return __builtin_altivec_vsubshs(a, b);
+ return __builtin_altivec_vsubshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vsubshs(vector bool short a, vector short b)
+vec_vsubshs(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vsubshs((vector short)a, b);
+ return __builtin_altivec_vsubshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vsubshs(vector short a, vector bool short b)
+vec_vsubshs(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vsubshs(a, (vector short)b);
+ return __builtin_altivec_vsubshs(__a, (vector short)__b);
}
/* vec_vsubuhs */
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhs(vector unsigned short a, vector unsigned short b)
+vec_vsubuhs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs(a, b);
+ return __builtin_altivec_vsubuhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhs(vector bool short a, vector unsigned short b)
+vec_vsubuhs(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs((vector unsigned short)a, b);
+ return __builtin_altivec_vsubuhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhs(vector unsigned short a, vector bool short b)
+vec_vsubuhs(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vsubuhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vsubuhs(__a, (vector unsigned short)__b);
}
/* vec_vsubsws */
static vector int __ATTRS_o_ai
-vec_vsubsws(vector int a, vector int b)
+vec_vsubsws(vector int __a, vector int __b)
{
- return __builtin_altivec_vsubsws(a, b);
+ return __builtin_altivec_vsubsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vsubsws(vector bool int a, vector int b)
+vec_vsubsws(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vsubsws((vector int)a, b);
+ return __builtin_altivec_vsubsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vsubsws(vector int a, vector bool int b)
+vec_vsubsws(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vsubsws(a, (vector int)b);
+ return __builtin_altivec_vsubsws(__a, (vector int)__b);
}
/* vec_vsubuws */
static vector unsigned int __ATTRS_o_ai
-vec_vsubuws(vector unsigned int a, vector unsigned int b)
+vec_vsubuws(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws(a, b);
+ return __builtin_altivec_vsubuws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuws(vector bool int a, vector unsigned int b)
+vec_vsubuws(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws((vector unsigned int)a, b);
+ return __builtin_altivec_vsubuws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuws(vector unsigned int a, vector bool int b)
+vec_vsubuws(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vsubuws(a, (vector unsigned int)b);
+ return __builtin_altivec_vsubuws(__a, (vector unsigned int)__b);
}
/* vec_sum4s */
static vector int __ATTRS_o_ai
-vec_sum4s(vector signed char a, vector int b)
+vec_sum4s(vector signed char __a, vector int __b)
{
- return __builtin_altivec_vsum4sbs(a, b);
+ return __builtin_altivec_vsum4sbs(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sum4s(vector unsigned char a, vector unsigned int b)
+vec_sum4s(vector unsigned char __a, vector unsigned int __b)
{
- return __builtin_altivec_vsum4ubs(a, b);
+ return __builtin_altivec_vsum4ubs(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_sum4s(vector signed short a, vector int b)
+vec_sum4s(vector signed short __a, vector int __b)
{
- return __builtin_altivec_vsum4shs(a, b);
+ return __builtin_altivec_vsum4shs(__a, __b);
}
/* vec_vsum4sbs */
static vector int __attribute__((__always_inline__))
-vec_vsum4sbs(vector signed char a, vector int b)
+vec_vsum4sbs(vector signed char __a, vector int __b)
{
- return __builtin_altivec_vsum4sbs(a, b);
+ return __builtin_altivec_vsum4sbs(__a, __b);
}
/* vec_vsum4ubs */
static vector unsigned int __attribute__((__always_inline__))
-vec_vsum4ubs(vector unsigned char a, vector unsigned int b)
+vec_vsum4ubs(vector unsigned char __a, vector unsigned int __b)
{
- return __builtin_altivec_vsum4ubs(a, b);
+ return __builtin_altivec_vsum4ubs(__a, __b);
}
/* vec_vsum4shs */
static vector int __attribute__((__always_inline__))
-vec_vsum4shs(vector signed short a, vector int b)
+vec_vsum4shs(vector signed short __a, vector int __b)
{
- return __builtin_altivec_vsum4shs(a, b);
+ return __builtin_altivec_vsum4shs(__a, __b);
}
/* vec_sum2s */
static vector signed int __attribute__((__always_inline__))
-vec_sum2s(vector int a, vector int b)
+vec_sum2s(vector int __a, vector int __b)
{
- return __builtin_altivec_vsum2sws(a, b);
+ return __builtin_altivec_vsum2sws(__a, __b);
}
/* vec_vsum2sws */
static vector signed int __attribute__((__always_inline__))
-vec_vsum2sws(vector int a, vector int b)
+vec_vsum2sws(vector int __a, vector int __b)
{
- return __builtin_altivec_vsum2sws(a, b);
+ return __builtin_altivec_vsum2sws(__a, __b);
}
/* vec_sums */
static vector signed int __attribute__((__always_inline__))
-vec_sums(vector signed int a, vector signed int b)
+vec_sums(vector signed int __a, vector signed int __b)
{
- return __builtin_altivec_vsumsws(a, b);
+ return __builtin_altivec_vsumsws(__a, __b);
}
/* vec_vsumsws */
static vector signed int __attribute__((__always_inline__))
-vec_vsumsws(vector signed int a, vector signed int b)
+vec_vsumsws(vector signed int __a, vector signed int __b)
{
- return __builtin_altivec_vsumsws(a, b);
+ return __builtin_altivec_vsumsws(__a, __b);
}
/* vec_trunc */
static vector float __attribute__((__always_inline__))
-vec_trunc(vector float a)
+vec_trunc(vector float __a)
{
- return __builtin_altivec_vrfiz(a);
+ return __builtin_altivec_vrfiz(__a);
}
/* vec_vrfiz */
static vector float __attribute__((__always_inline__))
-vec_vrfiz(vector float a)
+vec_vrfiz(vector float __a)
{
- return __builtin_altivec_vrfiz(a);
+ return __builtin_altivec_vrfiz(__a);
}
/* vec_unpackh */
static vector short __ATTRS_o_ai
-vec_unpackh(vector signed char a)
+vec_unpackh(vector signed char __a)
{
- return __builtin_altivec_vupkhsb((vector char)a);
+ return __builtin_altivec_vupkhsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_unpackh(vector bool char a)
+vec_unpackh(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupkhsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
}
static vector int __ATTRS_o_ai
-vec_unpackh(vector short a)
+vec_unpackh(vector short __a)
{
- return __builtin_altivec_vupkhsh(a);
+ return __builtin_altivec_vupkhsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_unpackh(vector bool short a)
+vec_unpackh(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_unpackh(vector pixel a)
+vec_unpackh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)__a);
}
/* vec_vupkhsb */
static vector short __ATTRS_o_ai
-vec_vupkhsb(vector signed char a)
+vec_vupkhsb(vector signed char __a)
{
- return __builtin_altivec_vupkhsb((vector char)a);
+ return __builtin_altivec_vupkhsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_vupkhsb(vector bool char a)
+vec_vupkhsb(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupkhsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
}
/* vec_vupkhsh */
static vector int __ATTRS_o_ai
-vec_vupkhsh(vector short a)
+vec_vupkhsh(vector short __a)
{
- return __builtin_altivec_vupkhsh(a);
+ return __builtin_altivec_vupkhsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_vupkhsh(vector bool short a)
+vec_vupkhsh(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_vupkhsh(vector pixel a)
+vec_vupkhsh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)__a);
}
/* vec_unpackl */
static vector short __ATTRS_o_ai
-vec_unpackl(vector signed char a)
+vec_unpackl(vector signed char __a)
{
- return __builtin_altivec_vupklsb((vector char)a);
+ return __builtin_altivec_vupklsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_unpackl(vector bool char a)
+vec_unpackl(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupklsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
}
static vector int __ATTRS_o_ai
-vec_unpackl(vector short a)
+vec_unpackl(vector short __a)
{
- return __builtin_altivec_vupklsh(a);
+ return __builtin_altivec_vupklsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_unpackl(vector bool short a)
+vec_unpackl(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_unpackl(vector pixel a)
+vec_unpackl(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupklsh((vector short)__a);
}
/* vec_vupklsb */
static vector short __ATTRS_o_ai
-vec_vupklsb(vector signed char a)
+vec_vupklsb(vector signed char __a)
{
- return __builtin_altivec_vupklsb((vector char)a);
+ return __builtin_altivec_vupklsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_vupklsb(vector bool char a)
+vec_vupklsb(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupklsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
}
/* vec_vupklsh */
static vector int __ATTRS_o_ai
-vec_vupklsh(vector short a)
+vec_vupklsh(vector short __a)
{
- return __builtin_altivec_vupklsh(a);
+ return __builtin_altivec_vupklsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_vupklsh(vector bool short a)
+vec_vupklsh(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_vupklsh(vector pixel a)
+vec_vupklsh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupklsh((vector short)__a);
}
/* vec_xor */
@@ -8237,299 +8237,299 @@ vec_vupklsh(vector pixel a)
#define __builtin_altivec_vxor vec_xor
static vector signed char __ATTRS_o_ai
-vec_xor(vector signed char a, vector signed char b)
+vec_xor(vector signed char __a, vector signed char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_xor(vector bool char a, vector signed char b)
+vec_xor(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a ^ b;
+ return (vector signed char)__a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_xor(vector signed char a, vector bool char b)
+vec_xor(vector signed char __a, vector bool char __b)
{
- return a ^ (vector signed char)b;
+ return __a ^ (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_xor(vector unsigned char a, vector unsigned char b)
+vec_xor(vector unsigned char __a, vector unsigned char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_xor(vector bool char a, vector unsigned char b)
+vec_xor(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a ^ b;
+ return (vector unsigned char)__a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_xor(vector unsigned char a, vector bool char b)
+vec_xor(vector unsigned char __a, vector bool char __b)
{
- return a ^ (vector unsigned char)b;
+ return __a ^ (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_xor(vector bool char a, vector bool char b)
+vec_xor(vector bool char __a, vector bool char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_xor(vector short a, vector short b)
+vec_xor(vector short __a, vector short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_xor(vector bool short a, vector short b)
+vec_xor(vector bool short __a, vector short __b)
{
- return (vector short)a ^ b;
+ return (vector short)__a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_xor(vector short a, vector bool short b)
+vec_xor(vector short __a, vector bool short __b)
{
- return a ^ (vector short)b;
+ return __a ^ (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_xor(vector unsigned short a, vector unsigned short b)
+vec_xor(vector unsigned short __a, vector unsigned short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_xor(vector bool short a, vector unsigned short b)
+vec_xor(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a ^ b;
+ return (vector unsigned short)__a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_xor(vector unsigned short a, vector bool short b)
+vec_xor(vector unsigned short __a, vector bool short __b)
{
- return a ^ (vector unsigned short)b;
+ return __a ^ (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_xor(vector bool short a, vector bool short b)
+vec_xor(vector bool short __a, vector bool short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_xor(vector int a, vector int b)
+vec_xor(vector int __a, vector int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_xor(vector bool int a, vector int b)
+vec_xor(vector bool int __a, vector int __b)
{
- return (vector int)a ^ b;
+ return (vector int)__a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_xor(vector int a, vector bool int b)
+vec_xor(vector int __a, vector bool int __b)
{
- return a ^ (vector int)b;
+ return __a ^ (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_xor(vector unsigned int a, vector unsigned int b)
+vec_xor(vector unsigned int __a, vector unsigned int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_xor(vector bool int a, vector unsigned int b)
+vec_xor(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a ^ b;
+ return (vector unsigned int)__a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_xor(vector unsigned int a, vector bool int b)
+vec_xor(vector unsigned int __a, vector bool int __b)
{
- return a ^ (vector unsigned int)b;
+ return __a ^ (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_xor(vector bool int a, vector bool int b)
+vec_xor(vector bool int __a, vector bool int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector float __ATTRS_o_ai
-vec_xor(vector float a, vector float b)
+vec_xor(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_xor(vector bool int a, vector float b)
+vec_xor(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_xor(vector float a, vector bool int b)
+vec_xor(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vxor */
static vector signed char __ATTRS_o_ai
-vec_vxor(vector signed char a, vector signed char b)
+vec_vxor(vector signed char __a, vector signed char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_vxor(vector bool char a, vector signed char b)
+vec_vxor(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a ^ b;
+ return (vector signed char)__a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_vxor(vector signed char a, vector bool char b)
+vec_vxor(vector signed char __a, vector bool char __b)
{
- return a ^ (vector signed char)b;
+ return __a ^ (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vxor(vector unsigned char a, vector unsigned char b)
+vec_vxor(vector unsigned char __a, vector unsigned char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vxor(vector bool char a, vector unsigned char b)
+vec_vxor(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a ^ b;
+ return (vector unsigned char)__a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vxor(vector unsigned char a, vector bool char b)
+vec_vxor(vector unsigned char __a, vector bool char __b)
{
- return a ^ (vector unsigned char)b;
+ return __a ^ (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vxor(vector bool char a, vector bool char b)
+vec_vxor(vector bool char __a, vector bool char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_vxor(vector short a, vector short b)
+vec_vxor(vector short __a, vector short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_vxor(vector bool short a, vector short b)
+vec_vxor(vector bool short __a, vector short __b)
{
- return (vector short)a ^ b;
+ return (vector short)__a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_vxor(vector short a, vector bool short b)
+vec_vxor(vector short __a, vector bool short __b)
{
- return a ^ (vector short)b;
+ return __a ^ (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vxor(vector unsigned short a, vector unsigned short b)
+vec_vxor(vector unsigned short __a, vector unsigned short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vxor(vector bool short a, vector unsigned short b)
+vec_vxor(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a ^ b;
+ return (vector unsigned short)__a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vxor(vector unsigned short a, vector bool short b)
+vec_vxor(vector unsigned short __a, vector bool short __b)
{
- return a ^ (vector unsigned short)b;
+ return __a ^ (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vxor(vector bool short a, vector bool short b)
+vec_vxor(vector bool short __a, vector bool short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_vxor(vector int a, vector int b)
+vec_vxor(vector int __a, vector int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_vxor(vector bool int a, vector int b)
+vec_vxor(vector bool int __a, vector int __b)
{
- return (vector int)a ^ b;
+ return (vector int)__a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_vxor(vector int a, vector bool int b)
+vec_vxor(vector int __a, vector bool int __b)
{
- return a ^ (vector int)b;
+ return __a ^ (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vxor(vector unsigned int a, vector unsigned int b)
+vec_vxor(vector unsigned int __a, vector unsigned int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vxor(vector bool int a, vector unsigned int b)
+vec_vxor(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a ^ b;
+ return (vector unsigned int)__a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vxor(vector unsigned int a, vector bool int b)
+vec_vxor(vector unsigned int __a, vector bool int __b)
{
- return a ^ (vector unsigned int)b;
+ return __a ^ (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vxor(vector bool int a, vector bool int b)
+vec_vxor(vector bool int __a, vector bool int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector float __ATTRS_o_ai
-vec_vxor(vector float a, vector float b)
+vec_vxor(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vxor(vector bool int a, vector float b)
+vec_vxor(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vxor(vector float a, vector bool int b)
+vec_vxor(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
/* ------------------------ extensions for CBEA ----------------------------- */
@@ -8537,1402 +8537,1402 @@ vec_vxor(vector float a, vector bool int b)
/* vec_extract */
static signed char __ATTRS_o_ai
-vec_extract(vector signed char a, int b)
+vec_extract(vector signed char __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static unsigned char __ATTRS_o_ai
-vec_extract(vector unsigned char a, int b)
+vec_extract(vector unsigned char __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static short __ATTRS_o_ai
-vec_extract(vector short a, int b)
+vec_extract(vector short __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static unsigned short __ATTRS_o_ai
-vec_extract(vector unsigned short a, int b)
+vec_extract(vector unsigned short __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static int __ATTRS_o_ai
-vec_extract(vector int a, int b)
+vec_extract(vector int __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static unsigned int __ATTRS_o_ai
-vec_extract(vector unsigned int a, int b)
+vec_extract(vector unsigned int __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static float __ATTRS_o_ai
-vec_extract(vector float a, int b)
+vec_extract(vector float __a, int __b)
{
- return a[b];
+ return __a[__b];
}
/* vec_insert */
static vector signed char __ATTRS_o_ai
-vec_insert(signed char a, vector signed char b, int c)
+vec_insert(signed char __a, vector signed char __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_insert(unsigned char a, vector unsigned char b, int c)
+vec_insert(unsigned char __a, vector unsigned char __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector short __ATTRS_o_ai
-vec_insert(short a, vector short b, int c)
+vec_insert(short __a, vector short __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_insert(unsigned short a, vector unsigned short b, int c)
+vec_insert(unsigned short __a, vector unsigned short __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector int __ATTRS_o_ai
-vec_insert(int a, vector int b, int c)
+vec_insert(int __a, vector int __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_insert(unsigned int a, vector unsigned int b, int c)
+vec_insert(unsigned int __a, vector unsigned int __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector float __ATTRS_o_ai
-vec_insert(float a, vector float b, int c)
+vec_insert(float __a, vector float __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
/* vec_lvlx */
static vector signed char __ATTRS_o_ai
-vec_lvlx(int a, const signed char *b)
+vec_lvlx(int __a, const signed char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvlx(int a, const vector signed char *b)
+vec_lvlx(int __a, const vector signed char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlx(int a, const unsigned char *b)
+vec_lvlx(int __a, const unsigned char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlx(int a, const vector unsigned char *b)
+vec_lvlx(int __a, const vector unsigned char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvlx(int a, const vector bool char *b)
+vec_lvlx(int __a, const vector bool char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector bool char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvlx(int a, const short *b)
+vec_lvlx(int __a, const short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvlx(int a, const vector short *b)
+vec_lvlx(int __a, const vector short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlx(int a, const unsigned short *b)
+vec_lvlx(int __a, const unsigned short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlx(int a, const vector unsigned short *b)
+vec_lvlx(int __a, const vector unsigned short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvlx(int a, const vector bool short *b)
+vec_lvlx(int __a, const vector bool short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector bool short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvlx(int a, const vector pixel *b)
+vec_lvlx(int __a, const vector pixel *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector pixel)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvlx(int a, const int *b)
+vec_lvlx(int __a, const int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvlx(int a, const vector int *b)
+vec_lvlx(int __a, const vector int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlx(int a, const unsigned int *b)
+vec_lvlx(int __a, const unsigned int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlx(int a, const vector unsigned int *b)
+vec_lvlx(int __a, const vector unsigned int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvlx(int a, const vector bool int *b)
+vec_lvlx(int __a, const vector bool int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector bool int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvlx(int a, const float *b)
+vec_lvlx(int __a, const float *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector float)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvlx(int a, const vector float *b)
+vec_lvlx(int __a, const vector float *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector float)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_lvlxl */
static vector signed char __ATTRS_o_ai
-vec_lvlxl(int a, const signed char *b)
+vec_lvlxl(int __a, const signed char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvlxl(int a, const vector signed char *b)
+vec_lvlxl(int __a, const vector signed char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlxl(int a, const unsigned char *b)
+vec_lvlxl(int __a, const unsigned char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlxl(int a, const vector unsigned char *b)
+vec_lvlxl(int __a, const vector unsigned char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvlxl(int a, const vector bool char *b)
+vec_lvlxl(int __a, const vector bool char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector bool char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvlxl(int a, const short *b)
+vec_lvlxl(int __a, const short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvlxl(int a, const vector short *b)
+vec_lvlxl(int __a, const vector short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlxl(int a, const unsigned short *b)
+vec_lvlxl(int __a, const unsigned short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlxl(int a, const vector unsigned short *b)
+vec_lvlxl(int __a, const vector unsigned short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvlxl(int a, const vector bool short *b)
+vec_lvlxl(int __a, const vector bool short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector bool short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvlxl(int a, const vector pixel *b)
+vec_lvlxl(int __a, const vector pixel *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector pixel)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvlxl(int a, const int *b)
+vec_lvlxl(int __a, const int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvlxl(int a, const vector int *b)
+vec_lvlxl(int __a, const vector int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlxl(int a, const unsigned int *b)
+vec_lvlxl(int __a, const unsigned int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlxl(int a, const vector unsigned int *b)
+vec_lvlxl(int __a, const vector unsigned int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvlxl(int a, const vector bool int *b)
+vec_lvlxl(int __a, const vector bool int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector bool int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvlxl(int a, const float *b)
+vec_lvlxl(int __a, const float *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector float)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvlxl(int a, vector float *b)
+vec_lvlxl(int __a, vector float *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector float)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_lvrx */
static vector signed char __ATTRS_o_ai
-vec_lvrx(int a, const signed char *b)
+vec_lvrx(int __a, const signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvrx(int a, const vector signed char *b)
+vec_lvrx(int __a, const vector signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrx(int a, const unsigned char *b)
+vec_lvrx(int __a, const unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrx(int a, const vector unsigned char *b)
+vec_lvrx(int __a, const vector unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvrx(int a, const vector bool char *b)
+vec_lvrx(int __a, const vector bool char *__b)
{
return vec_perm((vector bool char)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvrx(int a, const short *b)
+vec_lvrx(int __a, const short *__b)
{
return vec_perm((vector short)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvrx(int a, const vector short *b)
+vec_lvrx(int __a, const vector short *__b)
{
return vec_perm((vector short)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrx(int a, const unsigned short *b)
+vec_lvrx(int __a, const unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrx(int a, const vector unsigned short *b)
+vec_lvrx(int __a, const vector unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvrx(int a, const vector bool short *b)
+vec_lvrx(int __a, const vector bool short *__b)
{
return vec_perm((vector bool short)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvrx(int a, const vector pixel *b)
+vec_lvrx(int __a, const vector pixel *__b)
{
return vec_perm((vector pixel)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvrx(int a, const int *b)
+vec_lvrx(int __a, const int *__b)
{
return vec_perm((vector int)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvrx(int a, const vector int *b)
+vec_lvrx(int __a, const vector int *__b)
{
return vec_perm((vector int)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrx(int a, const unsigned int *b)
+vec_lvrx(int __a, const unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrx(int a, const vector unsigned int *b)
+vec_lvrx(int __a, const vector unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvrx(int a, const vector bool int *b)
+vec_lvrx(int __a, const vector bool int *__b)
{
return vec_perm((vector bool int)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvrx(int a, const float *b)
+vec_lvrx(int __a, const float *__b)
{
return vec_perm((vector float)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvrx(int a, const vector float *b)
+vec_lvrx(int __a, const vector float *__b)
{
return vec_perm((vector float)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_lvrxl */
static vector signed char __ATTRS_o_ai
-vec_lvrxl(int a, const signed char *b)
+vec_lvrxl(int __a, const signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvrxl(int a, const vector signed char *b)
+vec_lvrxl(int __a, const vector signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrxl(int a, const unsigned char *b)
+vec_lvrxl(int __a, const unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrxl(int a, const vector unsigned char *b)
+vec_lvrxl(int __a, const vector unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvrxl(int a, const vector bool char *b)
+vec_lvrxl(int __a, const vector bool char *__b)
{
return vec_perm((vector bool char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvrxl(int a, const short *b)
+vec_lvrxl(int __a, const short *__b)
{
return vec_perm((vector short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvrxl(int a, const vector short *b)
+vec_lvrxl(int __a, const vector short *__b)
{
return vec_perm((vector short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrxl(int a, const unsigned short *b)
+vec_lvrxl(int __a, const unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrxl(int a, const vector unsigned short *b)
+vec_lvrxl(int __a, const vector unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvrxl(int a, const vector bool short *b)
+vec_lvrxl(int __a, const vector bool short *__b)
{
return vec_perm((vector bool short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvrxl(int a, const vector pixel *b)
+vec_lvrxl(int __a, const vector pixel *__b)
{
return vec_perm((vector pixel)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvrxl(int a, const int *b)
+vec_lvrxl(int __a, const int *__b)
{
return vec_perm((vector int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvrxl(int a, const vector int *b)
+vec_lvrxl(int __a, const vector int *__b)
{
return vec_perm((vector int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrxl(int a, const unsigned int *b)
+vec_lvrxl(int __a, const unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrxl(int a, const vector unsigned int *b)
+vec_lvrxl(int __a, const vector unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvrxl(int a, const vector bool int *b)
+vec_lvrxl(int __a, const vector bool int *__b)
{
return vec_perm((vector bool int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvrxl(int a, const float *b)
+vec_lvrxl(int __a, const float *__b)
{
return vec_perm((vector float)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvrxl(int a, const vector float *b)
+vec_lvrxl(int __a, const vector float *__b)
{
return vec_perm((vector float)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_stvlx */
static void __ATTRS_o_ai
-vec_stvlx(vector signed char a, int b, signed char *c)
+vec_stvlx(vector signed char __a, int __b, signed char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector signed char a, int b, vector signed char *c)
+vec_stvlx(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned char a, int b, unsigned char *c)
+vec_stvlx(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvlx(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector bool char a, int b, vector bool char *c)
+vec_stvlx(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector short a, int b, short *c)
+vec_stvlx(vector short __a, int __b, short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector short a, int b, vector short *c)
+vec_stvlx(vector short __a, int __b, vector short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned short a, int b, unsigned short *c)
+vec_stvlx(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvlx(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector bool short a, int b, vector bool short *c)
+vec_stvlx(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector pixel a, int b, vector pixel *c)
+vec_stvlx(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector int a, int b, int *c)
+vec_stvlx(vector int __a, int __b, int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector int a, int b, vector int *c)
+vec_stvlx(vector int __a, int __b, vector int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned int a, int b, unsigned int *c)
+vec_stvlx(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvlx(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector bool int a, int b, vector bool int *c)
+vec_stvlx(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector float a, int b, vector float *c)
+vec_stvlx(vector float __a, int __b, vector float *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_stvlxl */
static void __ATTRS_o_ai
-vec_stvlxl(vector signed char a, int b, signed char *c)
+vec_stvlxl(vector signed char __a, int __b, signed char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector signed char a, int b, vector signed char *c)
+vec_stvlxl(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned char a, int b, unsigned char *c)
+vec_stvlxl(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvlxl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector bool char a, int b, vector bool char *c)
+vec_stvlxl(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector short a, int b, short *c)
+vec_stvlxl(vector short __a, int __b, short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector short a, int b, vector short *c)
+vec_stvlxl(vector short __a, int __b, vector short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned short a, int b, unsigned short *c)
+vec_stvlxl(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvlxl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector bool short a, int b, vector bool short *c)
+vec_stvlxl(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector pixel a, int b, vector pixel *c)
+vec_stvlxl(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector int a, int b, int *c)
+vec_stvlxl(vector int __a, int __b, int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector int a, int b, vector int *c)
+vec_stvlxl(vector int __a, int __b, vector int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned int a, int b, unsigned int *c)
+vec_stvlxl(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvlxl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector bool int a, int b, vector bool int *c)
+vec_stvlxl(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector float a, int b, vector float *c)
+vec_stvlxl(vector float __a, int __b, vector float *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_stvrx */
static void __ATTRS_o_ai
-vec_stvrx(vector signed char a, int b, signed char *c)
+vec_stvrx(vector signed char __a, int __b, signed char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector signed char a, int b, vector signed char *c)
+vec_stvrx(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned char a, int b, unsigned char *c)
+vec_stvrx(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvrx(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector bool char a, int b, vector bool char *c)
+vec_stvrx(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector short a, int b, short *c)
+vec_stvrx(vector short __a, int __b, short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector short a, int b, vector short *c)
+vec_stvrx(vector short __a, int __b, vector short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned short a, int b, unsigned short *c)
+vec_stvrx(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvrx(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector bool short a, int b, vector bool short *c)
+vec_stvrx(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector pixel a, int b, vector pixel *c)
+vec_stvrx(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector int a, int b, int *c)
+vec_stvrx(vector int __a, int __b, int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector int a, int b, vector int *c)
+vec_stvrx(vector int __a, int __b, vector int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned int a, int b, unsigned int *c)
+vec_stvrx(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvrx(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector bool int a, int b, vector bool int *c)
+vec_stvrx(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector float a, int b, vector float *c)
+vec_stvrx(vector float __a, int __b, vector float *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_stvrxl */
static void __ATTRS_o_ai
-vec_stvrxl(vector signed char a, int b, signed char *c)
+vec_stvrxl(vector signed char __a, int __b, signed char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector signed char a, int b, vector signed char *c)
+vec_stvrxl(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned char a, int b, unsigned char *c)
+vec_stvrxl(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvrxl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector bool char a, int b, vector bool char *c)
+vec_stvrxl(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector short a, int b, short *c)
+vec_stvrxl(vector short __a, int __b, short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector short a, int b, vector short *c)
+vec_stvrxl(vector short __a, int __b, vector short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned short a, int b, unsigned short *c)
+vec_stvrxl(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvrxl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector bool short a, int b, vector bool short *c)
+vec_stvrxl(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector pixel a, int b, vector pixel *c)
+vec_stvrxl(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector int a, int b, int *c)
+vec_stvrxl(vector int __a, int __b, int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector int a, int b, vector int *c)
+vec_stvrxl(vector int __a, int __b, vector int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned int a, int b, unsigned int *c)
+vec_stvrxl(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvrxl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector bool int a, int b, vector bool int *c)
+vec_stvrxl(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector float a, int b, vector float *c)
+vec_stvrxl(vector float __a, int __b, vector float *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_promote */
static vector signed char __ATTRS_o_ai
-vec_promote(signed char a, int b)
+vec_promote(signed char __a, int __b)
{
- vector signed char res = (vector signed char)(0);
- res[b] = a;
- return res;
+ vector signed char __res = (vector signed char)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector unsigned char __ATTRS_o_ai
-vec_promote(unsigned char a, int b)
+vec_promote(unsigned char __a, int __b)
{
- vector unsigned char res = (vector unsigned char)(0);
- res[b] = a;
- return res;
+ vector unsigned char __res = (vector unsigned char)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector short __ATTRS_o_ai
-vec_promote(short a, int b)
+vec_promote(short __a, int __b)
{
- vector short res = (vector short)(0);
- res[b] = a;
- return res;
+ vector short __res = (vector short)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector unsigned short __ATTRS_o_ai
-vec_promote(unsigned short a, int b)
+vec_promote(unsigned short __a, int __b)
{
- vector unsigned short res = (vector unsigned short)(0);
- res[b] = a;
- return res;
+ vector unsigned short __res = (vector unsigned short)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector int __ATTRS_o_ai
-vec_promote(int a, int b)
+vec_promote(int __a, int __b)
{
- vector int res = (vector int)(0);
- res[b] = a;
- return res;
+ vector int __res = (vector int)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector unsigned int __ATTRS_o_ai
-vec_promote(unsigned int a, int b)
+vec_promote(unsigned int __a, int __b)
{
- vector unsigned int res = (vector unsigned int)(0);
- res[b] = a;
- return res;
+ vector unsigned int __res = (vector unsigned int)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector float __ATTRS_o_ai
-vec_promote(float a, int b)
+vec_promote(float __a, int __b)
{
- vector float res = (vector float)(0);
- res[b] = a;
- return res;
+ vector float __res = (vector float)(0);
+ __res[__b] = __a;
+ return __res;
}
/* vec_splats */
static vector signed char __ATTRS_o_ai
-vec_splats(signed char a)
+vec_splats(signed char __a)
{
- return (vector signed char)(a);
+ return (vector signed char)(__a);
}
static vector unsigned char __ATTRS_o_ai
-vec_splats(unsigned char a)
+vec_splats(unsigned char __a)
{
- return (vector unsigned char)(a);
+ return (vector unsigned char)(__a);
}
static vector short __ATTRS_o_ai
-vec_splats(short a)
+vec_splats(short __a)
{
- return (vector short)(a);
+ return (vector short)(__a);
}
static vector unsigned short __ATTRS_o_ai
-vec_splats(unsigned short a)
+vec_splats(unsigned short __a)
{
- return (vector unsigned short)(a);
+ return (vector unsigned short)(__a);
}
static vector int __ATTRS_o_ai
-vec_splats(int a)
+vec_splats(int __a)
{
- return (vector int)(a);
+ return (vector int)(__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_splats(unsigned int a)
+vec_splats(unsigned int __a)
{
- return (vector unsigned int)(a);
+ return (vector unsigned int)(__a);
}
static vector float __ATTRS_o_ai
-vec_splats(float a)
+vec_splats(float __a)
{
- return (vector float)(a);
+ return (vector float)(__a);
}
/* ----------------------------- predicates --------------------------------- */
@@ -9940,1915 +9940,1915 @@ vec_splats(float a)
/* vec_all_eq */
static int __ATTRS_o_ai
-vec_all_eq(vector signed char a, vector signed char b)
+vec_all_eq(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector signed char a, vector bool char b)
+vec_all_eq(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned char a, vector unsigned char b)
+vec_all_eq(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned char a, vector bool char b)
+vec_all_eq(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool char a, vector signed char b)
+vec_all_eq(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool char a, vector unsigned char b)
+vec_all_eq(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool char a, vector bool char b)
+vec_all_eq(vector bool char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector short a, vector short b)
+vec_all_eq(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector short a, vector bool short b)
+vec_all_eq(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned short a, vector unsigned short b)
+vec_all_eq(vector unsigned short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned short a, vector bool short b)
+vec_all_eq(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool short a, vector short b)
+vec_all_eq(vector bool short __a, vector short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool short a, vector unsigned short b)
+vec_all_eq(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool short a, vector bool short b)
+vec_all_eq(vector bool short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector pixel a, vector pixel b)
+vec_all_eq(vector pixel __a, vector pixel __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector int a, vector int b)
+vec_all_eq(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector int a, vector bool int b)
+vec_all_eq(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned int a, vector unsigned int b)
+vec_all_eq(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned int a, vector bool int b)
+vec_all_eq(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool int a, vector int b)
+vec_all_eq(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool int a, vector unsigned int b)
+vec_all_eq(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool int a, vector bool int b)
+vec_all_eq(vector bool int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector float a, vector float b)
+vec_all_eq(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, __a, __b);
}
/* vec_all_ge */
static int __ATTRS_o_ai
-vec_all_ge(vector signed char a, vector signed char b)
+vec_all_ge(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector signed char a, vector bool char b)
+vec_all_ge(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned char a, vector unsigned char b)
+vec_all_ge(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned char a, vector bool char b)
+vec_all_ge(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool char a, vector signed char b)
+vec_all_ge(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool char a, vector unsigned char b)
+vec_all_ge(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, (vector unsigned char)a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool char a, vector bool char b)
+vec_all_ge(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector short a, vector short b)
+vec_all_ge(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector short a, vector bool short b)
+vec_all_ge(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned short a, vector unsigned short b)
+vec_all_ge(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned short a, vector bool short b)
+vec_all_ge(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool short a, vector short b)
+vec_all_ge(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool short a, vector unsigned short b)
+vec_all_ge(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, (vector unsigned short)a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool short a, vector bool short b)
+vec_all_ge(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector int a, vector int b)
+vec_all_ge(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector int a, vector bool int b)
+vec_all_ge(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned int a, vector unsigned int b)
+vec_all_ge(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned int a, vector bool int b)
+vec_all_ge(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool int a, vector int b)
+vec_all_ge(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool int a, vector unsigned int b)
+vec_all_ge(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool int a, vector bool int b)
+vec_all_ge(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector float a, vector float b)
+vec_all_ge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT, __a, __b);
}
/* vec_all_gt */
static int __ATTRS_o_ai
-vec_all_gt(vector signed char a, vector signed char b)
+vec_all_gt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector signed char a, vector bool char b)
+vec_all_gt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned char a, vector unsigned char b)
+vec_all_gt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned char a, vector bool char b)
+vec_all_gt(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, (vector unsigned char)b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool char a, vector signed char b)
+vec_all_gt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool char a, vector unsigned char b)
+vec_all_gt(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool char a, vector bool char b)
+vec_all_gt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector short a, vector short b)
+vec_all_gt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector short a, vector bool short b)
+vec_all_gt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned short a, vector unsigned short b)
+vec_all_gt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned short a, vector bool short b)
+vec_all_gt(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, (vector unsigned short)b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool short a, vector short b)
+vec_all_gt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool short a, vector unsigned short b)
+vec_all_gt(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool short a, vector bool short b)
+vec_all_gt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector int a, vector int b)
+vec_all_gt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector int a, vector bool int b)
+vec_all_gt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned int a, vector unsigned int b)
+vec_all_gt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned int a, vector bool int b)
+vec_all_gt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool int a, vector int b)
+vec_all_gt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool int a, vector unsigned int b)
+vec_all_gt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool int a, vector bool int b)
+vec_all_gt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector float a, vector float b)
+vec_all_gt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, __a, __b);
}
/* vec_all_in */
static int __attribute__((__always_inline__))
-vec_all_in(vector float a, vector float b)
+vec_all_in(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ, __a, __b);
}
/* vec_all_le */
static int __ATTRS_o_ai
-vec_all_le(vector signed char a, vector signed char b)
+vec_all_le(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector signed char a, vector bool char b)
+vec_all_le(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned char a, vector unsigned char b)
+vec_all_le(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned char a, vector bool char b)
+vec_all_le(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, (vector unsigned char)b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool char a, vector signed char b)
+vec_all_le(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool char a, vector unsigned char b)
+vec_all_le(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool char a, vector bool char b)
+vec_all_le(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector short a, vector short b)
+vec_all_le(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector short a, vector bool short b)
+vec_all_le(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned short a, vector unsigned short b)
+vec_all_le(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned short a, vector bool short b)
+vec_all_le(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, (vector unsigned short)b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool short a, vector short b)
+vec_all_le(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool short a, vector unsigned short b)
+vec_all_le(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool short a, vector bool short b)
+vec_all_le(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector int a, vector int b)
+vec_all_le(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector int a, vector bool int b)
+vec_all_le(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned int a, vector unsigned int b)
+vec_all_le(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned int a, vector bool int b)
+vec_all_le(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool int a, vector int b)
+vec_all_le(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool int a, vector unsigned int b)
+vec_all_le(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool int a, vector bool int b)
+vec_all_le(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector float a, vector float b)
+vec_all_le(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT, __b, __a);
}
/* vec_all_lt */
static int __ATTRS_o_ai
-vec_all_lt(vector signed char a, vector signed char b)
+vec_all_lt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector signed char a, vector bool char b)
+vec_all_lt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned char a, vector unsigned char b)
+vec_all_lt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned char a, vector bool char b)
+vec_all_lt(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool char a, vector signed char b)
+vec_all_lt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool char a, vector unsigned char b)
+vec_all_lt(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, (vector unsigned char)a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool char a, vector bool char b)
+vec_all_lt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector short a, vector short b)
+vec_all_lt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector short a, vector bool short b)
+vec_all_lt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned short a, vector unsigned short b)
+vec_all_lt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned short a, vector bool short b)
+vec_all_lt(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool short a, vector short b)
+vec_all_lt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool short a, vector unsigned short b)
+vec_all_lt(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, (vector unsigned short)a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool short a, vector bool short b)
+vec_all_lt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector int a, vector int b)
+vec_all_lt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector int a, vector bool int b)
+vec_all_lt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned int a, vector unsigned int b)
+vec_all_lt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned int a, vector bool int b)
+vec_all_lt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool int a, vector int b)
+vec_all_lt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool int a, vector unsigned int b)
+vec_all_lt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool int a, vector bool int b)
+vec_all_lt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector float a, vector float b)
+vec_all_lt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, __b, __a);
}
/* vec_all_nan */
static int __attribute__((__always_inline__))
-vec_all_nan(vector float a)
+vec_all_nan(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __a);
}
/* vec_all_ne */
static int __ATTRS_o_ai
-vec_all_ne(vector signed char a, vector signed char b)
+vec_all_ne(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector signed char a, vector bool char b)
+vec_all_ne(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned char a, vector unsigned char b)
+vec_all_ne(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned char a, vector bool char b)
+vec_all_ne(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool char a, vector signed char b)
+vec_all_ne(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool char a, vector unsigned char b)
+vec_all_ne(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool char a, vector bool char b)
+vec_all_ne(vector bool char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector short a, vector short b)
+vec_all_ne(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector short a, vector bool short b)
+vec_all_ne(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned short a, vector unsigned short b)
+vec_all_ne(vector unsigned short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned short a, vector bool short b)
+vec_all_ne(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool short a, vector short b)
+vec_all_ne(vector bool short __a, vector short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool short a, vector unsigned short b)
+vec_all_ne(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool short a, vector bool short b)
+vec_all_ne(vector bool short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector pixel a, vector pixel b)
+vec_all_ne(vector pixel __a, vector pixel __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector int a, vector int b)
+vec_all_ne(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector int a, vector bool int b)
+vec_all_ne(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned int a, vector unsigned int b)
+vec_all_ne(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned int a, vector bool int b)
+vec_all_ne(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool int a, vector int b)
+vec_all_ne(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool int a, vector unsigned int b)
+vec_all_ne(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool int a, vector bool int b)
+vec_all_ne(vector bool int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector float a, vector float b)
+vec_all_ne(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __b);
}
/* vec_all_nge */
static int __attribute__((__always_inline__))
-vec_all_nge(vector float a, vector float b)
+vec_all_nge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, __a, __b);
}
/* vec_all_ngt */
static int __attribute__((__always_inline__))
-vec_all_ngt(vector float a, vector float b)
+vec_all_ngt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, __a, __b);
}
/* vec_all_nle */
static int __attribute__((__always_inline__))
-vec_all_nle(vector float a, vector float b)
+vec_all_nle(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, __b, __a);
}
/* vec_all_nlt */
static int __attribute__((__always_inline__))
-vec_all_nlt(vector float a, vector float b)
+vec_all_nlt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, __b, __a);
}
/* vec_all_numeric */
static int __attribute__((__always_inline__))
-vec_all_numeric(vector float a)
+vec_all_numeric(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, __a, __a);
}
/* vec_any_eq */
static int __ATTRS_o_ai
-vec_any_eq(vector signed char a, vector signed char b)
+vec_any_eq(vector signed char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector signed char a, vector bool char b)
+vec_any_eq(vector signed char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned char a, vector unsigned char b)
+vec_any_eq(vector unsigned char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned char a, vector bool char b)
+vec_any_eq(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool char a, vector signed char b)
+vec_any_eq(vector bool char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool char a, vector unsigned char b)
+vec_any_eq(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool char a, vector bool char b)
+vec_any_eq(vector bool char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector short a, vector short b)
+vec_any_eq(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector short a, vector bool short b)
+vec_any_eq(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned short a, vector unsigned short b)
+vec_any_eq(vector unsigned short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned short a, vector bool short b)
+vec_any_eq(vector unsigned short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool short a, vector short b)
+vec_any_eq(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool short a, vector unsigned short b)
+vec_any_eq(vector bool short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool short a, vector bool short b)
+vec_any_eq(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector pixel a, vector pixel b)
+vec_any_eq(vector pixel __a, vector pixel __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector int a, vector int b)
+vec_any_eq(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector int a, vector bool int b)
+vec_any_eq(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned int a, vector unsigned int b)
+vec_any_eq(vector unsigned int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned int a, vector bool int b)
+vec_any_eq(vector unsigned int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool int a, vector int b)
+vec_any_eq(vector bool int __a, vector int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool int a, vector unsigned int b)
+vec_any_eq(vector bool int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool int a, vector bool int b)
+vec_any_eq(vector bool int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector float a, vector float b)
+vec_any_eq(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, __a, __b);
}
/* vec_any_ge */
static int __ATTRS_o_ai
-vec_any_ge(vector signed char a, vector signed char b)
+vec_any_ge(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector signed char a, vector bool char b)
+vec_any_ge(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned char a, vector unsigned char b)
+vec_any_ge(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned char a, vector bool char b)
+vec_any_ge(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool char a, vector signed char b)
+vec_any_ge(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool char a, vector unsigned char b)
+vec_any_ge(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, (vector unsigned char)a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool char a, vector bool char b)
+vec_any_ge(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector short a, vector short b)
+vec_any_ge(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector short a, vector bool short b)
+vec_any_ge(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned short a, vector unsigned short b)
+vec_any_ge(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned short a, vector bool short b)
+vec_any_ge(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)b, a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool short a, vector short b)
+vec_any_ge(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool short a, vector unsigned short b)
+vec_any_ge(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, (vector unsigned short)a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool short a, vector bool short b)
+vec_any_ge(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector int a, vector int b)
+vec_any_ge(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector int a, vector bool int b)
+vec_any_ge(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned int a, vector unsigned int b)
+vec_any_ge(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned int a, vector bool int b)
+vec_any_ge(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool int a, vector int b)
+vec_any_ge(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool int a, vector unsigned int b)
+vec_any_ge(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool int a, vector bool int b)
+vec_any_ge(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector float a, vector float b)
+vec_any_ge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, __a, __b);
}
/* vec_any_gt */
static int __ATTRS_o_ai
-vec_any_gt(vector signed char a, vector signed char b)
+vec_any_gt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector signed char a, vector bool char b)
+vec_any_gt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned char a, vector unsigned char b)
+vec_any_gt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned char a, vector bool char b)
+vec_any_gt(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, (vector unsigned char)b);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool char a, vector signed char b)
+vec_any_gt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool char a, vector unsigned char b)
+vec_any_gt(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)a, b);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool char a, vector bool char b)
+vec_any_gt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector short a, vector short b)
+vec_any_gt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector short a, vector bool short b)
+vec_any_gt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned short a, vector unsigned short b)
+vec_any_gt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned short a, vector bool short b)
+vec_any_gt(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, (vector unsigned short)b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool short a, vector short b)
+vec_any_gt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool short a, vector unsigned short b)
+vec_any_gt(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)a, b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool short a, vector bool short b)
+vec_any_gt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector int a, vector int b)
+vec_any_gt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector int a, vector bool int b)
+vec_any_gt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned int a, vector unsigned int b)
+vec_any_gt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned int a, vector bool int b)
+vec_any_gt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool int a, vector int b)
+vec_any_gt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool int a, vector unsigned int b)
+vec_any_gt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool int a, vector bool int b)
+vec_any_gt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector float a, vector float b)
+vec_any_gt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, __a, __b);
}
/* vec_any_le */
static int __ATTRS_o_ai
-vec_any_le(vector signed char a, vector signed char b)
+vec_any_le(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector signed char a, vector bool char b)
+vec_any_le(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned char a, vector unsigned char b)
+vec_any_le(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned char a, vector bool char b)
+vec_any_le(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, (vector unsigned char)b);
+ __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool char a, vector signed char b)
+vec_any_le(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool char a, vector unsigned char b)
+vec_any_le(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)a, b);
+ __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool char a, vector bool char b)
+vec_any_le(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector short a, vector short b)
+vec_any_le(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector short a, vector bool short b)
+vec_any_le(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned short a, vector unsigned short b)
+vec_any_le(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned short a, vector bool short b)
+vec_any_le(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, (vector unsigned short)b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool short a, vector short b)
+vec_any_le(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool short a, vector unsigned short b)
+vec_any_le(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)a, b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool short a, vector bool short b)
+vec_any_le(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector int a, vector int b)
+vec_any_le(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector int a, vector bool int b)
+vec_any_le(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned int a, vector unsigned int b)
+vec_any_le(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned int a, vector bool int b)
+vec_any_le(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool int a, vector int b)
+vec_any_le(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool int a, vector unsigned int b)
+vec_any_le(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool int a, vector bool int b)
+vec_any_le(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector float a, vector float b)
+vec_any_le(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, __b, __a);
}
/* vec_any_lt */
static int __ATTRS_o_ai
-vec_any_lt(vector signed char a, vector signed char b)
+vec_any_lt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector signed char a, vector bool char b)
+vec_any_lt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned char a, vector unsigned char b)
+vec_any_lt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned char a, vector bool char b)
+vec_any_lt(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)b, a);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool char a, vector signed char b)
+vec_any_lt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool char a, vector unsigned char b)
+vec_any_lt(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, (vector unsigned char)a);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool char a, vector bool char b)
+vec_any_lt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector short a, vector short b)
+vec_any_lt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector short a, vector bool short b)
+vec_any_lt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned short a, vector unsigned short b)
+vec_any_lt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned short a, vector bool short b)
+vec_any_lt(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)b, a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool short a, vector short b)
+vec_any_lt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool short a, vector unsigned short b)
+vec_any_lt(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, (vector unsigned short)a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool short a, vector bool short b)
+vec_any_lt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector int a, vector int b)
+vec_any_lt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector int a, vector bool int b)
+vec_any_lt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned int a, vector unsigned int b)
+vec_any_lt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned int a, vector bool int b)
+vec_any_lt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool int a, vector int b)
+vec_any_lt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool int a, vector unsigned int b)
+vec_any_lt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool int a, vector bool int b)
+vec_any_lt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector float a, vector float b)
+vec_any_lt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, __b, __a);
}
/* vec_any_nan */
static int __attribute__((__always_inline__))
-vec_any_nan(vector float a)
+vec_any_nan(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, __a, __a);
}
/* vec_any_ne */
static int __ATTRS_o_ai
-vec_any_ne(vector signed char a, vector signed char b)
+vec_any_ne(vector signed char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector signed char a, vector bool char b)
+vec_any_ne(vector signed char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned char a, vector unsigned char b)
+vec_any_ne(vector unsigned char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned char a, vector bool char b)
+vec_any_ne(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool char a, vector signed char b)
+vec_any_ne(vector bool char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool char a, vector unsigned char b)
+vec_any_ne(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool char a, vector bool char b)
+vec_any_ne(vector bool char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector short a, vector short b)
+vec_any_ne(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector short a, vector bool short b)
+vec_any_ne(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned short a, vector unsigned short b)
+vec_any_ne(vector unsigned short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned short a, vector bool short b)
+vec_any_ne(vector unsigned short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool short a, vector short b)
+vec_any_ne(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool short a, vector unsigned short b)
+vec_any_ne(vector bool short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool short a, vector bool short b)
+vec_any_ne(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector pixel a, vector pixel b)
+vec_any_ne(vector pixel __a, vector pixel __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector int a, vector int b)
+vec_any_ne(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector int a, vector bool int b)
+vec_any_ne(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned int a, vector unsigned int b)
+vec_any_ne(vector unsigned int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned int a, vector bool int b)
+vec_any_ne(vector unsigned int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool int a, vector int b)
+vec_any_ne(vector bool int __a, vector int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool int a, vector unsigned int b)
+vec_any_ne(vector bool int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool int a, vector bool int b)
+vec_any_ne(vector bool int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector float a, vector float b)
+vec_any_ne(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, __a, __b);
}
/* vec_any_nge */
static int __attribute__((__always_inline__))
-vec_any_nge(vector float a, vector float b)
+vec_any_nge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, __a, __b);
}
/* vec_any_ngt */
static int __attribute__((__always_inline__))
-vec_any_ngt(vector float a, vector float b)
+vec_any_ngt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, __a, __b);
}
/* vec_any_nle */
static int __attribute__((__always_inline__))
-vec_any_nle(vector float a, vector float b)
+vec_any_nle(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, __b, __a);
}
/* vec_any_nlt */
static int __attribute__((__always_inline__))
-vec_any_nlt(vector float a, vector float b)
+vec_any_nlt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, __b, __a);
}
/* vec_any_numeric */
static int __attribute__((__always_inline__))
-vec_any_numeric(vector float a)
+vec_any_numeric(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, __a, __a);
}
/* vec_any_out */
static int __attribute__((__always_inline__))
-vec_any_out(vector float a, vector float b)
+vec_any_out(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, __a, __b);
}
#undef __ATTRS_o_ai
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 2c53aedffd1d..63b1efc10537 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -29,39 +29,39 @@
#define _mm256_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw256((X), (Y), (M))
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_abs_epi8(__m256i a)
+_mm256_abs_epi8(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsb256((__v32qi)a);
+ return (__m256i)__builtin_ia32_pabsb256((__v32qi)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_abs_epi16(__m256i a)
+_mm256_abs_epi16(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsw256((__v16hi)a);
+ return (__m256i)__builtin_ia32_pabsw256((__v16hi)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_abs_epi32(__m256i a)
+_mm256_abs_epi32(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsd256((__v8si)a);
+ return (__m256i)__builtin_ia32_pabsd256((__v8si)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_packs_epi16(__m256i a, __m256i b)
+_mm256_packs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_packsswb256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_packsswb256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_packs_epi32(__m256i a, __m256i b)
+_mm256_packs_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_packssdw256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_packssdw256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_packus_epi16(__m256i a, __m256i b)
+_mm256_packus_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_packuswb256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_packuswb256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -71,51 +71,51 @@ _mm256_packus_epi32(__m256i __V1, __m256i __V2)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi8(__m256i a, __m256i b)
+_mm256_add_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a + (__v32qi)b);
+ return (__m256i)((__v32qi)__a + (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi16(__m256i a, __m256i b)
+_mm256_add_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a + (__v16hi)b);
+ return (__m256i)((__v16hi)__a + (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi32(__m256i a, __m256i b)
+_mm256_add_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a + (__v8si)b);
+ return (__m256i)((__v8si)__a + (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi64(__m256i a, __m256i b)
+_mm256_add_epi64(__m256i __a, __m256i __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epi8(__m256i a, __m256i b)
+_mm256_adds_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_paddsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epi16(__m256i a, __m256i b)
+_mm256_adds_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_paddsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epu8(__m256i a, __m256i b)
+_mm256_adds_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddusb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_paddusb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epu16(__m256i a, __m256i b)
+_mm256_adds_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddusw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_paddusw256((__v16hi)__a, (__v16hi)__b);
}
#define _mm256_alignr_epi8(a, b, n) __extension__ ({ \
@@ -124,27 +124,27 @@ _mm256_adds_epu16(__m256i a, __m256i b)
(__m256i)__builtin_ia32_palignr256((__v32qi)__a, (__v32qi)__b, (n)); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_and_si256(__m256i a, __m256i b)
+_mm256_and_si256(__m256i __a, __m256i __b)
{
- return a & b;
+ return __a & __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_andnot_si256(__m256i a, __m256i b)
+_mm256_andnot_si256(__m256i __a, __m256i __b)
{
- return ~a & b;
+ return ~__a & __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_avg_epu8(__m256i a, __m256i b)
+_mm256_avg_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pavgb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pavgb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_avg_epu16(__m256i a, __m256i b)
+_mm256_avg_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pavgw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pavgw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -160,177 +160,177 @@ _mm256_blendv_epi8(__m256i __V1, __m256i __V2, __m256i __M)
(__m256i)__builtin_ia32_pblendw256((__v16hi)__V1, (__v16hi)__V2, (M)); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi8(__m256i a, __m256i b)
+_mm256_cmpeq_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a == (__v32qi)b);
+ return (__m256i)((__v32qi)__a == (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi16(__m256i a, __m256i b)
+_mm256_cmpeq_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a == (__v16hi)b);
+ return (__m256i)((__v16hi)__a == (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi32(__m256i a, __m256i b)
+_mm256_cmpeq_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a == (__v8si)b);
+ return (__m256i)((__v8si)__a == (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi64(__m256i a, __m256i b)
+_mm256_cmpeq_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)(a == b);
+ return (__m256i)(__a == __b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi8(__m256i a, __m256i b)
+_mm256_cmpgt_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a > (__v32qi)b);
+ return (__m256i)((__v32qi)__a > (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi16(__m256i a, __m256i b)
+_mm256_cmpgt_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a > (__v16hi)b);
+ return (__m256i)((__v16hi)__a > (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi32(__m256i a, __m256i b)
+_mm256_cmpgt_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a > (__v8si)b);
+ return (__m256i)((__v8si)__a > (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi64(__m256i a, __m256i b)
+_mm256_cmpgt_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)(a > b);
+ return (__m256i)(__a > __b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_epi16(__m256i a, __m256i b)
+_mm256_hadd_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phaddw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phaddw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_epi32(__m256i a, __m256i b)
+_mm256_hadd_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phaddd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_phaddd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hadds_epi16(__m256i a, __m256i b)
+_mm256_hadds_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phaddsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phaddsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_epi16(__m256i a, __m256i b)
+_mm256_hsub_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phsubw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phsubw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_epi32(__m256i a, __m256i b)
+_mm256_hsub_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phsubd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_phsubd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hsubs_epi16(__m256i a, __m256i b)
+_mm256_hsubs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phsubsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phsubsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_maddubs_epi16(__m256i a, __m256i b)
+_mm256_maddubs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaddubsw256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pmaddubsw256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_madd_epi16(__m256i a, __m256i b)
+_mm256_madd_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaddwd256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmaddwd256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epi8(__m256i a, __m256i b)
+_mm256_max_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epi16(__m256i a, __m256i b)
+_mm256_max_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epi32(__m256i a, __m256i b)
+_mm256_max_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pmaxsd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epu8(__m256i a, __m256i b)
+_mm256_max_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxub256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pmaxub256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epu16(__m256i a, __m256i b)
+_mm256_max_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epu32(__m256i a, __m256i b)
+_mm256_max_epu32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxud256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pmaxud256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epi8(__m256i a, __m256i b)
+_mm256_min_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pminsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epi16(__m256i a, __m256i b)
+_mm256_min_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pminsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epi32(__m256i a, __m256i b)
+_mm256_min_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pminsd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epu8(__m256i a, __m256i b)
+_mm256_min_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminub256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pminub256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epu16(__m256i a, __m256i b)
+_mm256_min_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epu32(__m256i a, __m256i b)
+_mm256_min_epu32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminud256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pminud256((__v8si)__a, (__v8si)__b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm256_movemask_epi8(__m256i a)
+_mm256_movemask_epi8(__m256i __a)
{
- return __builtin_ia32_pmovmskb256((__v32qi)a);
+ return __builtin_ia32_pmovmskb256((__v32qi)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -406,63 +406,63 @@ _mm256_cvtepu32_epi64(__m128i __V)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_epi32(__m256i a, __m256i b)
+_mm256_mul_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmuldq256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pmuldq256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mulhrs_epi16(__m256i a, __m256i b)
+_mm256_mulhrs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmulhrsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmulhrsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mulhi_epu16(__m256i a, __m256i b)
+_mm256_mulhi_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmulhuw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmulhuw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mulhi_epi16(__m256i a, __m256i b)
+_mm256_mulhi_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmulhw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmulhw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mullo_epi16(__m256i a, __m256i b)
+_mm256_mullo_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a * (__v16hi)b);
+ return (__m256i)((__v16hi)__a * (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mullo_epi32 (__m256i a, __m256i b)
+_mm256_mullo_epi32 (__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a * (__v8si)b);
+ return (__m256i)((__v8si)__a * (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_epu32(__m256i a, __m256i b)
+_mm256_mul_epu32(__m256i __a, __m256i __b)
{
- return __builtin_ia32_pmuludq256((__v8si)a, (__v8si)b);
+ return __builtin_ia32_pmuludq256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_or_si256(__m256i a, __m256i b)
+_mm256_or_si256(__m256i __a, __m256i __b)
{
- return a | b;
+ return __a | __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sad_epu8(__m256i a, __m256i b)
+_mm256_sad_epu8(__m256i __a, __m256i __b)
{
- return __builtin_ia32_psadbw256((__v32qi)a, (__v32qi)b);
+ return __builtin_ia32_psadbw256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_shuffle_epi8(__m256i a, __m256i b)
+_mm256_shuffle_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pshufb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pshufb256((__v32qi)__a, (__v32qi)__b);
}
#define _mm256_shuffle_epi32(a, imm) __extension__ ({ \
@@ -502,21 +502,21 @@ _mm256_shuffle_epi8(__m256i a, __m256i b)
12, 13, 14, 15); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sign_epi8(__m256i a, __m256i b)
+_mm256_sign_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psignb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_psignb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sign_epi16(__m256i a, __m256i b)
+_mm256_sign_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psignw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_psignw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sign_epi32(__m256i a, __m256i b)
+_mm256_sign_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psignd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_psignd256((__v8si)__a, (__v8si)__b);
}
#define _mm256_slli_si256(a, count) __extension__ ({ \
@@ -524,63 +524,63 @@ _mm256_sign_epi32(__m256i a, __m256i b)
(__m256i)__builtin_ia32_pslldqi256(__a, (count)*8); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_slli_epi16(__m256i a, int count)
+_mm256_slli_epi16(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psllwi256((__v16hi)a, count);
+ return (__m256i)__builtin_ia32_psllwi256((__v16hi)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sll_epi16(__m256i a, __m128i count)
+_mm256_sll_epi16(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psllw256((__v16hi)a, (__v8hi)count);
+ return (__m256i)__builtin_ia32_psllw256((__v16hi)__a, (__v8hi)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_slli_epi32(__m256i a, int count)
+_mm256_slli_epi32(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_pslldi256((__v8si)a, count);
+ return (__m256i)__builtin_ia32_pslldi256((__v8si)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sll_epi32(__m256i a, __m128i count)
+_mm256_sll_epi32(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_pslld256((__v8si)a, (__v4si)count);
+ return (__m256i)__builtin_ia32_pslld256((__v8si)__a, (__v4si)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_slli_epi64(__m256i a, int count)
+_mm256_slli_epi64(__m256i __a, int __count)
{
- return __builtin_ia32_psllqi256(a, count);
+ return __builtin_ia32_psllqi256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sll_epi64(__m256i a, __m128i count)
+_mm256_sll_epi64(__m256i __a, __m128i __count)
{
- return __builtin_ia32_psllq256(a, count);
+ return __builtin_ia32_psllq256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srai_epi16(__m256i a, int count)
+_mm256_srai_epi16(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psrawi256((__v16hi)a, count);
+ return (__m256i)__builtin_ia32_psrawi256((__v16hi)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sra_epi16(__m256i a, __m128i count)
+_mm256_sra_epi16(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psraw256((__v16hi)a, (__v8hi)count);
+ return (__m256i)__builtin_ia32_psraw256((__v16hi)__a, (__v8hi)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srai_epi32(__m256i a, int count)
+_mm256_srai_epi32(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psradi256((__v8si)a, count);
+ return (__m256i)__builtin_ia32_psradi256((__v8si)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sra_epi32(__m256i a, __m128i count)
+_mm256_sra_epi32(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psrad256((__v8si)a, (__v4si)count);
+ return (__m256i)__builtin_ia32_psrad256((__v8si)__a, (__v4si)__count);
}
#define _mm256_srli_si256(a, count) __extension__ ({ \
@@ -588,141 +588,141 @@ _mm256_sra_epi32(__m256i a, __m128i count)
(__m256i)__builtin_ia32_psrldqi256(__a, (count)*8); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srli_epi16(__m256i a, int count)
+_mm256_srli_epi16(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psrlwi256((__v16hi)a, count);
+ return (__m256i)__builtin_ia32_psrlwi256((__v16hi)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srl_epi16(__m256i a, __m128i count)
+_mm256_srl_epi16(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psrlw256((__v16hi)a, (__v8hi)count);
+ return (__m256i)__builtin_ia32_psrlw256((__v16hi)__a, (__v8hi)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srli_epi32(__m256i a, int count)
+_mm256_srli_epi32(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psrldi256((__v8si)a, count);
+ return (__m256i)__builtin_ia32_psrldi256((__v8si)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srl_epi32(__m256i a, __m128i count)
+_mm256_srl_epi32(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psrld256((__v8si)a, (__v4si)count);
+ return (__m256i)__builtin_ia32_psrld256((__v8si)__a, (__v4si)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srli_epi64(__m256i a, int count)
+_mm256_srli_epi64(__m256i __a, int __count)
{
- return __builtin_ia32_psrlqi256(a, count);
+ return __builtin_ia32_psrlqi256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srl_epi64(__m256i a, __m128i count)
+_mm256_srl_epi64(__m256i __a, __m128i __count)
{
- return __builtin_ia32_psrlq256(a, count);
+ return __builtin_ia32_psrlq256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi8(__m256i a, __m256i b)
+_mm256_sub_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a - (__v32qi)b);
+ return (__m256i)((__v32qi)__a - (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi16(__m256i a, __m256i b)
+_mm256_sub_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a - (__v16hi)b);
+ return (__m256i)((__v16hi)__a - (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi32(__m256i a, __m256i b)
+_mm256_sub_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a - (__v8si)b);
+ return (__m256i)((__v8si)__a - (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi64(__m256i a, __m256i b)
+_mm256_sub_epi64(__m256i __a, __m256i __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epi8(__m256i a, __m256i b)
+_mm256_subs_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_psubsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epi16(__m256i a, __m256i b)
+_mm256_subs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_psubsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epu8(__m256i a, __m256i b)
+_mm256_subs_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubusb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_psubusb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epu16(__m256i a, __m256i b)
+_mm256_subs_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubusw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_psubusw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi8(__m256i a, __m256i b)
+_mm256_unpackhi_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v32qi)a, (__v32qi)b, 8, 32+8, 9, 32+9, 10, 32+10, 11, 32+11, 12, 32+12, 13, 32+13, 14, 32+14, 15, 32+15, 24, 32+24, 25, 32+25, 26, 32+26, 27, 32+27, 28, 32+28, 29, 32+29, 30, 32+30, 31, 32+31);
+ return (__m256i)__builtin_shufflevector((__v32qi)__a, (__v32qi)__b, 8, 32+8, 9, 32+9, 10, 32+10, 11, 32+11, 12, 32+12, 13, 32+13, 14, 32+14, 15, 32+15, 24, 32+24, 25, 32+25, 26, 32+26, 27, 32+27, 28, 32+28, 29, 32+29, 30, 32+30, 31, 32+31);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi16(__m256i a, __m256i b)
+_mm256_unpackhi_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v16hi)a, (__v16hi)b, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
+ return (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)__b, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi32(__m256i a, __m256i b)
+_mm256_unpackhi_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v8si)a, (__v8si)b, 2, 8+2, 3, 8+3, 6, 8+6, 7, 8+7);
+ return (__m256i)__builtin_shufflevector((__v8si)__a, (__v8si)__b, 2, 8+2, 3, 8+3, 6, 8+6, 7, 8+7);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi64(__m256i a, __m256i b)
+_mm256_unpackhi_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector(a, b, 1, 4+1, 3, 4+3);
+ return (__m256i)__builtin_shufflevector(__a, __b, 1, 4+1, 3, 4+3);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi8(__m256i a, __m256i b)
+_mm256_unpacklo_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v32qi)a, (__v32qi)b, 0, 32+0, 1, 32+1, 2, 32+2, 3, 32+3, 4, 32+4, 5, 32+5, 6, 32+6, 7, 32+7, 16, 32+16, 17, 32+17, 18, 32+18, 19, 32+19, 20, 32+20, 21, 32+21, 22, 32+22, 23, 32+23);
+ return (__m256i)__builtin_shufflevector((__v32qi)__a, (__v32qi)__b, 0, 32+0, 1, 32+1, 2, 32+2, 3, 32+3, 4, 32+4, 5, 32+5, 6, 32+6, 7, 32+7, 16, 32+16, 17, 32+17, 18, 32+18, 19, 32+19, 20, 32+20, 21, 32+21, 22, 32+22, 23, 32+23);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi16(__m256i a, __m256i b)
+_mm256_unpacklo_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v16hi)a, (__v16hi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11);
+ return (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)__b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi32(__m256i a, __m256i b)
+_mm256_unpacklo_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v8si)a, (__v8si)b, 0, 8+0, 1, 8+1, 4, 8+4, 5, 8+5);
+ return (__m256i)__builtin_shufflevector((__v8si)__a, (__v8si)__b, 0, 8+0, 1, 8+1, 4, 8+4, 5, 8+5);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi64(__m256i a, __m256i b)
+_mm256_unpacklo_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector(a, b, 0, 4+0, 2, 4+2);
+ return (__m256i)__builtin_shufflevector(__a, __b, 0, 4+0, 2, 4+2);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_xor_si256(__m256i a, __m256i b)
+_mm256_xor_si256(__m256i __a, __m256i __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -750,9 +750,9 @@ _mm256_broadcastsd_pd(__m128d __X)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm_broadcastsi128_si256(__m128i const *a)
+_mm_broadcastsi128_si256(__m128i const *__a)
{
- return (__m256i)__builtin_ia32_vbroadcastsi256(a);
+ return (__m256i)__builtin_ia32_vbroadcastsi256(__a);
}
#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
@@ -815,9 +815,9 @@ _mm_broadcastq_epi64(__m128i __X)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar8x32_epi32(__m256i a, __m256i b)
+_mm256_permutevar8x32_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_permvarsi256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_permvarsi256((__v8si)__a, (__v8si)__b);
}
#define _mm256_permute4x64_pd(V, M) __extension__ ({ \
@@ -827,9 +827,9 @@ _mm256_permutevar8x32_epi32(__m256i a, __m256i b)
((M) & 0x30) >> 4, ((M) & 0xc0) >> 6); })
static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar8x32_ps(__m256 a, __m256 b)
+_mm256_permutevar8x32_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_permvarsf256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_permvarsf256((__v8sf)__a, (__v8sf)__b);
}
#define _mm256_permute4x64_epi64(V, M) __extension__ ({ \
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index ee7f83572f5e..412d284f002b 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -38,111 +38,111 @@ typedef long long __m256i __attribute__((__vector_size__(32)));
/* Arithmetic */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_add_pd(__m256d a, __m256d b)
+_mm256_add_pd(__m256d __a, __m256d __b)
{
- return a+b;
+ return __a+__b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_add_ps(__m256 a, __m256 b)
+_mm256_add_ps(__m256 __a, __m256 __b)
{
- return a+b;
+ return __a+__b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_pd(__m256d a, __m256d b)
+_mm256_sub_pd(__m256d __a, __m256d __b)
{
- return a-b;
+ return __a-__b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_ps(__m256 a, __m256 b)
+_mm256_sub_ps(__m256 __a, __m256 __b)
{
- return a-b;
+ return __a-__b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_addsub_pd(__m256d a, __m256d b)
+_mm256_addsub_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_addsubpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_addsubpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_addsub_ps(__m256 a, __m256 b)
+_mm256_addsub_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_addsubps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_addsubps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_div_pd(__m256d a, __m256d b)
+_mm256_div_pd(__m256d __a, __m256d __b)
{
- return a / b;
+ return __a / __b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_div_ps(__m256 a, __m256 b)
+_mm256_div_ps(__m256 __a, __m256 __b)
{
- return a / b;
+ return __a / __b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_max_pd(__m256d a, __m256d b)
+_mm256_max_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_maxpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_maxpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_max_ps(__m256 a, __m256 b)
+_mm256_max_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_maxps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_maxps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_min_pd(__m256d a, __m256d b)
+_mm256_min_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_minpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_minpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_min_ps(__m256 a, __m256 b)
+_mm256_min_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_minps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_minps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_pd(__m256d a, __m256d b)
+_mm256_mul_pd(__m256d __a, __m256d __b)
{
- return a * b;
+ return __a * __b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_ps(__m256 a, __m256 b)
+_mm256_mul_ps(__m256 __a, __m256 __b)
{
- return a * b;
+ return __a * __b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_sqrt_pd(__m256d a)
+_mm256_sqrt_pd(__m256d __a)
{
- return (__m256d)__builtin_ia32_sqrtpd256((__v4df)a);
+ return (__m256d)__builtin_ia32_sqrtpd256((__v4df)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_sqrt_ps(__m256 a)
+_mm256_sqrt_ps(__m256 __a)
{
- return (__m256)__builtin_ia32_sqrtps256((__v8sf)a);
+ return (__m256)__builtin_ia32_sqrtps256((__v8sf)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_rsqrt_ps(__m256 a)
+_mm256_rsqrt_ps(__m256 __a)
{
- return (__m256)__builtin_ia32_rsqrtps256((__v8sf)a);
+ return (__m256)__builtin_ia32_rsqrtps256((__v8sf)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_rcp_ps(__m256 a)
+_mm256_rcp_ps(__m256 __a)
{
- return (__m256)__builtin_ia32_rcpps256((__v8sf)a);
+ return (__m256)__builtin_ia32_rcpps256((__v8sf)__a);
}
#define _mm256_round_pd(V, M) __extension__ ({ \
@@ -160,102 +160,102 @@ _mm256_rcp_ps(__m256 a)
/* Logical */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_and_pd(__m256d a, __m256d b)
+_mm256_and_pd(__m256d __a, __m256d __b)
{
- return (__m256d)((__v4di)a & (__v4di)b);
+ return (__m256d)((__v4di)__a & (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_and_ps(__m256 a, __m256 b)
+_mm256_and_ps(__m256 __a, __m256 __b)
{
- return (__m256)((__v8si)a & (__v8si)b);
+ return (__m256)((__v8si)__a & (__v8si)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_andnot_pd(__m256d a, __m256d b)
+_mm256_andnot_pd(__m256d __a, __m256d __b)
{
- return (__m256d)(~(__v4di)a & (__v4di)b);
+ return (__m256d)(~(__v4di)__a & (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_andnot_ps(__m256 a, __m256 b)
+_mm256_andnot_ps(__m256 __a, __m256 __b)
{
- return (__m256)(~(__v8si)a & (__v8si)b);
+ return (__m256)(~(__v8si)__a & (__v8si)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_or_pd(__m256d a, __m256d b)
+_mm256_or_pd(__m256d __a, __m256d __b)
{
- return (__m256d)((__v4di)a | (__v4di)b);
+ return (__m256d)((__v4di)__a | (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_or_ps(__m256 a, __m256 b)
+_mm256_or_ps(__m256 __a, __m256 __b)
{
- return (__m256)((__v8si)a | (__v8si)b);
+ return (__m256)((__v8si)__a | (__v8si)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_xor_pd(__m256d a, __m256d b)
+_mm256_xor_pd(__m256d __a, __m256d __b)
{
- return (__m256d)((__v4di)a ^ (__v4di)b);
+ return (__m256d)((__v4di)__a ^ (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_xor_ps(__m256 a, __m256 b)
+_mm256_xor_ps(__m256 __a, __m256 __b)
{
- return (__m256)((__v8si)a ^ (__v8si)b);
+ return (__m256)((__v8si)__a ^ (__v8si)__b);
}
/* Horizontal arithmetic */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_pd(__m256d a, __m256d b)
+_mm256_hadd_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_haddpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_haddpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_ps(__m256 a, __m256 b)
+_mm256_hadd_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_haddps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_haddps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_pd(__m256d a, __m256d b)
+_mm256_hsub_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_hsubpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_hsubpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_ps(__m256 a, __m256 b)
+_mm256_hsub_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_hsubps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_hsubps256((__v8sf)__a, (__v8sf)__b);
}
/* Vector permutations */
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_permutevar_pd(__m128d a, __m128i c)
+_mm_permutevar_pd(__m128d __a, __m128i __c)
{
- return (__m128d)__builtin_ia32_vpermilvarpd((__v2df)a, (__v2di)c);
+ return (__m128d)__builtin_ia32_vpermilvarpd((__v2df)__a, (__v2di)__c);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar_pd(__m256d a, __m256i c)
+_mm256_permutevar_pd(__m256d __a, __m256i __c)
{
- return (__m256d)__builtin_ia32_vpermilvarpd256((__v4df)a, (__v4di)c);
+ return (__m256d)__builtin_ia32_vpermilvarpd256((__v4df)__a, (__v4di)__c);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_permutevar_ps(__m128 a, __m128i c)
+_mm_permutevar_ps(__m128 __a, __m128i __c)
{
- return (__m128)__builtin_ia32_vpermilvarps((__v4sf)a, (__v4si)c);
+ return (__m128)__builtin_ia32_vpermilvarps((__v4sf)__a, (__v4si)__c);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar_ps(__m256 a, __m256i c)
+_mm256_permutevar_ps(__m256 __a, __m256i __c)
{
- return (__m256)__builtin_ia32_vpermilvarps256((__v8sf)a,
- (__v8si)c);
+ return (__m256)__builtin_ia32_vpermilvarps256((__v8sf)__a,
+ (__v8si)__c);
}
#define _mm_permute_pd(A, C) __extension__ ({ \
@@ -313,15 +313,17 @@ _mm256_permutevar_ps(__m256 a, __m256i c)
(__m256)__builtin_ia32_blendps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_blendv_pd(__m256d a, __m256d b, __m256d c)
+_mm256_blendv_pd(__m256d __a, __m256d __b, __m256d __c)
{
- return (__m256d)__builtin_ia32_blendvpd256((__v4df)a, (__v4df)b, (__v4df)c);
+ return (__m256d)__builtin_ia32_blendvpd256(
+ (__v4df)__a, (__v4df)__b, (__v4df)__c);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_blendv_ps(__m256 a, __m256 b, __m256 c)
+_mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
{
- return (__m256)__builtin_ia32_blendvps256((__v8sf)a, (__v8sf)b, (__v8sf)c);
+ return (__m256)__builtin_ia32_blendvps256(
+ (__v8sf)__a, (__v8sf)__b, (__v8sf)__c);
}
/* Vector Dot Product */
@@ -427,32 +429,32 @@ _mm256_blendv_ps(__m256 a, __m256 b, __m256 c)
(__m128i)__builtin_ia32_vextractf128_si256((__v8si)__A, (O)); })
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi32(__m256i a, int const imm)
+_mm256_extract_epi32(__m256i __a, int const __imm)
{
- __v8si b = (__v8si)a;
- return b[imm];
+ __v8si __b = (__v8si)__a;
+ return __b[__imm];
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi16(__m256i a, int const imm)
+_mm256_extract_epi16(__m256i __a, int const __imm)
{
- __v16hi b = (__v16hi)a;
- return b[imm];
+ __v16hi __b = (__v16hi)__a;
+ return __b[__imm];
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi8(__m256i a, int const imm)
+_mm256_extract_epi8(__m256i __a, int const __imm)
{
- __v32qi b = (__v32qi)a;
- return b[imm];
+ __v32qi __b = (__v32qi)__a;
+ return __b[__imm];
}
#ifdef __x86_64__
static __inline long long __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi64(__m256i a, const int imm)
+_mm256_extract_epi64(__m256i __a, const int __imm)
{
- __v4di b = (__v4di)a;
- return b[imm];
+ __v4di __b = (__v4di)__a;
+ return __b[__imm];
}
#endif
@@ -473,237 +475,237 @@ _mm256_extract_epi64(__m256i a, const int imm)
(__m256i)__builtin_ia32_vinsertf128_si256((__v8si)__V1, (__v4si)__V2, (O)); })
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi32(__m256i a, int b, int const imm)
+_mm256_insert_epi32(__m256i __a, int __b, int const __imm)
{
- __v8si c = (__v8si)a;
- c[imm & 7] = b;
- return (__m256i)c;
+ __v8si __c = (__v8si)__a;
+ __c[__imm & 7] = __b;
+ return (__m256i)__c;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi16(__m256i a, int b, int const imm)
+_mm256_insert_epi16(__m256i __a, int __b, int const __imm)
{
- __v16hi c = (__v16hi)a;
- c[imm & 15] = b;
- return (__m256i)c;
+ __v16hi __c = (__v16hi)__a;
+ __c[__imm & 15] = __b;
+ return (__m256i)__c;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi8(__m256i a, int b, int const imm)
+_mm256_insert_epi8(__m256i __a, int __b, int const __imm)
{
- __v32qi c = (__v32qi)a;
- c[imm & 31] = b;
- return (__m256i)c;
+ __v32qi __c = (__v32qi)__a;
+ __c[__imm & 31] = __b;
+ return (__m256i)__c;
}
#ifdef __x86_64__
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi64(__m256i a, int b, int const imm)
+_mm256_insert_epi64(__m256i __a, int __b, int const __imm)
{
- __v4di c = (__v4di)a;
- c[imm & 3] = b;
- return (__m256i)c;
+ __v4di __c = (__v4di)__a;
+ __c[__imm & 3] = __b;
+ return (__m256i)__c;
}
#endif
/* Conversion */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtepi32_pd(__m128i a)
+_mm256_cvtepi32_pd(__m128i __a)
{
- return (__m256d)__builtin_ia32_cvtdq2pd256((__v4si) a);
+ return (__m256d)__builtin_ia32_cvtdq2pd256((__v4si) __a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtepi32_ps(__m256i a)
+_mm256_cvtepi32_ps(__m256i __a)
{
- return (__m256)__builtin_ia32_cvtdq2ps256((__v8si) a);
+ return (__m256)__builtin_ia32_cvtdq2ps256((__v8si) __a);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtpd_ps(__m256d a)
+_mm256_cvtpd_ps(__m256d __a)
{
- return (__m128)__builtin_ia32_cvtpd2ps256((__v4df) a);
+ return (__m128)__builtin_ia32_cvtpd2ps256((__v4df) __a);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtps_epi32(__m256 a)
+_mm256_cvtps_epi32(__m256 __a)
{
- return (__m256i)__builtin_ia32_cvtps2dq256((__v8sf) a);
+ return (__m256i)__builtin_ia32_cvtps2dq256((__v8sf) __a);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtps_pd(__m128 a)
+_mm256_cvtps_pd(__m128 __a)
{
- return (__m256d)__builtin_ia32_cvtps2pd256((__v4sf) a);
+ return (__m256d)__builtin_ia32_cvtps2pd256((__v4sf) __a);
}
static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvttpd_epi32(__m256d a)
+_mm256_cvttpd_epi32(__m256d __a)
{
- return (__m128i)__builtin_ia32_cvttpd2dq256((__v4df) a);
+ return (__m128i)__builtin_ia32_cvttpd2dq256((__v4df) __a);
}
static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtpd_epi32(__m256d a)
+_mm256_cvtpd_epi32(__m256d __a)
{
- return (__m128i)__builtin_ia32_cvtpd2dq256((__v4df) a);
+ return (__m128i)__builtin_ia32_cvtpd2dq256((__v4df) __a);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvttps_epi32(__m256 a)
+_mm256_cvttps_epi32(__m256 __a)
{
- return (__m256i)__builtin_ia32_cvttps2dq256((__v8sf) a);
+ return (__m256i)__builtin_ia32_cvttps2dq256((__v8sf) __a);
}
/* Vector replicate */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_movehdup_ps(__m256 a)
+_mm256_movehdup_ps(__m256 __a)
{
- return __builtin_shufflevector(a, a, 1, 1, 3, 3, 5, 5, 7, 7);
+ return __builtin_shufflevector(__a, __a, 1, 1, 3, 3, 5, 5, 7, 7);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_moveldup_ps(__m256 a)
+_mm256_moveldup_ps(__m256 __a)
{
- return __builtin_shufflevector(a, a, 0, 0, 2, 2, 4, 4, 6, 6);
+ return __builtin_shufflevector(__a, __a, 0, 0, 2, 2, 4, 4, 6, 6);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_movedup_pd(__m256d a)
+_mm256_movedup_pd(__m256d __a)
{
- return __builtin_shufflevector(a, a, 0, 0, 2, 2);
+ return __builtin_shufflevector(__a, __a, 0, 0, 2, 2);
}
/* Unpack and Interleave */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_pd(__m256d a, __m256d b)
+_mm256_unpackhi_pd(__m256d __a, __m256d __b)
{
- return __builtin_shufflevector(a, b, 1, 5, 1+2, 5+2);
+ return __builtin_shufflevector(__a, __b, 1, 5, 1+2, 5+2);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_pd(__m256d a, __m256d b)
+_mm256_unpacklo_pd(__m256d __a, __m256d __b)
{
- return __builtin_shufflevector(a, b, 0, 4, 0+2, 4+2);
+ return __builtin_shufflevector(__a, __b, 0, 4, 0+2, 4+2);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_ps(__m256 a, __m256 b)
+_mm256_unpackhi_ps(__m256 __a, __m256 __b)
{
- return __builtin_shufflevector(a, b, 2, 10, 2+1, 10+1, 6, 14, 6+1, 14+1);
+ return __builtin_shufflevector(__a, __b, 2, 10, 2+1, 10+1, 6, 14, 6+1, 14+1);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_ps(__m256 a, __m256 b)
+_mm256_unpacklo_ps(__m256 __a, __m256 __b)
{
- return __builtin_shufflevector(a, b, 0, 8, 0+1, 8+1, 4, 12, 4+1, 12+1);
+ return __builtin_shufflevector(__a, __b, 0, 8, 0+1, 8+1, 4, 12, 4+1, 12+1);
}
/* Bit Test */
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testz_pd(__m128d a, __m128d b)
+_mm_testz_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_vtestzpd((__v2df)a, (__v2df)b);
+ return __builtin_ia32_vtestzpd((__v2df)__a, (__v2df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testc_pd(__m128d a, __m128d b)
+_mm_testc_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_vtestcpd((__v2df)a, (__v2df)b);
+ return __builtin_ia32_vtestcpd((__v2df)__a, (__v2df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testnzc_pd(__m128d a, __m128d b)
+_mm_testnzc_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_vtestnzcpd((__v2df)a, (__v2df)b);
+ return __builtin_ia32_vtestnzcpd((__v2df)__a, (__v2df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testz_ps(__m128 a, __m128 b)
+_mm_testz_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_vtestzps((__v4sf)a, (__v4sf)b);
+ return __builtin_ia32_vtestzps((__v4sf)__a, (__v4sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testc_ps(__m128 a, __m128 b)
+_mm_testc_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_vtestcps((__v4sf)a, (__v4sf)b);
+ return __builtin_ia32_vtestcps((__v4sf)__a, (__v4sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testnzc_ps(__m128 a, __m128 b)
+_mm_testnzc_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_vtestnzcps((__v4sf)a, (__v4sf)b);
+ return __builtin_ia32_vtestnzcps((__v4sf)__a, (__v4sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testz_pd(__m256d a, __m256d b)
+_mm256_testz_pd(__m256d __a, __m256d __b)
{
- return __builtin_ia32_vtestzpd256((__v4df)a, (__v4df)b);
+ return __builtin_ia32_vtestzpd256((__v4df)__a, (__v4df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testc_pd(__m256d a, __m256d b)
+_mm256_testc_pd(__m256d __a, __m256d __b)
{
- return __builtin_ia32_vtestcpd256((__v4df)a, (__v4df)b);
+ return __builtin_ia32_vtestcpd256((__v4df)__a, (__v4df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testnzc_pd(__m256d a, __m256d b)
+_mm256_testnzc_pd(__m256d __a, __m256d __b)
{
- return __builtin_ia32_vtestnzcpd256((__v4df)a, (__v4df)b);
+ return __builtin_ia32_vtestnzcpd256((__v4df)__a, (__v4df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testz_ps(__m256 a, __m256 b)
+_mm256_testz_ps(__m256 __a, __m256 __b)
{
- return __builtin_ia32_vtestzps256((__v8sf)a, (__v8sf)b);
+ return __builtin_ia32_vtestzps256((__v8sf)__a, (__v8sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testc_ps(__m256 a, __m256 b)
+_mm256_testc_ps(__m256 __a, __m256 __b)
{
- return __builtin_ia32_vtestcps256((__v8sf)a, (__v8sf)b);
+ return __builtin_ia32_vtestcps256((__v8sf)__a, (__v8sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testnzc_ps(__m256 a, __m256 b)
+_mm256_testnzc_ps(__m256 __a, __m256 __b)
{
- return __builtin_ia32_vtestnzcps256((__v8sf)a, (__v8sf)b);
+ return __builtin_ia32_vtestnzcps256((__v8sf)__a, (__v8sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testz_si256(__m256i a, __m256i b)
+_mm256_testz_si256(__m256i __a, __m256i __b)
{
- return __builtin_ia32_ptestz256((__v4di)a, (__v4di)b);
+ return __builtin_ia32_ptestz256((__v4di)__a, (__v4di)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testc_si256(__m256i a, __m256i b)
+_mm256_testc_si256(__m256i __a, __m256i __b)
{
- return __builtin_ia32_ptestc256((__v4di)a, (__v4di)b);
+ return __builtin_ia32_ptestc256((__v4di)__a, (__v4di)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testnzc_si256(__m256i a, __m256i b)
+_mm256_testnzc_si256(__m256i __a, __m256i __b)
{
- return __builtin_ia32_ptestnzc256((__v4di)a, (__v4di)b);
+ return __builtin_ia32_ptestnzc256((__v4di)__a, (__v4di)__b);
}
/* Vector extract sign mask */
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_movemask_pd(__m256d a)
+_mm256_movemask_pd(__m256d __a)
{
- return __builtin_ia32_movmskpd256((__v4df)a);
+ return __builtin_ia32_movmskpd256((__v4df)__a);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_movemask_ps(__m256 a)
+_mm256_movemask_ps(__m256 __a)
{
- return __builtin_ia32_movmskps256((__v8sf)a);
+ return __builtin_ia32_movmskps256((__v8sf)__a);
}
-/* Vector zero */
+/* Vector __zero */
static __inline void __attribute__((__always_inline__, __nodebug__))
_mm256_zeroall(void)
{
@@ -718,341 +720,344 @@ _mm256_zeroupper(void)
/* Vector load with broadcast */
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_broadcast_ss(float const *a)
+_mm_broadcast_ss(float const *__a)
{
- return (__m128)__builtin_ia32_vbroadcastss(a);
+ return (__m128)__builtin_ia32_vbroadcastss(__a);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_sd(double const *a)
+_mm256_broadcast_sd(double const *__a)
{
- return (__m256d)__builtin_ia32_vbroadcastsd256(a);
+ return (__m256d)__builtin_ia32_vbroadcastsd256(__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_ss(float const *a)
+_mm256_broadcast_ss(float const *__a)
{
- return (__m256)__builtin_ia32_vbroadcastss256(a);
+ return (__m256)__builtin_ia32_vbroadcastss256(__a);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_pd(__m128d const *a)
+_mm256_broadcast_pd(__m128d const *__a)
{
- return (__m256d)__builtin_ia32_vbroadcastf128_pd256(a);
+ return (__m256d)__builtin_ia32_vbroadcastf128_pd256(__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_ps(__m128 const *a)
+_mm256_broadcast_ps(__m128 const *__a)
{
- return (__m256)__builtin_ia32_vbroadcastf128_ps256(a);
+ return (__m256)__builtin_ia32_vbroadcastf128_ps256(__a);
}
/* SIMD load ops */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_load_pd(double const *p)
+_mm256_load_pd(double const *__p)
{
- return *(__m256d *)p;
+ return *(__m256d *)__p;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_load_ps(float const *p)
+_mm256_load_ps(float const *__p)
{
- return *(__m256 *)p;
+ return *(__m256 *)__p;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu_pd(double const *p)
+_mm256_loadu_pd(double const *__p)
{
struct __loadu_pd {
- __m256d v;
+ __m256d __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_pd*)p)->v;
+ return ((struct __loadu_pd*)__p)->__v;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu_ps(float const *p)
+_mm256_loadu_ps(float const *__p)
{
struct __loadu_ps {
- __m256 v;
+ __m256 __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_ps*)p)->v;
+ return ((struct __loadu_ps*)__p)->__v;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_load_si256(__m256i const *p)
+_mm256_load_si256(__m256i const *__p)
{
- return *p;
+ return *__p;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu_si256(__m256i const *p)
+_mm256_loadu_si256(__m256i const *__p)
{
struct __loadu_si256 {
- __m256i v;
+ __m256i __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_si256*)p)->v;
+ return ((struct __loadu_si256*)__p)->__v;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_lddqu_si256(__m256i const *p)
+_mm256_lddqu_si256(__m256i const *__p)
{
- return (__m256i)__builtin_ia32_lddqu256((char const *)p);
+ return (__m256i)__builtin_ia32_lddqu256((char const *)__p);
}
/* SIMD store ops */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_store_pd(double *p, __m256d a)
+_mm256_store_pd(double *__p, __m256d __a)
{
- *(__m256d *)p = a;
+ *(__m256d *)__p = __a;
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_store_ps(float *p, __m256 a)
+_mm256_store_ps(float *__p, __m256 __a)
{
- *(__m256 *)p = a;
+ *(__m256 *)__p = __a;
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu_pd(double *p, __m256d a)
+_mm256_storeu_pd(double *__p, __m256d __a)
{
- __builtin_ia32_storeupd256(p, (__v4df)a);
+ __builtin_ia32_storeupd256(__p, (__v4df)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu_ps(float *p, __m256 a)
+_mm256_storeu_ps(float *__p, __m256 __a)
{
- __builtin_ia32_storeups256(p, (__v8sf)a);
+ __builtin_ia32_storeups256(__p, (__v8sf)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_store_si256(__m256i *p, __m256i a)
+_mm256_store_si256(__m256i *__p, __m256i __a)
{
- *p = a;
+ *__p = __a;
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu_si256(__m256i *p, __m256i a)
+_mm256_storeu_si256(__m256i *__p, __m256i __a)
{
- __builtin_ia32_storedqu256((char *)p, (__v32qi)a);
+ __builtin_ia32_storedqu256((char *)__p, (__v32qi)__a);
}
/* Conditional load ops */
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_maskload_pd(double const *p, __m128d m)
+_mm_maskload_pd(double const *__p, __m128d __m)
{
- return (__m128d)__builtin_ia32_maskloadpd((const __v2df *)p, (__v2df)m);
+ return (__m128d)__builtin_ia32_maskloadpd((const __v2df *)__p, (__v2df)__m);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_maskload_pd(double const *p, __m256d m)
+_mm256_maskload_pd(double const *__p, __m256d __m)
{
- return (__m256d)__builtin_ia32_maskloadpd256((const __v4df *)p, (__v4df)m);
+ return (__m256d)__builtin_ia32_maskloadpd256((const __v4df *)__p,
+ (__v4df)__m);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_maskload_ps(float const *p, __m128 m)
+_mm_maskload_ps(float const *__p, __m128 __m)
{
- return (__m128)__builtin_ia32_maskloadps((const __v4sf *)p, (__v4sf)m);
+ return (__m128)__builtin_ia32_maskloadps((const __v4sf *)__p, (__v4sf)__m);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_maskload_ps(float const *p, __m256 m)
+_mm256_maskload_ps(float const *__p, __m256 __m)
{
- return (__m256)__builtin_ia32_maskloadps256((const __v8sf *)p, (__v8sf)m);
+ return (__m256)__builtin_ia32_maskloadps256((const __v8sf *)__p, (__v8sf)__m);
}
/* Conditional store ops */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_maskstore_ps(float *p, __m256 m, __m256 a)
+_mm256_maskstore_ps(float *__p, __m256 __m, __m256 __a)
{
- __builtin_ia32_maskstoreps256((__v8sf *)p, (__v8sf)m, (__v8sf)a);
+ __builtin_ia32_maskstoreps256((__v8sf *)__p, (__v8sf)__m, (__v8sf)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm_maskstore_pd(double *p, __m128d m, __m128d a)
+_mm_maskstore_pd(double *__p, __m128d __m, __m128d __a)
{
- __builtin_ia32_maskstorepd((__v2df *)p, (__v2df)m, (__v2df)a);
+ __builtin_ia32_maskstorepd((__v2df *)__p, (__v2df)__m, (__v2df)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_maskstore_pd(double *p, __m256d m, __m256d a)
+_mm256_maskstore_pd(double *__p, __m256d __m, __m256d __a)
{
- __builtin_ia32_maskstorepd256((__v4df *)p, (__v4df)m, (__v4df)a);
+ __builtin_ia32_maskstorepd256((__v4df *)__p, (__v4df)__m, (__v4df)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm_maskstore_ps(float *p, __m128 m, __m128 a)
+_mm_maskstore_ps(float *__p, __m128 __m, __m128 __a)
{
- __builtin_ia32_maskstoreps((__v4sf *)p, (__v4sf)m, (__v4sf)a);
+ __builtin_ia32_maskstoreps((__v4sf *)__p, (__v4sf)__m, (__v4sf)__a);
}
/* Cacheability support ops */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_stream_si256(__m256i *a, __m256i b)
+_mm256_stream_si256(__m256i *__a, __m256i __b)
{
- __builtin_ia32_movntdq256((__v4di *)a, (__v4di)b);
+ __builtin_ia32_movntdq256((__v4di *)__a, (__v4di)__b);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_stream_pd(double *a, __m256d b)
+_mm256_stream_pd(double *__a, __m256d __b)
{
- __builtin_ia32_movntpd256(a, (__v4df)b);
+ __builtin_ia32_movntpd256(__a, (__v4df)__b);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_stream_ps(float *p, __m256 a)
+_mm256_stream_ps(float *__p, __m256 __a)
{
- __builtin_ia32_movntps256(p, (__v8sf)a);
+ __builtin_ia32_movntps256(__p, (__v8sf)__a);
}
/* Create vectors */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_set_pd(double a, double b, double c, double d)
+_mm256_set_pd(double __a, double __b, double __c, double __d)
{
- return (__m256d){ d, c, b, a };
+ return (__m256d){ __d, __c, __b, __a };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_set_ps(float a, float b, float c, float d,
- float e, float f, float g, float h)
+_mm256_set_ps(float __a, float __b, float __c, float __d,
+ float __e, float __f, float __g, float __h)
{
- return (__m256){ h, g, f, e, d, c, b, a };
+ return (__m256){ __h, __g, __f, __e, __d, __c, __b, __a };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi32(int i0, int i1, int i2, int i3,
- int i4, int i5, int i6, int i7)
+_mm256_set_epi32(int __i0, int __i1, int __i2, int __i3,
+ int __i4, int __i5, int __i6, int __i7)
{
- return (__m256i)(__v8si){ i7, i6, i5, i4, i3, i2, i1, i0 };
+ return (__m256i)(__v8si){ __i7, __i6, __i5, __i4, __i3, __i2, __i1, __i0 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi16(short w15, short w14, short w13, short w12,
- short w11, short w10, short w09, short w08,
- short w07, short w06, short w05, short w04,
- short w03, short w02, short w01, short w00)
+_mm256_set_epi16(short __w15, short __w14, short __w13, short __w12,
+ short __w11, short __w10, short __w09, short __w08,
+ short __w07, short __w06, short __w05, short __w04,
+ short __w03, short __w02, short __w01, short __w00)
{
- return (__m256i)(__v16hi){ w00, w01, w02, w03, w04, w05, w06, w07,
- w08, w09, w10, w11, w12, w13, w14, w15 };
+ return (__m256i)(__v16hi){ __w00, __w01, __w02, __w03, __w04, __w05, __w06,
+ __w07, __w08, __w09, __w10, __w11, __w12, __w13, __w14, __w15 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi8(char b31, char b30, char b29, char b28,
- char b27, char b26, char b25, char b24,
- char b23, char b22, char b21, char b20,
- char b19, char b18, char b17, char b16,
- char b15, char b14, char b13, char b12,
- char b11, char b10, char b09, char b08,
- char b07, char b06, char b05, char b04,
- char b03, char b02, char b01, char b00)
+_mm256_set_epi8(char __b31, char __b30, char __b29, char __b28,
+ char __b27, char __b26, char __b25, char __b24,
+ char __b23, char __b22, char __b21, char __b20,
+ char __b19, char __b18, char __b17, char __b16,
+ char __b15, char __b14, char __b13, char __b12,
+ char __b11, char __b10, char __b09, char __b08,
+ char __b07, char __b06, char __b05, char __b04,
+ char __b03, char __b02, char __b01, char __b00)
{
return (__m256i)(__v32qi){
- b00, b01, b02, b03, b04, b05, b06, b07,
- b08, b09, b10, b11, b12, b13, b14, b15,
- b16, b17, b18, b19, b20, b21, b22, b23,
- b24, b25, b26, b27, b28, b29, b30, b31
+ __b00, __b01, __b02, __b03, __b04, __b05, __b06, __b07,
+ __b08, __b09, __b10, __b11, __b12, __b13, __b14, __b15,
+ __b16, __b17, __b18, __b19, __b20, __b21, __b22, __b23,
+ __b24, __b25, __b26, __b27, __b28, __b29, __b30, __b31
};
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi64x(long long a, long long b, long long c, long long d)
+_mm256_set_epi64x(long long __a, long long __b, long long __c, long long __d)
{
- return (__m256i)(__v4di){ d, c, b, a };
+ return (__m256i)(__v4di){ __d, __c, __b, __a };
}
/* Create vectors with elements in reverse order */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_pd(double a, double b, double c, double d)
+_mm256_setr_pd(double __a, double __b, double __c, double __d)
{
- return (__m256d){ a, b, c, d };
+ return (__m256d){ __a, __b, __c, __d };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_ps(float a, float b, float c, float d,
- float e, float f, float g, float h)
+_mm256_setr_ps(float __a, float __b, float __c, float __d,
+ float __e, float __f, float __g, float __h)
{
- return (__m256){ a, b, c, d, e, f, g, h };
+ return (__m256){ __a, __b, __c, __d, __e, __f, __g, __h };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi32(int i0, int i1, int i2, int i3,
- int i4, int i5, int i6, int i7)
+_mm256_setr_epi32(int __i0, int __i1, int __i2, int __i3,
+ int __i4, int __i5, int __i6, int __i7)
{
- return (__m256i)(__v8si){ i0, i1, i2, i3, i4, i5, i6, i7 };
+ return (__m256i)(__v8si){ __i0, __i1, __i2, __i3, __i4, __i5, __i6, __i7 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi16(short w15, short w14, short w13, short w12,
- short w11, short w10, short w09, short w08,
- short w07, short w06, short w05, short w04,
- short w03, short w02, short w01, short w00)
+_mm256_setr_epi16(short __w15, short __w14, short __w13, short __w12,
+ short __w11, short __w10, short __w09, short __w08,
+ short __w07, short __w06, short __w05, short __w04,
+ short __w03, short __w02, short __w01, short __w00)
{
- return (__m256i)(__v16hi){ w15, w14, w13, w12, w11, w10, w09, w08,
- w07, w06, w05, w04, w03, w02, w01, w00 };
+ return (__m256i)(__v16hi){ __w15, __w14, __w13, __w12, __w11, __w10, __w09,
+ __w08, __w07, __w06, __w05, __w04, __w03, __w02, __w01, __w00 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi8(char b31, char b30, char b29, char b28,
- char b27, char b26, char b25, char b24,
- char b23, char b22, char b21, char b20,
- char b19, char b18, char b17, char b16,
- char b15, char b14, char b13, char b12,
- char b11, char b10, char b09, char b08,
- char b07, char b06, char b05, char b04,
- char b03, char b02, char b01, char b00)
+_mm256_setr_epi8(char __b31, char __b30, char __b29, char __b28,
+ char __b27, char __b26, char __b25, char __b24,
+ char __b23, char __b22, char __b21, char __b20,
+ char __b19, char __b18, char __b17, char __b16,
+ char __b15, char __b14, char __b13, char __b12,
+ char __b11, char __b10, char __b09, char __b08,
+ char __b07, char __b06, char __b05, char __b04,
+ char __b03, char __b02, char __b01, char __b00)
{
return (__m256i)(__v32qi){
- b31, b30, b29, b28, b27, b26, b25, b24,
- b23, b22, b21, b20, b19, b18, b17, b16,
- b15, b14, b13, b12, b11, b10, b09, b08,
- b07, b06, b05, b04, b03, b02, b01, b00 };
+ __b31, __b30, __b29, __b28, __b27, __b26, __b25, __b24,
+ __b23, __b22, __b21, __b20, __b19, __b18, __b17, __b16,
+ __b15, __b14, __b13, __b12, __b11, __b10, __b09, __b08,
+ __b07, __b06, __b05, __b04, __b03, __b02, __b01, __b00 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi64x(long long a, long long b, long long c, long long d)
+_mm256_setr_epi64x(long long __a, long long __b, long long __c, long long __d)
{
- return (__m256i)(__v4di){ a, b, c, d };
+ return (__m256i)(__v4di){ __a, __b, __c, __d };
}
/* Create vectors with repeated elements */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_pd(double w)
+_mm256_set1_pd(double __w)
{
- return (__m256d){ w, w, w, w };
+ return (__m256d){ __w, __w, __w, __w };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_ps(float w)
+_mm256_set1_ps(float __w)
{
- return (__m256){ w, w, w, w, w, w, w, w };
+ return (__m256){ __w, __w, __w, __w, __w, __w, __w, __w };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi32(int i)
+_mm256_set1_epi32(int __i)
{
- return (__m256i)(__v8si){ i, i, i, i, i, i, i, i };
+ return (__m256i)(__v8si){ __i, __i, __i, __i, __i, __i, __i, __i };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi16(short w)
+_mm256_set1_epi16(short __w)
{
- return (__m256i)(__v16hi){ w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w };
+ return (__m256i)(__v16hi){ __w, __w, __w, __w, __w, __w, __w, __w, __w, __w,
+ __w, __w, __w, __w, __w, __w };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi8(char b)
+_mm256_set1_epi8(char __b)
{
- return (__m256i)(__v32qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b,
- b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b };
+ return (__m256i)(__v32qi){ __b, __b, __b, __b, __b, __b, __b, __b, __b, __b,
+ __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b,
+ __b, __b, __b, __b, __b, __b, __b };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi64x(long long q)
+_mm256_set1_epi64x(long long __q)
{
- return (__m256i)(__v4di){ q, q, q, q };
+ return (__m256i)(__v4di){ __q, __q, __q, __q };
}
-/* Create zeroed vectors */
+/* Create __zeroed vectors */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_setzero_pd(void)
{
@@ -1073,143 +1078,145 @@ _mm256_setzero_si256(void)
/* Cast between vector types */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd_ps(__m256d in)
+_mm256_castpd_ps(__m256d __in)
{
- return (__m256)in;
+ return (__m256)__in;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd_si256(__m256d in)
+_mm256_castpd_si256(__m256d __in)
{
- return (__m256i)in;
+ return (__m256i)__in;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_castps_pd(__m256 in)
+_mm256_castps_pd(__m256 __in)
{
- return (__m256d)in;
+ return (__m256d)__in;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_castps_si256(__m256 in)
+_mm256_castps_si256(__m256 __in)
{
- return (__m256i)in;
+ return (__m256i)__in;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi256_ps(__m256i in)
+_mm256_castsi256_ps(__m256i __in)
{
- return (__m256)in;
+ return (__m256)__in;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi256_pd(__m256i in)
+_mm256_castsi256_pd(__m256i __in)
{
- return (__m256d)in;
+ return (__m256d)__in;
}
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd256_pd128(__m256d in)
+_mm256_castpd256_pd128(__m256d __in)
{
- return __builtin_shufflevector(in, in, 0, 1);
+ return __builtin_shufflevector(__in, __in, 0, 1);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm256_castps256_ps128(__m256 in)
+_mm256_castps256_ps128(__m256 __in)
{
- return __builtin_shufflevector(in, in, 0, 1, 2, 3);
+ return __builtin_shufflevector(__in, __in, 0, 1, 2, 3);
}
static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi256_si128(__m256i in)
+_mm256_castsi256_si128(__m256i __in)
{
- return __builtin_shufflevector(in, in, 0, 1);
+ return __builtin_shufflevector(__in, __in, 0, 1);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd128_pd256(__m128d in)
+_mm256_castpd128_pd256(__m128d __in)
{
- __m128d zero = _mm_setzero_pd();
- return __builtin_shufflevector(in, zero, 0, 1, 2, 2);
+ __m128d __zero = _mm_setzero_pd();
+ return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_castps128_ps256(__m128 in)
+_mm256_castps128_ps256(__m128 __in)
{
- __m128 zero = _mm_setzero_ps();
- return __builtin_shufflevector(in, zero, 0, 1, 2, 3, 4, 4, 4, 4);
+ __m128 __zero = _mm_setzero_ps();
+ return __builtin_shufflevector(__in, __zero, 0, 1, 2, 3, 4, 4, 4, 4);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi128_si256(__m128i in)
+_mm256_castsi128_si256(__m128i __in)
{
- __m128i zero = _mm_setzero_si128();
- return __builtin_shufflevector(in, zero, 0, 1, 2, 2);
+ __m128i __zero = _mm_setzero_si128();
+ return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2);
}
/* SIMD load ops (unaligned) */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu2_m128(float const *addr_hi, float const *addr_lo)
+_mm256_loadu2_m128(float const *__addr_hi, float const *__addr_lo)
{
struct __loadu_ps {
- __m128 v;
+ __m128 __v;
} __attribute__((__packed__, __may_alias__));
- __m256 v256 = _mm256_castps128_ps256(((struct __loadu_ps*)addr_lo)->v);
- return _mm256_insertf128_ps(v256, ((struct __loadu_ps*)addr_hi)->v, 1);
+ __m256 __v256 = _mm256_castps128_ps256(((struct __loadu_ps*)__addr_lo)->__v);
+ return _mm256_insertf128_ps(__v256, ((struct __loadu_ps*)__addr_hi)->__v, 1);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu2_m128d(double const *addr_hi, double const *addr_lo)
+_mm256_loadu2_m128d(double const *__addr_hi, double const *__addr_lo)
{
struct __loadu_pd {
- __m128d v;
+ __m128d __v;
} __attribute__((__packed__, __may_alias__));
- __m256d v256 = _mm256_castpd128_pd256(((struct __loadu_pd*)addr_lo)->v);
- return _mm256_insertf128_pd(v256, ((struct __loadu_pd*)addr_hi)->v, 1);
+ __m256d __v256 = _mm256_castpd128_pd256(((struct __loadu_pd*)__addr_lo)->__v);
+ return _mm256_insertf128_pd(__v256, ((struct __loadu_pd*)__addr_hi)->__v, 1);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu2_m128i(__m128i const *addr_hi, __m128i const *addr_lo)
+_mm256_loadu2_m128i(__m128i const *__addr_hi, __m128i const *__addr_lo)
{
struct __loadu_si128 {
- __m128i v;
+ __m128i __v;
} __attribute__((packed, may_alias));
- __m256i v256 = _mm256_castsi128_si256(((struct __loadu_si128*)addr_lo)->v);
- return _mm256_insertf128_si256(v256, ((struct __loadu_si128*)addr_hi)->v, 1);
+ __m256i __v256 = _mm256_castsi128_si256(
+ ((struct __loadu_si128*)__addr_lo)->__v);
+ return _mm256_insertf128_si256(__v256,
+ ((struct __loadu_si128*)__addr_hi)->__v, 1);
}
/* SIMD store ops (unaligned) */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu2_m128(float *addr_hi, float *addr_lo, __m256 a)
+_mm256_storeu2_m128(float *__addr_hi, float *__addr_lo, __m256 __a)
{
- __m128 v128;
+ __m128 __v128;
- v128 = _mm256_castps256_ps128(a);
- __builtin_ia32_storeups(addr_lo, v128);
- v128 = _mm256_extractf128_ps(a, 1);
- __builtin_ia32_storeups(addr_hi, v128);
+ __v128 = _mm256_castps256_ps128(__a);
+ __builtin_ia32_storeups(__addr_lo, __v128);
+ __v128 = _mm256_extractf128_ps(__a, 1);
+ __builtin_ia32_storeups(__addr_hi, __v128);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu2_m128d(double *addr_hi, double *addr_lo, __m256d a)
+_mm256_storeu2_m128d(double *__addr_hi, double *__addr_lo, __m256d __a)
{
- __m128d v128;
+ __m128d __v128;
- v128 = _mm256_castpd256_pd128(a);
- __builtin_ia32_storeupd(addr_lo, v128);
- v128 = _mm256_extractf128_pd(a, 1);
- __builtin_ia32_storeupd(addr_hi, v128);
+ __v128 = _mm256_castpd256_pd128(__a);
+ __builtin_ia32_storeupd(__addr_lo, __v128);
+ __v128 = _mm256_extractf128_pd(__a, 1);
+ __builtin_ia32_storeupd(__addr_hi, __v128);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu2_m128i(__m128i *addr_hi, __m128i *addr_lo, __m256i a)
+_mm256_storeu2_m128i(__m128i *__addr_hi, __m128i *__addr_lo, __m256i __a)
{
- __m128i v128;
+ __m128i __v128;
- v128 = _mm256_castsi256_si128(a);
- __builtin_ia32_storedqu((char *)addr_lo, (__v16qi)v128);
- v128 = _mm256_extractf128_si256(a, 1);
- __builtin_ia32_storedqu((char *)addr_hi, (__v16qi)v128);
+ __v128 = _mm256_castsi256_si128(__a);
+ __builtin_ia32_storedqu((char *)__addr_lo, (__v16qi)__v128);
+ __v128 = _mm256_extractf128_si256(__a, 1);
+ __builtin_ia32_storedqu((char *)__addr_hi, (__v16qi)__v128);
}
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 33df7c2d19f0..7b012384a2aa 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -25,9 +25,10 @@
#error this header is for x86 only
#endif
-static inline int __get_cpuid (unsigned int level, unsigned int *eax,
- unsigned int *ebx, unsigned int *ecx,
- unsigned int *edx) {
- __asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level));
+static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax,
+ unsigned int *__ebx, unsigned int *__ecx,
+ unsigned int *__edx) {
+ __asm("cpuid" : "=a"(*__eax), "=b" (*__ebx), "=c"(*__ecx), "=d"(*__edx)
+ : "0"(__level));
return 1;
}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 91395ed16f7f..e18fae40eced 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -40,507 +40,507 @@ typedef short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __attribute__((__vector_size__(16)));
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_add_sd(__m128d a, __m128d b)
+_mm_add_sd(__m128d __a, __m128d __b)
{
- a[0] += b[0];
- return a;
+ __a[0] += __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_add_pd(__m128d a, __m128d b)
+_mm_add_pd(__m128d __a, __m128d __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sub_sd(__m128d a, __m128d b)
+_mm_sub_sd(__m128d __a, __m128d __b)
{
- a[0] -= b[0];
- return a;
+ __a[0] -= __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sub_pd(__m128d a, __m128d b)
+_mm_sub_pd(__m128d __a, __m128d __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_mul_sd(__m128d a, __m128d b)
+_mm_mul_sd(__m128d __a, __m128d __b)
{
- a[0] *= b[0];
- return a;
+ __a[0] *= __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_mul_pd(__m128d a, __m128d b)
+_mm_mul_pd(__m128d __a, __m128d __b)
{
- return a * b;
+ return __a * __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_div_sd(__m128d a, __m128d b)
+_mm_div_sd(__m128d __a, __m128d __b)
{
- a[0] /= b[0];
- return a;
+ __a[0] /= __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_div_pd(__m128d a, __m128d b)
+_mm_div_pd(__m128d __a, __m128d __b)
{
- return a / b;
+ return __a / __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_sd(__m128d a, __m128d b)
+_mm_sqrt_sd(__m128d __a, __m128d __b)
{
- __m128d c = __builtin_ia32_sqrtsd(b);
- return (__m128d) { c[0], a[1] };
+ __m128d __c = __builtin_ia32_sqrtsd(__b);
+ return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_pd(__m128d a)
+_mm_sqrt_pd(__m128d __a)
{
- return __builtin_ia32_sqrtpd(a);
+ return __builtin_ia32_sqrtpd(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_min_sd(__m128d a, __m128d b)
+_mm_min_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_minsd(a, b);
+ return __builtin_ia32_minsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_min_pd(__m128d a, __m128d b)
+_mm_min_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_minpd(a, b);
+ return __builtin_ia32_minpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_max_sd(__m128d a, __m128d b)
+_mm_max_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_maxsd(a, b);
+ return __builtin_ia32_maxsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_max_pd(__m128d a, __m128d b)
+_mm_max_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_maxpd(a, b);
+ return __builtin_ia32_maxpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_and_pd(__m128d a, __m128d b)
+_mm_and_pd(__m128d __a, __m128d __b)
{
- return (__m128d)((__v4si)a & (__v4si)b);
+ return (__m128d)((__v4si)__a & (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_andnot_pd(__m128d a, __m128d b)
+_mm_andnot_pd(__m128d __a, __m128d __b)
{
- return (__m128d)(~(__v4si)a & (__v4si)b);
+ return (__m128d)(~(__v4si)__a & (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_or_pd(__m128d a, __m128d b)
+_mm_or_pd(__m128d __a, __m128d __b)
{
- return (__m128d)((__v4si)a | (__v4si)b);
+ return (__m128d)((__v4si)__a | (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_xor_pd(__m128d a, __m128d b)
+_mm_xor_pd(__m128d __a, __m128d __b)
{
- return (__m128d)((__v4si)a ^ (__v4si)b);
+ return (__m128d)((__v4si)__a ^ (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_pd(__m128d a, __m128d b)
+_mm_cmpeq_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 0);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_pd(__m128d a, __m128d b)
+_mm_cmplt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 1);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_pd(__m128d a, __m128d b)
+_mm_cmple_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 2);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_pd(__m128d a, __m128d b)
+_mm_cmpgt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 1);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_pd(__m128d a, __m128d b)
+_mm_cmpge_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 2);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_pd(__m128d a, __m128d b)
+_mm_cmpord_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 7);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 7);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_pd(__m128d a, __m128d b)
+_mm_cmpunord_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 3);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 3);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_pd(__m128d a, __m128d b)
+_mm_cmpneq_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 4);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 4);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_pd(__m128d a, __m128d b)
+_mm_cmpnlt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 5);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_pd(__m128d a, __m128d b)
+_mm_cmpnle_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 6);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 6);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_pd(__m128d a, __m128d b)
+_mm_cmpngt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 5);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_pd(__m128d a, __m128d b)
+_mm_cmpnge_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 6);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 6);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_sd(__m128d a, __m128d b)
+_mm_cmpeq_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 0);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_sd(__m128d a, __m128d b)
+_mm_cmplt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 1);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_sd(__m128d a, __m128d b)
+_mm_cmple_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 2);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_sd(__m128d a, __m128d b)
+_mm_cmpgt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 1);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_sd(__m128d a, __m128d b)
+_mm_cmpge_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 2);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_sd(__m128d a, __m128d b)
+_mm_cmpord_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 7);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 7);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_sd(__m128d a, __m128d b)
+_mm_cmpunord_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 3);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 3);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_sd(__m128d a, __m128d b)
+_mm_cmpneq_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 4);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 4);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_sd(__m128d a, __m128d b)
+_mm_cmpnlt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 5);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_sd(__m128d a, __m128d b)
+_mm_cmpnle_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 6);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 6);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_sd(__m128d a, __m128d b)
+_mm_cmpngt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 5);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_sd(__m128d a, __m128d b)
+_mm_cmpnge_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 6);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 6);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comieq_sd(__m128d a, __m128d b)
+_mm_comieq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdeq(a, b);
+ return __builtin_ia32_comisdeq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comilt_sd(__m128d a, __m128d b)
+_mm_comilt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdlt(a, b);
+ return __builtin_ia32_comisdlt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comile_sd(__m128d a, __m128d b)
+_mm_comile_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdle(a, b);
+ return __builtin_ia32_comisdle(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comigt_sd(__m128d a, __m128d b)
+_mm_comigt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdgt(a, b);
+ return __builtin_ia32_comisdgt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comige_sd(__m128d a, __m128d b)
+_mm_comige_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdge(a, b);
+ return __builtin_ia32_comisdge(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comineq_sd(__m128d a, __m128d b)
+_mm_comineq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdneq(a, b);
+ return __builtin_ia32_comisdneq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomieq_sd(__m128d a, __m128d b)
+_mm_ucomieq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdeq(a, b);
+ return __builtin_ia32_ucomisdeq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomilt_sd(__m128d a, __m128d b)
+_mm_ucomilt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdlt(a, b);
+ return __builtin_ia32_ucomisdlt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomile_sd(__m128d a, __m128d b)
+_mm_ucomile_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdle(a, b);
+ return __builtin_ia32_ucomisdle(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomigt_sd(__m128d a, __m128d b)
+_mm_ucomigt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdgt(a, b);
+ return __builtin_ia32_ucomisdgt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomige_sd(__m128d a, __m128d b)
+_mm_ucomige_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdge(a, b);
+ return __builtin_ia32_ucomisdge(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomineq_sd(__m128d a, __m128d b)
+_mm_ucomineq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdneq(a, b);
+ return __builtin_ia32_ucomisdneq(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpd_ps(__m128d a)
+_mm_cvtpd_ps(__m128d __a)
{
- return __builtin_ia32_cvtpd2ps(a);
+ return __builtin_ia32_cvtpd2ps(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pd(__m128 a)
+_mm_cvtps_pd(__m128 __a)
{
- return __builtin_ia32_cvtps2pd(a);
+ return __builtin_ia32_cvtps2pd(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtepi32_pd(__m128i a)
+_mm_cvtepi32_pd(__m128i __a)
{
- return __builtin_ia32_cvtdq2pd((__v4si)a);
+ return __builtin_ia32_cvtdq2pd((__v4si)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpd_epi32(__m128d a)
+_mm_cvtpd_epi32(__m128d __a)
{
- return __builtin_ia32_cvtpd2dq(a);
+ return __builtin_ia32_cvtpd2dq(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_si32(__m128d a)
+_mm_cvtsd_si32(__m128d __a)
{
- return __builtin_ia32_cvtsd2si(a);
+ return __builtin_ia32_cvtsd2si(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_ss(__m128 a, __m128d b)
+_mm_cvtsd_ss(__m128 __a, __m128d __b)
{
- a[0] = b[0];
- return a;
+ __a[0] = __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi32_sd(__m128d a, int b)
+_mm_cvtsi32_sd(__m128d __a, int __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_sd(__m128d a, __m128 b)
+_mm_cvtss_sd(__m128d __a, __m128 __b)
{
- a[0] = b[0];
- return a;
+ __a[0] = __b[0];
+ return __a;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvttpd_epi32(__m128d a)
+_mm_cvttpd_epi32(__m128d __a)
{
- return (__m128i)__builtin_ia32_cvttpd2dq(a);
+ return (__m128i)__builtin_ia32_cvttpd2dq(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvttsd_si32(__m128d a)
+_mm_cvttsd_si32(__m128d __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpd_pi32(__m128d a)
+_mm_cvtpd_pi32(__m128d __a)
{
- return (__m64)__builtin_ia32_cvtpd2pi(a);
+ return (__m64)__builtin_ia32_cvtpd2pi(__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvttpd_pi32(__m128d a)
+_mm_cvttpd_pi32(__m128d __a)
{
- return (__m64)__builtin_ia32_cvttpd2pi(a);
+ return (__m64)__builtin_ia32_cvttpd2pi(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi32_pd(__m64 a)
+_mm_cvtpi32_pd(__m64 __a)
{
- return __builtin_ia32_cvtpi2pd((__v2si)a);
+ return __builtin_ia32_cvtpi2pd((__v2si)__a);
}
static __inline__ double __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_f64(__m128d a)
+_mm_cvtsd_f64(__m128d __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_load_pd(double const *dp)
+_mm_load_pd(double const *__dp)
{
- return *(__m128d*)dp;
+ return *(__m128d*)__dp;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_load1_pd(double const *dp)
+_mm_load1_pd(double const *__dp)
{
struct __mm_load1_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_load1_pd_struct*)dp)->u;
- return (__m128d){ u, u };
+ double __u = ((struct __mm_load1_pd_struct*)__dp)->__u;
+ return (__m128d){ __u, __u };
}
#define _mm_load_pd1(dp) _mm_load1_pd(dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadr_pd(double const *dp)
+_mm_loadr_pd(double const *__dp)
{
- __m128d u = *(__m128d*)dp;
- return __builtin_shufflevector(u, u, 1, 0);
+ __m128d __u = *(__m128d*)__dp;
+ return __builtin_shufflevector(__u, __u, 1, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_pd(double const *dp)
+_mm_loadu_pd(double const *__dp)
{
struct __loadu_pd {
- __m128d v;
+ __m128d __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_pd*)dp)->v;
+ return ((struct __loadu_pd*)__dp)->__v;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_load_sd(double const *dp)
+_mm_load_sd(double const *__dp)
{
struct __mm_load_sd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_load_sd_struct*)dp)->u;
- return (__m128d){ u, 0 };
+ double __u = ((struct __mm_load_sd_struct*)__dp)->__u;
+ return (__m128d){ __u, 0 };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadh_pd(__m128d a, double const *dp)
+_mm_loadh_pd(__m128d __a, double const *__dp)
{
struct __mm_loadh_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_loadh_pd_struct*)dp)->u;
- return (__m128d){ a[0], u };
+ double __u = ((struct __mm_loadh_pd_struct*)__dp)->__u;
+ return (__m128d){ __a[0], __u };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_pd(__m128d a, double const *dp)
+_mm_loadl_pd(__m128d __a, double const *__dp)
{
struct __mm_loadl_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_loadl_pd_struct*)dp)->u;
- return (__m128d){ u, a[1] };
+ double __u = ((struct __mm_loadl_pd_struct*)__dp)->__u;
+ return (__m128d){ __u, __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_set_sd(double w)
+_mm_set_sd(double __w)
{
- return (__m128d){ w, 0 };
+ return (__m128d){ __w, 0 };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_set1_pd(double w)
+_mm_set1_pd(double __w)
{
- return (__m128d){ w, w };
+ return (__m128d){ __w, __w };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_set_pd(double w, double x)
+_mm_set_pd(double __w, double __x)
{
- return (__m128d){ x, w };
+ return (__m128d){ __x, __w };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pd(double w, double x)
+_mm_setr_pd(double __w, double __x)
{
- return (__m128d){ w, x };
+ return (__m128d){ __w, __x };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -550,275 +550,275 @@ _mm_setzero_pd(void)
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_move_sd(__m128d a, __m128d b)
+_mm_move_sd(__m128d __a, __m128d __b)
{
- return (__m128d){ b[0], a[1] };
+ return (__m128d){ __b[0], __a[1] };
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_sd(double *dp, __m128d a)
+_mm_store_sd(double *__dp, __m128d __a)
{
struct __mm_store_sd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_store_sd_struct*)dp)->u = a[0];
+ ((struct __mm_store_sd_struct*)__dp)->__u = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store1_pd(double *dp, __m128d a)
+_mm_store1_pd(double *__dp, __m128d __a)
{
struct __mm_store1_pd_struct {
- double u[2];
+ double __u[2];
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_store1_pd_struct*)dp)->u[0] = a[0];
- ((struct __mm_store1_pd_struct*)dp)->u[1] = a[0];
+ ((struct __mm_store1_pd_struct*)__dp)->__u[0] = __a[0];
+ ((struct __mm_store1_pd_struct*)__dp)->__u[1] = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_pd(double *dp, __m128d a)
+_mm_store_pd(double *__dp, __m128d __a)
{
- *(__m128d *)dp = a;
+ *(__m128d *)__dp = __a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeu_pd(double *dp, __m128d a)
+_mm_storeu_pd(double *__dp, __m128d __a)
{
- __builtin_ia32_storeupd(dp, a);
+ __builtin_ia32_storeupd(__dp, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storer_pd(double *dp, __m128d a)
+_mm_storer_pd(double *__dp, __m128d __a)
{
- a = __builtin_shufflevector(a, a, 1, 0);
- *(__m128d *)dp = a;
+ __a = __builtin_shufflevector(__a, __a, 1, 0);
+ *(__m128d *)__dp = __a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeh_pd(double *dp, __m128d a)
+_mm_storeh_pd(double *__dp, __m128d __a)
{
struct __mm_storeh_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_storeh_pd_struct*)dp)->u = a[1];
+ ((struct __mm_storeh_pd_struct*)__dp)->__u = __a[1];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storel_pd(double *dp, __m128d a)
+_mm_storel_pd(double *__dp, __m128d __a)
{
struct __mm_storeh_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_storeh_pd_struct*)dp)->u = a[0];
+ ((struct __mm_storeh_pd_struct*)__dp)->__u = __a[0];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi8(__m128i a, __m128i b)
+_mm_add_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)((__v16qi)a + (__v16qi)b);
+ return (__m128i)((__v16qi)__a + (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi16(__m128i a, __m128i b)
+_mm_add_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a + (__v8hi)b);
+ return (__m128i)((__v8hi)__a + (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi32(__m128i a, __m128i b)
+_mm_add_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a + (__v4si)b);
+ return (__m128i)((__v4si)__a + (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_add_si64(__m64 a, __m64 b)
+_mm_add_si64(__m64 __a, __m64 __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi64(__m128i a, __m128i b)
+_mm_add_epi64(__m128i __a, __m128i __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epi8(__m128i a, __m128i b)
+_mm_adds_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddsb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_paddsb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epi16(__m128i a, __m128i b)
+_mm_adds_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_paddsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epu8(__m128i a, __m128i b)
+_mm_adds_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddusb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_paddusb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epu16(__m128i a, __m128i b)
+_mm_adds_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddusw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_paddusw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_avg_epu8(__m128i a, __m128i b)
+_mm_avg_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pavgb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pavgb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_avg_epu16(__m128i a, __m128i b)
+_mm_avg_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pavgw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pavgw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_madd_epi16(__m128i a, __m128i b)
+_mm_madd_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_max_epi16(__m128i a, __m128i b)
+_mm_max_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_max_epu8(__m128i a, __m128i b)
+_mm_max_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaxub128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pmaxub128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_min_epi16(__m128i a, __m128i b)
+_mm_min_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pminsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pminsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_min_epu8(__m128i a, __m128i b)
+_mm_min_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pminub128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pminub128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mulhi_epi16(__m128i a, __m128i b)
+_mm_mulhi_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmulhw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmulhw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mulhi_epu16(__m128i a, __m128i b)
+_mm_mulhi_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mullo_epi16(__m128i a, __m128i b)
+_mm_mullo_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a * (__v8hi)b);
+ return (__m128i)((__v8hi)__a * (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_mul_su32(__m64 a, __m64 b)
+_mm_mul_su32(__m64 __a, __m64 __b)
{
- return __builtin_ia32_pmuludq((__v2si)a, (__v2si)b);
+ return __builtin_ia32_pmuludq((__v2si)__a, (__v2si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mul_epu32(__m128i a, __m128i b)
+_mm_mul_epu32(__m128i __a, __m128i __b)
{
- return __builtin_ia32_pmuludq128((__v4si)a, (__v4si)b);
+ return __builtin_ia32_pmuludq128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sad_epu8(__m128i a, __m128i b)
+_mm_sad_epu8(__m128i __a, __m128i __b)
{
- return __builtin_ia32_psadbw128((__v16qi)a, (__v16qi)b);
+ return __builtin_ia32_psadbw128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi8(__m128i a, __m128i b)
+_mm_sub_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)((__v16qi)a - (__v16qi)b);
+ return (__m128i)((__v16qi)__a - (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi16(__m128i a, __m128i b)
+_mm_sub_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a - (__v8hi)b);
+ return (__m128i)((__v8hi)__a - (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi32(__m128i a, __m128i b)
+_mm_sub_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a - (__v4si)b);
+ return (__m128i)((__v4si)__a - (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sub_si64(__m64 a, __m64 b)
+_mm_sub_si64(__m64 __a, __m64 __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi64(__m128i a, __m128i b)
+_mm_sub_epi64(__m128i __a, __m128i __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epi8(__m128i a, __m128i b)
+_mm_subs_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubsb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_psubsb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epi16(__m128i a, __m128i b)
+_mm_subs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_psubsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epu8(__m128i a, __m128i b)
+_mm_subs_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubusb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_psubusb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epu16(__m128i a, __m128i b)
+_mm_subs_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubusw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_psubusw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_and_si128(__m128i a, __m128i b)
+_mm_and_si128(__m128i __a, __m128i __b)
{
- return a & b;
+ return __a & __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_andnot_si128(__m128i a, __m128i b)
+_mm_andnot_si128(__m128i __a, __m128i __b)
{
- return ~a & b;
+ return ~__a & __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_or_si128(__m128i a, __m128i b)
+_mm_or_si128(__m128i __a, __m128i __b)
{
- return a | b;
+ return __a | __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_xor_si128(__m128i a, __m128i b)
+_mm_xor_si128(__m128i __a, __m128i __b)
{
- return a ^ b;
+ return __a ^ __b;
}
#define _mm_slli_si128(a, count) __extension__ ({ \
@@ -826,63 +826,63 @@ _mm_xor_si128(__m128i a, __m128i b)
(__m128i)__builtin_ia32_pslldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_slli_epi16(__m128i a, int count)
+_mm_slli_epi16(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psllwi128((__v8hi)a, count);
+ return (__m128i)__builtin_ia32_psllwi128((__v8hi)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sll_epi16(__m128i a, __m128i count)
+_mm_sll_epi16(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psllw128((__v8hi)a, (__v8hi)count);
+ return (__m128i)__builtin_ia32_psllw128((__v8hi)__a, (__v8hi)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_slli_epi32(__m128i a, int count)
+_mm_slli_epi32(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_pslldi128((__v4si)a, count);
+ return (__m128i)__builtin_ia32_pslldi128((__v4si)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sll_epi32(__m128i a, __m128i count)
+_mm_sll_epi32(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_pslld128((__v4si)a, (__v4si)count);
+ return (__m128i)__builtin_ia32_pslld128((__v4si)__a, (__v4si)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_slli_epi64(__m128i a, int count)
+_mm_slli_epi64(__m128i __a, int __count)
{
- return __builtin_ia32_psllqi128(a, count);
+ return __builtin_ia32_psllqi128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sll_epi64(__m128i a, __m128i count)
+_mm_sll_epi64(__m128i __a, __m128i __count)
{
- return __builtin_ia32_psllq128(a, count);
+ return __builtin_ia32_psllq128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srai_epi16(__m128i a, int count)
+_mm_srai_epi16(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psrawi128((__v8hi)a, count);
+ return (__m128i)__builtin_ia32_psrawi128((__v8hi)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sra_epi16(__m128i a, __m128i count)
+_mm_sra_epi16(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psraw128((__v8hi)a, (__v8hi)count);
+ return (__m128i)__builtin_ia32_psraw128((__v8hi)__a, (__v8hi)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srai_epi32(__m128i a, int count)
+_mm_srai_epi32(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psradi128((__v4si)a, count);
+ return (__m128i)__builtin_ia32_psradi128((__v4si)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sra_epi32(__m128i a, __m128i count)
+_mm_sra_epi32(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psrad128((__v4si)a, (__v4si)count);
+ return (__m128i)__builtin_ia32_psrad128((__v4si)__a, (__v4si)__count);
}
@@ -891,188 +891,188 @@ _mm_sra_epi32(__m128i a, __m128i count)
(__m128i)__builtin_ia32_psrldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srli_epi16(__m128i a, int count)
+_mm_srli_epi16(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psrlwi128((__v8hi)a, count);
+ return (__m128i)__builtin_ia32_psrlwi128((__v8hi)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srl_epi16(__m128i a, __m128i count)
+_mm_srl_epi16(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psrlw128((__v8hi)a, (__v8hi)count);
+ return (__m128i)__builtin_ia32_psrlw128((__v8hi)__a, (__v8hi)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srli_epi32(__m128i a, int count)
+_mm_srli_epi32(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psrldi128((__v4si)a, count);
+ return (__m128i)__builtin_ia32_psrldi128((__v4si)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srl_epi32(__m128i a, __m128i count)
+_mm_srl_epi32(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psrld128((__v4si)a, (__v4si)count);
+ return (__m128i)__builtin_ia32_psrld128((__v4si)__a, (__v4si)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srli_epi64(__m128i a, int count)
+_mm_srli_epi64(__m128i __a, int __count)
{
- return __builtin_ia32_psrlqi128(a, count);
+ return __builtin_ia32_psrlqi128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srl_epi64(__m128i a, __m128i count)
+_mm_srl_epi64(__m128i __a, __m128i __count)
{
- return __builtin_ia32_psrlq128(a, count);
+ return __builtin_ia32_psrlq128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_epi8(__m128i a, __m128i b)
+_mm_cmpeq_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)((__v16qi)a == (__v16qi)b);
+ return (__m128i)((__v16qi)__a == (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_epi16(__m128i a, __m128i b)
+_mm_cmpeq_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a == (__v8hi)b);
+ return (__m128i)((__v8hi)__a == (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_epi32(__m128i a, __m128i b)
+_mm_cmpeq_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a == (__v4si)b);
+ return (__m128i)((__v4si)__a == (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_epi8(__m128i a, __m128i b)
+_mm_cmpgt_epi8(__m128i __a, __m128i __b)
{
/* This function always performs a signed comparison, but __v16qi is a char
which may be signed or unsigned. */
typedef signed char __v16qs __attribute__((__vector_size__(16)));
- return (__m128i)((__v16qs)a > (__v16qs)b);
+ return (__m128i)((__v16qs)__a > (__v16qs)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_epi16(__m128i a, __m128i b)
+_mm_cmpgt_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a > (__v8hi)b);
+ return (__m128i)((__v8hi)__a > (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_epi32(__m128i a, __m128i b)
+_mm_cmpgt_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a > (__v4si)b);
+ return (__m128i)((__v4si)__a > (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_epi8(__m128i a, __m128i b)
+_mm_cmplt_epi8(__m128i __a, __m128i __b)
{
- return _mm_cmpgt_epi8(b,a);
+ return _mm_cmpgt_epi8(__b, __a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_epi16(__m128i a, __m128i b)
+_mm_cmplt_epi16(__m128i __a, __m128i __b)
{
- return _mm_cmpgt_epi16(b,a);
+ return _mm_cmpgt_epi16(__b, __a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_epi32(__m128i a, __m128i b)
+_mm_cmplt_epi32(__m128i __a, __m128i __b)
{
- return _mm_cmpgt_epi32(b,a);
+ return _mm_cmpgt_epi32(__b, __a);
}
#ifdef __x86_64__
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi64_sd(__m128d a, long long b)
+_mm_cvtsi64_sd(__m128d __a, long long __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_si64(__m128d a)
+_mm_cvtsd_si64(__m128d __a)
{
- return __builtin_ia32_cvtsd2si64(a);
+ return __builtin_ia32_cvtsd2si64(__a);
}
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvttsd_si64(__m128d a)
+_mm_cvttsd_si64(__m128d __a)
{
- return a[0];
+ return __a[0];
}
#endif
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtepi32_ps(__m128i a)
+_mm_cvtepi32_ps(__m128i __a)
{
- return __builtin_ia32_cvtdq2ps((__v4si)a);
+ return __builtin_ia32_cvtdq2ps((__v4si)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_epi32(__m128 a)
+_mm_cvtps_epi32(__m128 __a)
{
- return (__m128i)__builtin_ia32_cvtps2dq(a);
+ return (__m128i)__builtin_ia32_cvtps2dq(__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvttps_epi32(__m128 a)
+_mm_cvttps_epi32(__m128 __a)
{
- return (__m128i)__builtin_ia32_cvttps2dq(a);
+ return (__m128i)__builtin_ia32_cvttps2dq(__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi32_si128(int a)
+_mm_cvtsi32_si128(int __a)
{
- return (__m128i)(__v4si){ a, 0, 0, 0 };
+ return (__m128i)(__v4si){ __a, 0, 0, 0 };
}
#ifdef __x86_64__
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi64_si128(long long a)
+_mm_cvtsi64_si128(long long __a)
{
- return (__m128i){ a, 0 };
+ return (__m128i){ __a, 0 };
}
#endif
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi128_si32(__m128i a)
+_mm_cvtsi128_si32(__m128i __a)
{
- __v4si b = (__v4si)a;
- return b[0];
+ __v4si __b = (__v4si)__a;
+ return __b[0];
}
#ifdef __x86_64__
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi128_si64(__m128i a)
+_mm_cvtsi128_si64(__m128i __a)
{
- return a[0];
+ return __a[0];
}
#endif
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_load_si128(__m128i const *p)
+_mm_load_si128(__m128i const *__p)
{
- return *p;
+ return *__p;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_si128(__m128i const *p)
+_mm_loadu_si128(__m128i const *__p)
{
struct __loadu_si128 {
- __m128i v;
+ __m128i __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_si128*)p)->v;
+ return ((struct __loadu_si128*)__p)->__v;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_epi64(__m128i const *p)
+_mm_loadl_epi64(__m128i const *__p)
{
struct __mm_loadl_epi64_struct {
- long long u;
+ long long __u;
} __attribute__((__packed__, __may_alias__));
- return (__m128i) { ((struct __mm_loadl_epi64_struct*)p)->u, 0};
+ return (__m128i) { ((struct __mm_loadl_epi64_struct*)__p)->__u, 0};
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1106,33 +1106,33 @@ _mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi64x(long long q)
+_mm_set1_epi64x(long long __q)
{
- return (__m128i){ q, q };
+ return (__m128i){ __q, __q };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi64(__m64 q)
+_mm_set1_epi64(__m64 __q)
{
- return (__m128i){ (long long)q, (long long)q };
+ return (__m128i){ (long long)__q, (long long)__q };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi32(int i)
+_mm_set1_epi32(int __i)
{
- return (__m128i)(__v4si){ i, i, i, i };
+ return (__m128i)(__v4si){ __i, __i, __i, __i };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi16(short w)
+_mm_set1_epi16(short __w)
{
- return (__m128i)(__v8hi){ w, w, w, w, w, w, w, w };
+ return (__m128i)(__v8hi){ __w, __w, __w, __w, __w, __w, __w, __w };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi8(char b)
+_mm_set1_epi8(char __b)
{
- return (__m128i)(__v16qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b };
+ return (__m128i)(__v16qi){ __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1166,54 +1166,54 @@ _mm_setzero_si128(void)
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_si128(__m128i *p, __m128i b)
+_mm_store_si128(__m128i *__p, __m128i __b)
{
- *p = b;
+ *__p = __b;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeu_si128(__m128i *p, __m128i b)
+_mm_storeu_si128(__m128i *__p, __m128i __b)
{
- __builtin_ia32_storedqu((char *)p, (__v16qi)b);
+ __builtin_ia32_storedqu((char *)__p, (__v16qi)__b);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_maskmoveu_si128(__m128i d, __m128i n, char *p)
+_mm_maskmoveu_si128(__m128i __d, __m128i __n, char *__p)
{
- __builtin_ia32_maskmovdqu((__v16qi)d, (__v16qi)n, p);
+ __builtin_ia32_maskmovdqu((__v16qi)__d, (__v16qi)__n, __p);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storel_epi64(__m128i *p, __m128i a)
+_mm_storel_epi64(__m128i *__p, __m128i __a)
{
struct __mm_storel_epi64_struct {
- long long u;
+ long long __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_storel_epi64_struct*)p)->u = a[0];
+ ((struct __mm_storel_epi64_struct*)__p)->__u = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_pd(double *p, __m128d a)
+_mm_stream_pd(double *__p, __m128d __a)
{
- __builtin_ia32_movntpd(p, a);
+ __builtin_ia32_movntpd(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_si128(__m128i *p, __m128i a)
+_mm_stream_si128(__m128i *__p, __m128i __a)
{
- __builtin_ia32_movntdq(p, a);
+ __builtin_ia32_movntdq(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_si32(int *p, int a)
+_mm_stream_si32(int *__p, int __a)
{
- __builtin_ia32_movnti(p, a);
+ __builtin_ia32_movnti(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_clflush(void const *p)
+_mm_clflush(void const *__p)
{
- __builtin_ia32_clflush(p);
+ __builtin_ia32_clflush(__p);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
@@ -1229,42 +1229,42 @@ _mm_mfence(void)
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_packs_epi16(__m128i a, __m128i b)
+_mm_packs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_packsswb128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_packsswb128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_packs_epi32(__m128i a, __m128i b)
+_mm_packs_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_packssdw128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_packssdw128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_packus_epi16(__m128i a, __m128i b)
+_mm_packus_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_packuswb128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_packuswb128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_extract_epi16(__m128i a, int imm)
+_mm_extract_epi16(__m128i __a, int __imm)
{
- __v8hi b = (__v8hi)a;
- return (unsigned short)b[imm];
+ __v8hi __b = (__v8hi)__a;
+ return (unsigned short)__b[__imm];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_insert_epi16(__m128i a, int b, int imm)
+_mm_insert_epi16(__m128i __a, int __b, int __imm)
{
- __v8hi c = (__v8hi)a;
- c[imm & 7] = b;
- return (__m128i)c;
+ __v8hi __c = (__v8hi)__a;
+ __c[__imm & 7] = __b;
+ return (__m128i)__c;
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_epi8(__m128i a)
+_mm_movemask_epi8(__m128i __a)
{
- return __builtin_ia32_pmovmskb128((__v16qi)a);
+ return __builtin_ia32_pmovmskb128((__v16qi)__a);
}
#define _mm_shuffle_epi32(a, imm) __extension__ ({ \
@@ -1290,87 +1290,87 @@ _mm_movemask_epi8(__m128i a)
4 + (((imm) & 0xc0) >> 6)); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi8(__m128i a, __m128i b)
+_mm_unpackhi_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
+ return (__m128i)__builtin_shufflevector((__v16qi)__a, (__v16qi)__b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi16(__m128i a, __m128i b)
+_mm_unpackhi_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
+ return (__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi)__b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi32(__m128i a, __m128i b)
+_mm_unpackhi_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 2, 4+2, 3, 4+3);
+ return (__m128i)__builtin_shufflevector((__v4si)__a, (__v4si)__b, 2, 4+2, 3, 4+3);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi64(__m128i a, __m128i b)
+_mm_unpackhi_epi64(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector(a, b, 1, 2+1);
+ return (__m128i)__builtin_shufflevector(__a, __b, 1, 2+1);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi8(__m128i a, __m128i b)
+_mm_unpacklo_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7);
+ return (__m128i)__builtin_shufflevector((__v16qi)__a, (__v16qi)__b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi16(__m128i a, __m128i b)
+_mm_unpacklo_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
+ return (__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi)__b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi32(__m128i a, __m128i b)
+_mm_unpacklo_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 0, 4+0, 1, 4+1);
+ return (__m128i)__builtin_shufflevector((__v4si)__a, (__v4si)__b, 0, 4+0, 1, 4+1);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi64(__m128i a, __m128i b)
+_mm_unpacklo_epi64(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector(a, b, 0, 2+0);
+ return (__m128i)__builtin_shufflevector(__a, __b, 0, 2+0);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_movepi64_pi64(__m128i a)
+_mm_movepi64_pi64(__m128i __a)
{
- return (__m64)a[0];
+ return (__m64)__a[0];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_movpi64_pi64(__m64 a)
+_mm_movpi64_pi64(__m64 __a)
{
- return (__m128i){ (long long)a, 0 };
+ return (__m128i){ (long long)__a, 0 };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_move_epi64(__m128i a)
+_mm_move_epi64(__m128i __a)
{
- return __builtin_shufflevector(a, (__m128i){ 0 }, 0, 2);
+ return __builtin_shufflevector(__a, (__m128i){ 0 }, 0, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_pd(__m128d a, __m128d b)
+_mm_unpackhi_pd(__m128d __a, __m128d __b)
{
- return __builtin_shufflevector(a, b, 1, 2+1);
+ return __builtin_shufflevector(__a, __b, 1, 2+1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_pd(__m128d a, __m128d b)
+_mm_unpacklo_pd(__m128d __a, __m128d __b)
{
- return __builtin_shufflevector(a, b, 0, 2+0);
+ return __builtin_shufflevector(__a, __b, 0, 2+0);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_pd(__m128d a)
+_mm_movemask_pd(__m128d __a)
{
- return __builtin_ia32_movmskpd(a);
+ return __builtin_ia32_movmskpd(__a);
}
#define _mm_shuffle_pd(a, b, i) __extension__ ({ \
@@ -1379,39 +1379,39 @@ _mm_movemask_pd(__m128d a)
__builtin_shufflevector(__a, __b, (i) & 1, (((i) & 2) >> 1) + 2); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_castpd_ps(__m128d in)
+_mm_castpd_ps(__m128d __in)
{
- return (__m128)in;
+ return (__m128)__in;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_castpd_si128(__m128d in)
+_mm_castpd_si128(__m128d __in)
{
- return (__m128i)in;
+ return (__m128i)__in;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_castps_pd(__m128 in)
+_mm_castps_pd(__m128 __in)
{
- return (__m128d)in;
+ return (__m128d)__in;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_castps_si128(__m128 in)
+_mm_castps_si128(__m128 __in)
{
- return (__m128i)in;
+ return (__m128i)__in;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_castsi128_ps(__m128i in)
+_mm_castsi128_ps(__m128i __in)
{
- return (__m128)in;
+ return (__m128)__in;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_castsi128_pd(__m128i in)
+_mm_castsi128_pd(__m128i __in)
{
- return (__m128d)in;
+ return (__m128d)__in;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
index 2c96952446d6..a6d7812a4696 100644
--- a/lib/Headers/f16cintrin.h
+++ b/lib/Headers/f16cintrin.h
@@ -1,6 +1,6 @@
/*===---- f16cintrin.h - F16C intrinsics ---------------------------------===
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * 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
@@ -44,15 +44,15 @@ typedef float __m256 __attribute__ ((__vector_size__ (32)));
(__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (imm)); })
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtph_ps(__m128i a)
+_mm_cvtph_ps(__m128i __a)
{
- return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)a);
+ return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtph_ps(__m128i a)
+_mm256_cvtph_ps(__m128i __a)
{
- return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)a);
+ return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)__a);
}
#endif /* __F16CINTRIN_H */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index cd733bfc71d3..fea7c3ba29f1 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -102,4 +102,13 @@ _rdrand64_step(unsigned long long *__p)
#include <rtmintrin.h>
#endif
+/* FIXME: check __HLE__ as well when HLE is supported. */
+#if defined (__RTM__)
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_xtest(void)
+{
+ return __builtin_ia32_xtest();
+}
+#endif
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/mm3dnow.h b/lib/Headers/mm3dnow.h
index d5236f81ef41..5242d99cbd75 100644
--- a/lib/Headers/mm3dnow.h
+++ b/lib/Headers/mm3dnow.h
@@ -25,6 +25,7 @@
#define _MM3DNOW_H_INCLUDED
#include <mmintrin.h>
+#include <prfchwintrin.h>
typedef float __v2sf __attribute__((__vector_size__(8)));
diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h
index 5fa176187227..305afd31adda 100644
--- a/lib/Headers/mm_malloc.h
+++ b/lib/Headers/mm_malloc.h
@@ -30,45 +30,45 @@
#include <malloc.h>
#else
#ifndef __cplusplus
-extern int posix_memalign(void **memptr, size_t alignment, size_t size);
+extern int posix_memalign(void **__memptr, size_t __alignment, size_t __size);
#else
// Some systems (e.g. those with GNU libc) declare posix_memalign with an
// exception specifier. Via an "egregious workaround" in
// Sema::CheckEquivalentExceptionSpec, Clang accepts the following as a valid
// redeclaration of glibc's declaration.
-extern "C" int posix_memalign(void **memptr, size_t alignment, size_t size);
+extern "C" int posix_memalign(void **__memptr, size_t __alignment, size_t __size);
#endif
#endif
#if !(defined(_WIN32) && defined(_mm_malloc))
static __inline__ void *__attribute__((__always_inline__, __nodebug__,
__malloc__))
-_mm_malloc(size_t size, size_t align)
+_mm_malloc(size_t __size, size_t __align)
{
- if (align == 1) {
- return malloc(size);
+ if (__align == 1) {
+ return malloc(__size);
}
- if (!(align & (align - 1)) && align < sizeof(void *))
- align = sizeof(void *);
+ if (!(__align & (__align - 1)) && __align < sizeof(void *))
+ __align = sizeof(void *);
- void *mallocedMemory;
+ void *__mallocedMemory;
#if defined(__MINGW32__)
- mallocedMemory = __mingw_aligned_malloc(size, align);
+ __mallocedMemory = __mingw_aligned_malloc(__size, __align);
#elif defined(_WIN32)
- mallocedMemory = _aligned_malloc(size, align);
+ __mallocedMemory = _aligned_malloc(__size, __align);
#else
- if (posix_memalign(&mallocedMemory, align, size))
+ if (posix_memalign(&__mallocedMemory, __align, __size))
return 0;
#endif
- return mallocedMemory;
+ return __mallocedMemory;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_free(void *p)
+_mm_free(void *__p)
{
- free(p);
+ free(__p);
}
#endif
diff --git a/lib/Headers/module.map b/lib/Headers/module.map
index b24bccc12056..aa219cb407c9 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.map
@@ -17,6 +17,7 @@ module _Builtin_intrinsics [system] {
}
explicit module cpuid {
+ requires x86
header "cpuid.h"
}
@@ -33,7 +34,6 @@ module _Builtin_intrinsics [system] {
explicit module sse {
requires sse
export mmx
- export * // note: for hackish <emmintrin.h> dependency
header "xmmintrin.h"
}
diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
index 5f9b097ba65f..6f1fc3294644 100644
--- a/lib/Headers/pmmintrin.h
+++ b/lib/Headers/pmmintrin.h
@@ -31,65 +31,65 @@
#include <emmintrin.h>
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_lddqu_si128(__m128i const *p)
+_mm_lddqu_si128(__m128i const *__p)
{
- return (__m128i)__builtin_ia32_lddqu((char const *)p);
+ return (__m128i)__builtin_ia32_lddqu((char const *)__p);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_addsub_ps(__m128 a, __m128 b)
+_mm_addsub_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_addsubps(a, b);
+ return __builtin_ia32_addsubps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_ps(__m128 a, __m128 b)
+_mm_hadd_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_haddps(a, b);
+ return __builtin_ia32_haddps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_ps(__m128 a, __m128 b)
+_mm_hsub_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_hsubps(a, b);
+ return __builtin_ia32_hsubps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_movehdup_ps(__m128 a)
+_mm_movehdup_ps(__m128 __a)
{
- return __builtin_shufflevector(a, a, 1, 1, 3, 3);
+ return __builtin_shufflevector(__a, __a, 1, 1, 3, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_moveldup_ps(__m128 a)
+_mm_moveldup_ps(__m128 __a)
{
- return __builtin_shufflevector(a, a, 0, 0, 2, 2);
+ return __builtin_shufflevector(__a, __a, 0, 0, 2, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_addsub_pd(__m128d a, __m128d b)
+_mm_addsub_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_addsubpd(a, b);
+ return __builtin_ia32_addsubpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_pd(__m128d a, __m128d b)
+_mm_hadd_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_haddpd(a, b);
+ return __builtin_ia32_haddpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_pd(__m128d a, __m128d b)
+_mm_hsub_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_hsubpd(a, b);
+ return __builtin_ia32_hsubpd(__a, __b);
}
#define _mm_loaddup_pd(dp) _mm_load1_pd(dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_movedup_pd(__m128d a)
+_mm_movedup_pd(__m128d __a)
{
- return __builtin_shufflevector(a, a, 0, 0);
+ return __builtin_shufflevector(__a, __a, 0, 0);
}
#define _MM_DENORMALS_ZERO_ON (0x0040)
@@ -101,15 +101,15 @@ _mm_movedup_pd(__m128d a)
#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_monitor(void const *p, unsigned extensions, unsigned hints)
+_mm_monitor(void const *__p, unsigned __extensions, unsigned __hints)
{
- __builtin_ia32_monitor((void *)p, extensions, hints);
+ __builtin_ia32_monitor((void *)__p, __extensions, __hints);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_mwait(unsigned extensions, unsigned hints)
+_mm_mwait(unsigned __extensions, unsigned __hints)
{
- __builtin_ia32_mwait(extensions, hints);
+ __builtin_ia32_mwait(__extensions, __hints);
}
#endif /* __SSE3__ */
diff --git a/lib/Headers/prfchwintrin.h b/lib/Headers/prfchwintrin.h
new file mode 100644
index 000000000000..2d529c66349c
--- /dev/null
+++ b/lib/Headers/prfchwintrin.h
@@ -0,0 +1,34 @@
+/*===---- prfchwintrin.h - PREFETCHW intrinsic -----------------------------===
+ *
+ * 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.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined(__X86INTRIN_H) && !defined(_MM3DNOW_H_INCLUDED)
+#error "Never use <prfchwintrin.h> directly; include <x86intrin.h> or <mm3dnow.h> instead."
+#endif
+
+#if defined(__PRFCHW__) || defined(__3dNOW__)
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_m_prefetchw(void *__P)
+{
+ __builtin_prefetch (__P, 1, 3 /* _MM_HINT_T0 */);
+}
+#endif
diff --git a/lib/Headers/rdseedintrin.h b/lib/Headers/rdseedintrin.h
new file mode 100644
index 000000000000..54aabd177a1d
--- /dev/null
+++ b/lib/Headers/rdseedintrin.h
@@ -0,0 +1,48 @@
+/*===---- rdseedintrin.h - RDSEED 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 __X86INTRIN_H
+#error "Never use <rdseedintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifdef __RDSEED__
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_rdseed16_step(unsigned short *__p)
+{
+ return __builtin_ia32_rdseed16_step(__p);
+}
+
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_rdseed32_step(unsigned int *__p)
+{
+ return __builtin_ia32_rdseed32_step(__p);
+}
+
+#ifdef __x86_64__
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_rdseed64_step(unsigned long long *__p)
+{
+ return __builtin_ia32_rdseed64_step(__p);
+}
+#endif
+#endif /* __RDSEED__ */
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 2fab50e4eb57..498f6f0dcd86 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -195,10 +195,10 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/* SSE4 Insertion and Extraction from XMM Register Instructions. */
#define _mm_insert_ps(X, Y, N) __builtin_ia32_insertps128((X), (Y), (N))
#define _mm_extract_ps(X, N) (__extension__ \
- ({ union { int i; float f; } __t; \
+ ({ union { int __i; float __f; } __t; \
__v4sf __a = (__v4sf)(X); \
- __t.f = __a[N]; \
- __t.i;}))
+ __t.__f = __a[N]; \
+ __t.__i;}))
/* Miscellaneous insert and extract macros. */
/* Extract a single-precision float from X at index N into D. */
diff --git a/lib/Headers/stdalign.h b/lib/Headers/stdalign.h
index e7fbfa0499fd..3738d1284f95 100644
--- a/lib/Headers/stdalign.h
+++ b/lib/Headers/stdalign.h
@@ -24,7 +24,12 @@
#ifndef __STDALIGN_H
#define __STDALIGN_H
+#ifndef __cplusplus
#define alignas _Alignas
+#define alignof _Alignof
+#endif
+
#define __alignas_is_defined 1
+#define __alignof_is_defined 1
#endif /* __STDALIGN_H */
diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h
index eb919b57bcb9..52962248f67f 100644
--- a/lib/Headers/stddef.h
+++ b/lib/Headers/stddef.h
@@ -26,17 +26,28 @@
#ifndef __STDDEF_H
#define __STDDEF_H
-#ifndef _PTRDIFF_T
+#if !defined(_PTRDIFF_T) || __has_feature(modules)
+/* Always define ptrdiff_t when modules are available. */
+#if !__has_feature(modules)
#define _PTRDIFF_T
-typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
#endif
-#ifndef _SIZE_T
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#endif
+
+#if !defined(_SIZE_T) || __has_feature(modules)
+/* Always define size_t when modules are available. */
+#if !__has_feature(modules)
#define _SIZE_T
-typedef __typeof__(sizeof(int)) size_t;
#endif
+typedef __SIZE_TYPE__ size_t;
+#endif
+
#ifndef __cplusplus
-#ifndef _WCHAR_T
+/* Always define wchar_t when modules are available. */
+#if !defined(_WCHAR_T) || __has_feature(modules)
+#if !__has_feature(modules)
#define _WCHAR_T
+#endif
typedef __WCHAR_TYPE__ wchar_t;
#endif
#endif
@@ -66,9 +77,12 @@ using ::std::nullptr_t;
/* 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 */
#if defined(__need_wint_t)
-#if !defined(_WINT_T)
+/* Always define wint_t when modules are available. */
+#if !defined(_WINT_T) || __has_feature(modules)
+#if !__has_feature(modules)
#define _WINT_T
+#endif
typedef __WINT_TYPE__ wint_t;
-#endif /* _WINT_T */
+#endif
#undef __need_wint_t
#endif /* __need_wint_t */
diff --git a/lib/Headers/stdnoreturn.h b/lib/Headers/stdnoreturn.h
new file mode 100644
index 000000000000..a7a301d7e0bd
--- /dev/null
+++ b/lib/Headers/stdnoreturn.h
@@ -0,0 +1,30 @@
+/*===---- stdnoreturn.h - Standard header for noreturn macro ---------------===
+ *
+ * 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 __STDNORETURN_H
+#define __STDNORETURN_H
+
+#define noreturn _Noreturn
+#define __noreturn_is_defined 1
+
+#endif /* __STDNORETURN_H */
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index a62c6cccd01a..4238f5b38934 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -31,39 +31,39 @@
#include <pmmintrin.h>
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_abs_pi8(__m64 a)
+_mm_abs_pi8(__m64 __a)
{
- return (__m64)__builtin_ia32_pabsb((__v8qi)a);
+ return (__m64)__builtin_ia32_pabsb((__v8qi)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_abs_epi8(__m128i a)
+_mm_abs_epi8(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsb128((__v16qi)a);
+ return (__m128i)__builtin_ia32_pabsb128((__v16qi)__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_abs_pi16(__m64 a)
+_mm_abs_pi16(__m64 __a)
{
- return (__m64)__builtin_ia32_pabsw((__v4hi)a);
+ return (__m64)__builtin_ia32_pabsw((__v4hi)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_abs_epi16(__m128i a)
+_mm_abs_epi16(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsw128((__v8hi)a);
+ return (__m128i)__builtin_ia32_pabsw128((__v8hi)__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_abs_pi32(__m64 a)
+_mm_abs_pi32(__m64 __a)
{
- return (__m64)__builtin_ia32_pabsd((__v2si)a);
+ return (__m64)__builtin_ia32_pabsd((__v2si)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_abs_epi32(__m128i a)
+_mm_abs_epi32(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsd128((__v4si)a);
+ return (__m128i)__builtin_ia32_pabsd128((__v4si)__a);
}
#define _mm_alignr_epi8(a, b, n) __extension__ ({ \
@@ -77,147 +77,147 @@ _mm_abs_epi32(__m128i a)
(__m64)__builtin_ia32_palignr((__v8qi)__a, (__v8qi)__b, (n)); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_epi16(__m128i a, __m128i b)
+_mm_hadd_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phaddw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phaddw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_epi32(__m128i a, __m128i b)
+_mm_hadd_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phaddd128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_phaddd128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_pi16(__m64 a, __m64 b)
+_mm_hadd_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phaddw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phaddw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_pi32(__m64 a, __m64 b)
+_mm_hadd_pi32(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phaddd((__v2si)a, (__v2si)b);
+ return (__m64)__builtin_ia32_phaddd((__v2si)__a, (__v2si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hadds_epi16(__m128i a, __m128i b)
+_mm_hadds_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phaddsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phaddsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hadds_pi16(__m64 a, __m64 b)
+_mm_hadds_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phaddsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phaddsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_epi16(__m128i a, __m128i b)
+_mm_hsub_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phsubw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phsubw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_epi32(__m128i a, __m128i b)
+_mm_hsub_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phsubd128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_phsubd128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_pi16(__m64 a, __m64 b)
+_mm_hsub_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phsubw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phsubw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_pi32(__m64 a, __m64 b)
+_mm_hsub_pi32(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phsubd((__v2si)a, (__v2si)b);
+ return (__m64)__builtin_ia32_phsubd((__v2si)__a, (__v2si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hsubs_epi16(__m128i a, __m128i b)
+_mm_hsubs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phsubsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phsubsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hsubs_pi16(__m64 a, __m64 b)
+_mm_hsubs_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phsubsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phsubsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_maddubs_epi16(__m128i a, __m128i b)
+_mm_maddubs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_maddubs_pi16(__m64 a, __m64 b)
+_mm_maddubs_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmaddubsw((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pmaddubsw((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mulhrs_epi16(__m128i a, __m128i b)
+_mm_mulhrs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_mulhrs_pi16(__m64 a, __m64 b)
+_mm_mulhrs_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmulhrsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pmulhrsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_shuffle_epi8(__m128i a, __m128i b)
+_mm_shuffle_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pshufb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pshufb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_shuffle_pi8(__m64 a, __m64 b)
+_mm_shuffle_pi8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pshufb((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pshufb((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sign_epi8(__m128i a, __m128i b)
+_mm_sign_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psignb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_psignb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sign_epi16(__m128i a, __m128i b)
+_mm_sign_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psignw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_psignw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sign_epi32(__m128i a, __m128i b)
+_mm_sign_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psignd128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_psignd128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sign_pi8(__m64 a, __m64 b)
+_mm_sign_pi8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psignb((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_psignb((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sign_pi16(__m64 a, __m64 b)
+_mm_sign_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psignw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_psignw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sign_pi32(__m64 a, __m64 b)
+_mm_sign_pi32(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psignd((__v2si)a, (__v2si)b);
+ return (__m64)__builtin_ia32_psignd((__v2si)__a, (__v2si)__b);
}
#endif /* __SSSE3__ */
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index 6520b8316f3d..e94fd70900cc 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -23,6 +23,9 @@
/* See "Data Definitions for libgcc_s" in the Linux Standard Base.*/
+#ifndef __CLANG_UNWIND_H
+#define __CLANG_UNWIND_H
+
#if __has_include_next(<unwind.h>)
/* Darwin and libunwind provide an unwind.h. If that's available, use
* it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE,
@@ -59,7 +62,9 @@ extern "C" {
/* It is a bit strange for a header to play with the visibility of the
symbols it declares, but this matches gcc's behavior and some programs
depend on it */
+#ifndef HIDE_EXPORTS
#pragma GCC visibility push(default)
+#endif
struct _Unwind_Context;
typedef enum {
@@ -79,46 +84,50 @@ typedef enum {
#ifdef __arm__
-typedef enum {
- _UVRSC_CORE = 0, /* integer register */
- _UVRSC_VFP = 1, /* vfp */
- _UVRSC_WMMXD = 3, /* Intel WMMX data register */
- _UVRSC_WMMXC = 4 /* Intel WMMX control register */
-} _Unwind_VRS_RegClass;
-
-typedef enum {
- _UVRSD_UINT32 = 0,
- _UVRSD_VFPX = 1,
- _UVRSD_UINT64 = 3,
- _UVRSD_FLOAT = 4,
- _UVRSD_DOUBLE = 5
-} _Unwind_VRS_DataRepresentation;
-
-typedef enum {
- _UVRSR_OK = 0,
- _UVRSR_NOT_IMPLEMENTED = 1,
- _UVRSR_FAILED = 2
-} _Unwind_VRS_Result;
-
-_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *context,
- _Unwind_VRS_RegClass regclass,
- uint32_t regno,
- _Unwind_VRS_DataRepresentation representation,
- void *valuep);
+typedef enum {
+ _UVRSC_CORE = 0, /* integer register */
+ _UVRSC_VFP = 1, /* vfp */
+ _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+ _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context,
+ _Unwind_VRS_RegClass __regclass,
+ uint32_t __regno,
+ _Unwind_VRS_DataRepresentation __representation,
+ void *__valuep);
#else
-uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
+uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
#endif
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
+#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
+#endif
#ifdef __cplusplus
}
#endif
#endif
+
+#endif /* __CLANG_UNWIND_H */
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 68ce106be308..94fbe2fe234d 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -46,6 +46,14 @@
#include <popcntintrin.h>
#endif
+#ifdef __RDSEED__
+#include <rdseedintrin.h>
+#endif
+
+#ifdef __PRFCHW__
+#include <prfchwintrin.h>
+#endif
+
#ifdef __SSE4A__
#include <ammintrin.h>
#endif
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index e2480ec7a0e3..8c5fc9528cf0 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -41,563 +41,563 @@ typedef float __m128 __attribute__((__vector_size__(16)));
#endif
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_add_ss(__m128 a, __m128 b)
+_mm_add_ss(__m128 __a, __m128 __b)
{
- a[0] += b[0];
- return a;
+ __a[0] += __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_add_ps(__m128 a, __m128 b)
+_mm_add_ps(__m128 __a, __m128 __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sub_ss(__m128 a, __m128 b)
+_mm_sub_ss(__m128 __a, __m128 __b)
{
- a[0] -= b[0];
- return a;
+ __a[0] -= __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sub_ps(__m128 a, __m128 b)
+_mm_sub_ps(__m128 __a, __m128 __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_mul_ss(__m128 a, __m128 b)
+_mm_mul_ss(__m128 __a, __m128 __b)
{
- a[0] *= b[0];
- return a;
+ __a[0] *= __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_mul_ps(__m128 a, __m128 b)
+_mm_mul_ps(__m128 __a, __m128 __b)
{
- return a * b;
+ return __a * __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_div_ss(__m128 a, __m128 b)
+_mm_div_ss(__m128 __a, __m128 __b)
{
- a[0] /= b[0];
- return a;
+ __a[0] /= __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_div_ps(__m128 a, __m128 b)
+_mm_div_ps(__m128 __a, __m128 __b)
{
- return a / b;
+ return __a / __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_ss(__m128 a)
+_mm_sqrt_ss(__m128 __a)
{
- __m128 c = __builtin_ia32_sqrtss(a);
- return (__m128) { c[0], a[1], a[2], a[3] };
+ __m128 __c = __builtin_ia32_sqrtss(__a);
+ return (__m128) { __c[0], __a[1], __a[2], __a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_ps(__m128 a)
+_mm_sqrt_ps(__m128 __a)
{
- return __builtin_ia32_sqrtps(a);
+ return __builtin_ia32_sqrtps(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rcp_ss(__m128 a)
+_mm_rcp_ss(__m128 __a)
{
- __m128 c = __builtin_ia32_rcpss(a);
- return (__m128) { c[0], a[1], a[2], a[3] };
+ __m128 __c = __builtin_ia32_rcpss(__a);
+ return (__m128) { __c[0], __a[1], __a[2], __a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rcp_ps(__m128 a)
+_mm_rcp_ps(__m128 __a)
{
- return __builtin_ia32_rcpps(a);
+ return __builtin_ia32_rcpps(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rsqrt_ss(__m128 a)
+_mm_rsqrt_ss(__m128 __a)
{
- __m128 c = __builtin_ia32_rsqrtss(a);
- return (__m128) { c[0], a[1], a[2], a[3] };
+ __m128 __c = __builtin_ia32_rsqrtss(__a);
+ return (__m128) { __c[0], __a[1], __a[2], __a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rsqrt_ps(__m128 a)
+_mm_rsqrt_ps(__m128 __a)
{
- return __builtin_ia32_rsqrtps(a);
+ return __builtin_ia32_rsqrtps(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_min_ss(__m128 a, __m128 b)
+_mm_min_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_minss(a, b);
+ return __builtin_ia32_minss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_min_ps(__m128 a, __m128 b)
+_mm_min_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_minps(a, b);
+ return __builtin_ia32_minps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_max_ss(__m128 a, __m128 b)
+_mm_max_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_maxss(a, b);
+ return __builtin_ia32_maxss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_max_ps(__m128 a, __m128 b)
+_mm_max_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_maxps(a, b);
+ return __builtin_ia32_maxps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_and_ps(__m128 a, __m128 b)
+_mm_and_ps(__m128 __a, __m128 __b)
{
- return (__m128)((__v4si)a & (__v4si)b);
+ return (__m128)((__v4si)__a & (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_andnot_ps(__m128 a, __m128 b)
+_mm_andnot_ps(__m128 __a, __m128 __b)
{
- return (__m128)(~(__v4si)a & (__v4si)b);
+ return (__m128)(~(__v4si)__a & (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_or_ps(__m128 a, __m128 b)
+_mm_or_ps(__m128 __a, __m128 __b)
{
- return (__m128)((__v4si)a | (__v4si)b);
+ return (__m128)((__v4si)__a | (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_xor_ps(__m128 a, __m128 b)
+_mm_xor_ps(__m128 __a, __m128 __b)
{
- return (__m128)((__v4si)a ^ (__v4si)b);
+ return (__m128)((__v4si)__a ^ (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_ss(__m128 a, __m128 b)
+_mm_cmpeq_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 0);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 0);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_ps(__m128 a, __m128 b)
+_mm_cmpeq_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 0);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 0);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_ss(__m128 a, __m128 b)
+_mm_cmplt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 1);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_ps(__m128 a, __m128 b)
+_mm_cmplt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 1);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_ss(__m128 a, __m128 b)
+_mm_cmple_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 2);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_ps(__m128 a, __m128 b)
+_mm_cmple_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 2);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_ss(__m128 a, __m128 b)
+_mm_cmpgt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 1);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_ps(__m128 a, __m128 b)
+_mm_cmpgt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 1);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_ss(__m128 a, __m128 b)
+_mm_cmpge_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 2);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_ps(__m128 a, __m128 b)
+_mm_cmpge_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 2);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_ss(__m128 a, __m128 b)
+_mm_cmpneq_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 4);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 4);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_ps(__m128 a, __m128 b)
+_mm_cmpneq_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 4);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 4);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_ss(__m128 a, __m128 b)
+_mm_cmpnlt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 5);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_ps(__m128 a, __m128 b)
+_mm_cmpnlt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 5);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_ss(__m128 a, __m128 b)
+_mm_cmpnle_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 6);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_ps(__m128 a, __m128 b)
+_mm_cmpnle_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 6);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_ss(__m128 a, __m128 b)
+_mm_cmpngt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 5);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_ps(__m128 a, __m128 b)
+_mm_cmpngt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 5);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_ss(__m128 a, __m128 b)
+_mm_cmpnge_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 6);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_ps(__m128 a, __m128 b)
+_mm_cmpnge_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 6);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_ss(__m128 a, __m128 b)
+_mm_cmpord_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 7);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 7);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_ps(__m128 a, __m128 b)
+_mm_cmpord_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 7);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 7);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_ss(__m128 a, __m128 b)
+_mm_cmpunord_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 3);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_ps(__m128 a, __m128 b)
+_mm_cmpunord_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 3);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 3);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comieq_ss(__m128 a, __m128 b)
+_mm_comieq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comieq(a, b);
+ return __builtin_ia32_comieq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comilt_ss(__m128 a, __m128 b)
+_mm_comilt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comilt(a, b);
+ return __builtin_ia32_comilt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comile_ss(__m128 a, __m128 b)
+_mm_comile_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comile(a, b);
+ return __builtin_ia32_comile(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comigt_ss(__m128 a, __m128 b)
+_mm_comigt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comigt(a, b);
+ return __builtin_ia32_comigt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comige_ss(__m128 a, __m128 b)
+_mm_comige_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comige(a, b);
+ return __builtin_ia32_comige(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comineq_ss(__m128 a, __m128 b)
+_mm_comineq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comineq(a, b);
+ return __builtin_ia32_comineq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomieq_ss(__m128 a, __m128 b)
+_mm_ucomieq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomieq(a, b);
+ return __builtin_ia32_ucomieq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomilt_ss(__m128 a, __m128 b)
+_mm_ucomilt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomilt(a, b);
+ return __builtin_ia32_ucomilt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomile_ss(__m128 a, __m128 b)
+_mm_ucomile_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomile(a, b);
+ return __builtin_ia32_ucomile(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomigt_ss(__m128 a, __m128 b)
+_mm_ucomigt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomigt(a, b);
+ return __builtin_ia32_ucomigt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomige_ss(__m128 a, __m128 b)
+_mm_ucomige_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomige(a, b);
+ return __builtin_ia32_ucomige(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomineq_ss(__m128 a, __m128 b)
+_mm_ucomineq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomineq(a, b);
+ return __builtin_ia32_ucomineq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_si32(__m128 a)
+_mm_cvtss_si32(__m128 __a)
{
- return __builtin_ia32_cvtss2si(a);
+ return __builtin_ia32_cvtss2si(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_ss2si(__m128 a)
+_mm_cvt_ss2si(__m128 __a)
{
- return _mm_cvtss_si32(a);
+ return _mm_cvtss_si32(__a);
}
#ifdef __x86_64__
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_si64(__m128 a)
+_mm_cvtss_si64(__m128 __a)
{
- return __builtin_ia32_cvtss2si64(a);
+ return __builtin_ia32_cvtss2si64(__a);
}
#endif
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pi32(__m128 a)
+_mm_cvtps_pi32(__m128 __a)
{
- return (__m64)__builtin_ia32_cvtps2pi(a);
+ return (__m64)__builtin_ia32_cvtps2pi(__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_ps2pi(__m128 a)
+_mm_cvt_ps2pi(__m128 __a)
{
- return _mm_cvtps_pi32(a);
+ return _mm_cvtps_pi32(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvttss_si32(__m128 a)
+_mm_cvttss_si32(__m128 __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtt_ss2si(__m128 a)
+_mm_cvtt_ss2si(__m128 __a)
{
- return _mm_cvttss_si32(a);
+ return _mm_cvttss_si32(__a);
}
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvttss_si64(__m128 a)
+_mm_cvttss_si64(__m128 __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvttps_pi32(__m128 a)
+_mm_cvttps_pi32(__m128 __a)
{
- return (__m64)__builtin_ia32_cvttps2pi(a);
+ return (__m64)__builtin_ia32_cvttps2pi(__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtt_ps2pi(__m128 a)
+_mm_cvtt_ps2pi(__m128 __a)
{
- return _mm_cvttps_pi32(a);
+ return _mm_cvttps_pi32(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi32_ss(__m128 a, int b)
+_mm_cvtsi32_ss(__m128 __a, int __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_si2ss(__m128 a, int b)
+_mm_cvt_si2ss(__m128 __a, int __b)
{
- return _mm_cvtsi32_ss(a, b);
+ return _mm_cvtsi32_ss(__a, __b);
}
#ifdef __x86_64__
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi64_ss(__m128 a, long long b)
+_mm_cvtsi64_ss(__m128 __a, long long __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
#endif
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi32_ps(__m128 a, __m64 b)
+_mm_cvtpi32_ps(__m128 __a, __m64 __b)
{
- return __builtin_ia32_cvtpi2ps(a, (__v2si)b);
+ return __builtin_ia32_cvtpi2ps(__a, (__v2si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_pi2ps(__m128 a, __m64 b)
+_mm_cvt_pi2ps(__m128 __a, __m64 __b)
{
- return _mm_cvtpi32_ps(a, b);
+ return _mm_cvtpi32_ps(__a, __b);
}
static __inline__ float __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_f32(__m128 a)
+_mm_cvtss_f32(__m128 __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadh_pi(__m128 a, const __m64 *p)
+_mm_loadh_pi(__m128 __a, const __m64 *__p)
{
typedef float __mm_loadh_pi_v2f32 __attribute__((__vector_size__(8)));
struct __mm_loadh_pi_struct {
- __mm_loadh_pi_v2f32 u;
+ __mm_loadh_pi_v2f32 __u;
} __attribute__((__packed__, __may_alias__));
- __mm_loadh_pi_v2f32 b = ((struct __mm_loadh_pi_struct*)p)->u;
- __m128 bb = __builtin_shufflevector(b, b, 0, 1, 0, 1);
- return __builtin_shufflevector(a, bb, 0, 1, 4, 5);
+ __mm_loadh_pi_v2f32 __b = ((struct __mm_loadh_pi_struct*)__p)->__u;
+ __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1);
+ return __builtin_shufflevector(__a, __bb, 0, 1, 4, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_pi(__m128 a, const __m64 *p)
+_mm_loadl_pi(__m128 __a, const __m64 *__p)
{
typedef float __mm_loadl_pi_v2f32 __attribute__((__vector_size__(8)));
struct __mm_loadl_pi_struct {
- __mm_loadl_pi_v2f32 u;
+ __mm_loadl_pi_v2f32 __u;
} __attribute__((__packed__, __may_alias__));
- __mm_loadl_pi_v2f32 b = ((struct __mm_loadl_pi_struct*)p)->u;
- __m128 bb = __builtin_shufflevector(b, b, 0, 1, 0, 1);
- return __builtin_shufflevector(a, bb, 4, 5, 2, 3);
+ __mm_loadl_pi_v2f32 __b = ((struct __mm_loadl_pi_struct*)__p)->__u;
+ __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1);
+ return __builtin_shufflevector(__a, __bb, 4, 5, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ss(const float *p)
+_mm_load_ss(const float *__p)
{
struct __mm_load_ss_struct {
- float u;
+ float __u;
} __attribute__((__packed__, __may_alias__));
- float u = ((struct __mm_load_ss_struct*)p)->u;
- return (__m128){ u, 0, 0, 0 };
+ float __u = ((struct __mm_load_ss_struct*)__p)->__u;
+ return (__m128){ __u, 0, 0, 0 };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load1_ps(const float *p)
+_mm_load1_ps(const float *__p)
{
struct __mm_load1_ps_struct {
- float u;
+ float __u;
} __attribute__((__packed__, __may_alias__));
- float u = ((struct __mm_load1_ps_struct*)p)->u;
- return (__m128){ u, u, u, u };
+ float __u = ((struct __mm_load1_ps_struct*)__p)->__u;
+ return (__m128){ __u, __u, __u, __u };
}
#define _mm_load_ps1(p) _mm_load1_ps(p)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ps(const float *p)
+_mm_load_ps(const float *__p)
{
- return *(__m128*)p;
+ return *(__m128*)__p;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_ps(const float *p)
+_mm_loadu_ps(const float *__p)
{
struct __loadu_ps {
- __m128 v;
+ __m128 __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_ps*)p)->v;
+ return ((struct __loadu_ps*)__p)->__v;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadr_ps(const float *p)
+_mm_loadr_ps(const float *__p)
{
- __m128 a = _mm_load_ps(p);
- return __builtin_shufflevector(a, a, 3, 2, 1, 0);
+ __m128 __a = _mm_load_ps(__p);
+ return __builtin_shufflevector(__a, __a, 3, 2, 1, 0);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set_ss(float w)
+_mm_set_ss(float __w)
{
- return (__m128){ w, 0, 0, 0 };
+ return (__m128){ __w, 0, 0, 0 };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set1_ps(float w)
+_mm_set1_ps(float __w)
{
- return (__m128){ w, w, w, w };
+ return (__m128){ __w, __w, __w, __w };
}
// Microsoft specific.
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set_ps1(float w)
+_mm_set_ps1(float __w)
{
- return _mm_set1_ps(w);
+ return _mm_set1_ps(__w);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set_ps(float z, float y, float x, float w)
+_mm_set_ps(float __z, float __y, float __x, float __w)
{
- return (__m128){ w, x, y, z };
+ return (__m128){ __w, __x, __y, __z };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_ps(float z, float y, float x, float w)
+_mm_setr_ps(float __z, float __y, float __x, float __w)
{
- return (__m128){ z, y, x, w };
+ return (__m128){ __z, __y, __x, __w };
}
static __inline__ __m128 __attribute__((__always_inline__))
@@ -607,56 +607,56 @@ _mm_setzero_ps(void)
}
static __inline__ void __attribute__((__always_inline__))
-_mm_storeh_pi(__m64 *p, __m128 a)
+_mm_storeh_pi(__m64 *__p, __m128 __a)
{
- __builtin_ia32_storehps((__v2si *)p, a);
+ __builtin_ia32_storehps((__v2si *)__p, __a);
}
static __inline__ void __attribute__((__always_inline__))
-_mm_storel_pi(__m64 *p, __m128 a)
+_mm_storel_pi(__m64 *__p, __m128 __a)
{
- __builtin_ia32_storelps((__v2si *)p, a);
+ __builtin_ia32_storelps((__v2si *)__p, __a);
}
static __inline__ void __attribute__((__always_inline__))
-_mm_store_ss(float *p, __m128 a)
+_mm_store_ss(float *__p, __m128 __a)
{
struct __mm_store_ss_struct {
- float u;
+ float __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_store_ss_struct*)p)->u = a[0];
+ ((struct __mm_store_ss_struct*)__p)->__u = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeu_ps(float *p, __m128 a)
+_mm_storeu_ps(float *__p, __m128 __a)
{
- __builtin_ia32_storeups(p, a);
+ __builtin_ia32_storeups(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store1_ps(float *p, __m128 a)
+_mm_store1_ps(float *__p, __m128 __a)
{
- a = __builtin_shufflevector(a, a, 0, 0, 0, 0);
- _mm_storeu_ps(p, a);
+ __a = __builtin_shufflevector(__a, __a, 0, 0, 0, 0);
+ _mm_storeu_ps(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_ps1(float *p, __m128 a)
+_mm_store_ps1(float *__p, __m128 __a)
{
- return _mm_store1_ps(p, a);
+ return _mm_store1_ps(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_ps(float *p, __m128 a)
+_mm_store_ps(float *__p, __m128 __a)
{
- *(__m128 *)p = a;
+ *(__m128 *)__p = __a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storer_ps(float *p, __m128 a)
+_mm_storer_ps(float *__p, __m128 __a)
{
- a = __builtin_shufflevector(a, a, 3, 2, 1, 0);
- _mm_store_ps(p, a);
+ __a = __builtin_shufflevector(__a, __a, 3, 2, 1, 0);
+ _mm_store_ps(__p, __a);
}
#define _MM_HINT_T0 3
@@ -670,15 +670,15 @@ _mm_storer_ps(float *p, __m128 a)
#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel)))
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_pi(__m64 *p, __m64 a)
+_mm_stream_pi(__m64 *__p, __m64 __a)
{
- __builtin_ia32_movntq(p, a);
+ __builtin_ia32_movntq(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_ps(float *p, __m128 a)
+_mm_stream_ps(float *__p, __m128 __a)
{
- __builtin_ia32_movntps(p, a);
+ __builtin_ia32_movntps(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
@@ -688,54 +688,54 @@ _mm_sfence(void)
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_extract_pi16(__m64 a, int n)
+_mm_extract_pi16(__m64 __a, int __n)
{
- __v4hi b = (__v4hi)a;
- return (unsigned short)b[n & 3];
+ __v4hi __b = (__v4hi)__a;
+ return (unsigned short)__b[__n & 3];
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_insert_pi16(__m64 a, int d, int n)
+_mm_insert_pi16(__m64 __a, int __d, int __n)
{
- __v4hi b = (__v4hi)a;
- b[n & 3] = d;
- return (__m64)b;
+ __v4hi __b = (__v4hi)__a;
+ __b[__n & 3] = __d;
+ return (__m64)__b;
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_max_pi16(__m64 a, __m64 b)
+_mm_max_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmaxsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pmaxsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_max_pu8(__m64 a, __m64 b)
+_mm_max_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmaxub((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pmaxub((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_min_pi16(__m64 a, __m64 b)
+_mm_min_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pminsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pminsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_min_pu8(__m64 a, __m64 b)
+_mm_min_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pminub((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pminub((__v8qi)__a, (__v8qi)__b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_pi8(__m64 a)
+_mm_movemask_pi8(__m64 __a)
{
- return __builtin_ia32_pmovmskb((__v8qi)a);
+ return __builtin_ia32_pmovmskb((__v8qi)__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_mulhi_pu16(__m64 a, __m64 b)
+_mm_mulhi_pu16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pmulhuw((__v4hi)__a, (__v4hi)__b);
}
#define _mm_shuffle_pi16(a, n) __extension__ ({ \
@@ -743,27 +743,27 @@ _mm_mulhi_pu16(__m64 a, __m64 b)
(__m64)__builtin_ia32_pshufw((__v4hi)__a, (n)); })
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_maskmove_si64(__m64 d, __m64 n, char *p)
+_mm_maskmove_si64(__m64 __d, __m64 __n, char *__p)
{
- __builtin_ia32_maskmovq((__v8qi)d, (__v8qi)n, p);
+ __builtin_ia32_maskmovq((__v8qi)__d, (__v8qi)__n, __p);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_avg_pu8(__m64 a, __m64 b)
+_mm_avg_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pavgb((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pavgb((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_avg_pu16(__m64 a, __m64 b)
+_mm_avg_pu16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pavgw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pavgw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sad_pu8(__m64 a, __m64 b)
+_mm_sad_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psadbw((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_psadbw((__v8qi)__a, (__v8qi)__b);
}
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
@@ -773,9 +773,9 @@ _mm_getcsr(void)
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_setcsr(unsigned int i)
+_mm_setcsr(unsigned int __i)
{
- __builtin_ia32_ldmxcsr(i);
+ __builtin_ia32_ldmxcsr(__i);
}
#define _mm_shuffle_ps(a, b, mask) __extension__ ({ \
@@ -787,132 +787,132 @@ _mm_setcsr(unsigned int i)
(((mask) & 0xc0) >> 6) + 4); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_ps(__m128 a, __m128 b)
+_mm_unpackhi_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 2, 6, 3, 7);
+ return __builtin_shufflevector(__a, __b, 2, 6, 3, 7);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_ps(__m128 a, __m128 b)
+_mm_unpacklo_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 0, 4, 1, 5);
+ return __builtin_shufflevector(__a, __b, 0, 4, 1, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_move_ss(__m128 a, __m128 b)
+_mm_move_ss(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 4, 1, 2, 3);
+ return __builtin_shufflevector(__a, __b, 4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_movehl_ps(__m128 a, __m128 b)
+_mm_movehl_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 6, 7, 2, 3);
+ return __builtin_shufflevector(__a, __b, 6, 7, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_movelh_ps(__m128 a, __m128 b)
+_mm_movelh_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 0, 1, 4, 5);
+ return __builtin_shufflevector(__a, __b, 0, 1, 4, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi16_ps(__m64 a)
+_mm_cvtpi16_ps(__m64 __a)
{
- __m64 b, c;
- __m128 r;
+ __m64 __b, __c;
+ __m128 __r;
- b = _mm_setzero_si64();
- b = _mm_cmpgt_pi16(b, a);
- c = _mm_unpackhi_pi16(a, b);
- r = _mm_setzero_ps();
- r = _mm_cvtpi32_ps(r, c);
- r = _mm_movelh_ps(r, r);
- c = _mm_unpacklo_pi16(a, b);
- r = _mm_cvtpi32_ps(r, c);
+ __b = _mm_setzero_si64();
+ __b = _mm_cmpgt_pi16(__b, __a);
+ __c = _mm_unpackhi_pi16(__a, __b);
+ __r = _mm_setzero_ps();
+ __r = _mm_cvtpi32_ps(__r, __c);
+ __r = _mm_movelh_ps(__r, __r);
+ __c = _mm_unpacklo_pi16(__a, __b);
+ __r = _mm_cvtpi32_ps(__r, __c);
- return r;
+ return __r;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpu16_ps(__m64 a)
+_mm_cvtpu16_ps(__m64 __a)
{
- __m64 b, c;
- __m128 r;
+ __m64 __b, __c;
+ __m128 __r;
- b = _mm_setzero_si64();
- c = _mm_unpackhi_pi16(a, b);
- r = _mm_setzero_ps();
- r = _mm_cvtpi32_ps(r, c);
- r = _mm_movelh_ps(r, r);
- c = _mm_unpacklo_pi16(a, b);
- r = _mm_cvtpi32_ps(r, c);
+ __b = _mm_setzero_si64();
+ __c = _mm_unpackhi_pi16(__a, __b);
+ __r = _mm_setzero_ps();
+ __r = _mm_cvtpi32_ps(__r, __c);
+ __r = _mm_movelh_ps(__r, __r);
+ __c = _mm_unpacklo_pi16(__a, __b);
+ __r = _mm_cvtpi32_ps(__r, __c);
- return r;
+ return __r;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi8_ps(__m64 a)
+_mm_cvtpi8_ps(__m64 __a)
{
- __m64 b;
+ __m64 __b;
- b = _mm_setzero_si64();
- b = _mm_cmpgt_pi8(b, a);
- b = _mm_unpacklo_pi8(a, b);
+ __b = _mm_setzero_si64();
+ __b = _mm_cmpgt_pi8(__b, __a);
+ __b = _mm_unpacklo_pi8(__a, __b);
- return _mm_cvtpi16_ps(b);
+ return _mm_cvtpi16_ps(__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpu8_ps(__m64 a)
+_mm_cvtpu8_ps(__m64 __a)
{
- __m64 b;
+ __m64 __b;
- b = _mm_setzero_si64();
- b = _mm_unpacklo_pi8(a, b);
+ __b = _mm_setzero_si64();
+ __b = _mm_unpacklo_pi8(__a, __b);
- return _mm_cvtpi16_ps(b);
+ return _mm_cvtpi16_ps(__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi32x2_ps(__m64 a, __m64 b)
+_mm_cvtpi32x2_ps(__m64 __a, __m64 __b)
{
- __m128 c;
+ __m128 __c;
- c = _mm_setzero_ps();
- c = _mm_cvtpi32_ps(c, b);
- c = _mm_movelh_ps(c, c);
+ __c = _mm_setzero_ps();
+ __c = _mm_cvtpi32_ps(__c, __b);
+ __c = _mm_movelh_ps(__c, __c);
- return _mm_cvtpi32_ps(c, a);
+ return _mm_cvtpi32_ps(__c, __a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pi16(__m128 a)
+_mm_cvtps_pi16(__m128 __a)
{
- __m64 b, c;
+ __m64 __b, __c;
- b = _mm_cvtps_pi32(a);
- a = _mm_movehl_ps(a, a);
- c = _mm_cvtps_pi32(a);
+ __b = _mm_cvtps_pi32(__a);
+ __a = _mm_movehl_ps(__a, __a);
+ __c = _mm_cvtps_pi32(__a);
- return _mm_packs_pi16(b, c);
+ return _mm_packs_pi16(__b, __c);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pi8(__m128 a)
+_mm_cvtps_pi8(__m128 __a)
{
- __m64 b, c;
+ __m64 __b, __c;
- b = _mm_cvtps_pi16(a);
- c = _mm_setzero_si64();
+ __b = _mm_cvtps_pi16(__a);
+ __c = _mm_setzero_si64();
- return _mm_packs_pi16(b, c);
+ return _mm_packs_pi16(__b, __c);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_ps(__m128 a)
+_mm_movemask_ps(__m128 __a)
{
- return __builtin_ia32_movmskps(a);
+ return __builtin_ia32_movmskps(__a);
}
#define _MM_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
@@ -983,10 +983,12 @@ do { \
#define _m_ _mm_
#define _m_ _mm_
+#if !__has_feature(modules)
/* Ugly hack for backwards-compatibility (compatible with gcc) */
#ifdef __SSE2__
#include <emmintrin.h>
#endif
+#endif
#endif /* __SSE__ */
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
index 241abbc4bc68..2ee468294ae7 100644
--- a/lib/Lex/CMakeLists.txt
+++ b/lib/Lex/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangLex
ModuleMap.cpp
PPCaching.cpp
PPCallbacks.cpp
+ PPConditionalDirectiveRecord.cpp
PPDirectives.cpp
PPExpressions.cpp
PPLexerChange.cpp
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index 7dc0491392cc..dcf1f0c70c54 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#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 <cctype>
#include <cstdio>
using namespace clang;
@@ -62,7 +62,7 @@ static inline unsigned HashHMapKey(StringRef Str) {
const char *S = Str.begin(), *End = Str.end();
for (; S != End; S++)
- Result += tolower(*S) * 13;
+ Result += toLowercase(*S) * 13;
return Result;
}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 67000b682982..304bd6969a68 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -12,17 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/HeaderMap.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
+#include "clang/Lex/HeaderMap.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include <cstdio>
+#if defined(LLVM_ON_UNIX)
+#include <limits.h>
+#endif
using namespace clang;
const IdentifierInfo *
@@ -39,12 +42,12 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
-HeaderSearch::HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
FileManager &FM, DiagnosticsEngine &Diags,
const LangOptions &LangOpts,
const TargetInfo *Target)
: HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
- ModMap(FileMgr, *Diags.getClient(), LangOpts, Target)
+ ModMap(FileMgr, *Diags.getClient(), LangOpts, Target, *this)
{
AngledDirIdx = 0;
SystemDirIdx = 0;
@@ -134,7 +137,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
if (Module || !AllowSearch)
return Module;
- // Look through the various header search paths to load any avai;able module
+ // Look through the various header search paths to load any available module
// maps, searching for a module map that describes this module.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
if (SearchDirs[Idx].isFramework()) {
@@ -178,8 +181,22 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
if (Module)
break;
}
+
+ // If we've already performed the exhaustive search for module maps in this
+ // search directory, don't do it again.
+ if (SearchDirs[Idx].haveSearchedAllModuleMaps())
+ continue;
+
+ // Load all module maps in the immediate subdirectories of this search
+ // directory.
+ loadSubdirectoryModuleMaps(SearchDirs[Idx]);
+
+ // Look again for the module.
+ Module = ModMap.findModule(ModuleName);
+ if (Module)
+ break;
}
-
+
return Module;
}
@@ -263,6 +280,55 @@ const FileEntry *DirectoryLookup::LookupFile(
return Result;
}
+/// \brief Given a framework directory, find the top-most framework directory.
+///
+/// \param FileMgr The file manager to use for directory lookups.
+/// \param DirName The name of the framework directory.
+/// \param SubmodulePath Will be populated with the submodule path from the
+/// returned top-level module to the originally named framework.
+static const DirectoryEntry *
+getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
+ SmallVectorImpl<std::string> &SubmodulePath) {
+ assert(llvm::sys::path::extension(DirName) == ".framework" &&
+ "Not a framework directory");
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // frameworks moving between top-level frameworks to embedded frameworks tend
+ // to be symlinked, and we base the logical structure of modules on the
+ // physical layout. In particular, we need to deal with crazy includes like
+ //
+ // #include <Foo/Frameworks/Bar.framework/Headers/Wibble.h>
+ //
+ // where 'Bar' used to be embedded in 'Foo', is now a top-level framework
+ // which one should access with, e.g.,
+ //
+ // #include <Bar/Wibble.h>
+ //
+ // Similar issues occur when a top-level framework has moved into an
+ // embedded framework.
+ const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
+ DirName = FileMgr.getCanonicalName(TopFrameworkDir);
+ do {
+ // Get the parent directory name.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Determine whether this directory exists.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(DirName) == ".framework") {
+ SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+ TopFrameworkDir = Dir;
+ }
+ } while (true);
+
+ return TopFrameworkDir;
+}
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
@@ -334,17 +400,6 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
-
- // If we're allowed to look for modules, try to load or create the module
- // corresponding to this framework.
- Module *Module = 0;
- if (SuggestedModule) {
- if (const DirectoryEntry *FrameworkDir
- = FileMgr.getDirectory(FrameworkName)) {
- bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
- Module = HS.loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
- }
- }
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
unsigned OrigSize = FrameworkName.size();
@@ -357,28 +412,64 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
}
- // Determine whether this is the module we're building or not.
- bool AutomaticImport = Module;
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/!AutomaticImport)) {
- if (AutomaticImport)
- *SuggestedModule = HS.findModuleForHeader(FE);
- return FE;
+ const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ /*openFile=*/!SuggestedModule);
+ if (!FE) {
+ // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
+ const char *Private = "Private";
+ FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
+ Private+strlen(Private));
+ if (SearchPath != NULL)
+ SearchPath->insert(SearchPath->begin()+OrigSize, Private,
+ Private+strlen(Private));
+
+ FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule);
}
- // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
- const char *Private = "Private";
- FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
- Private+strlen(Private));
- if (SearchPath != NULL)
- SearchPath->insert(SearchPath->begin()+OrigSize, Private,
- Private+strlen(Private));
-
- const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/!AutomaticImport);
- if (FE && AutomaticImport)
- *SuggestedModule = HS.findModuleForHeader(FE);
+ // 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();
+ 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)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(FrameworkPath) == ".framework") {
+ FoundFramework = true;
+ break;
+ }
+ } while (true);
+
+ if (FoundFramework) {
+ // Find the top-level framework based on this framework.
+ SmallVector<std::string, 4> SubmodulePath;
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, FrameworkPath, SubmodulePath);
+
+ // Determine the name of the top-level framework.
+ StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+ // Load this framework module. If that succeeds, find the suggested module
+ // for this header, if any.
+ bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
+ if (HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
+ *SuggestedModule = HS.findModuleForHeader(FE);
+ }
+ } else {
+ *SuggestedModule = HS.findModuleForHeader(FE);
+ }
+ }
return FE;
}
@@ -584,7 +675,8 @@ const FileEntry *HeaderSearch::
LookupSubframeworkHeader(StringRef Filename,
const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath) {
+ SmallVectorImpl<char> *RelativePath,
+ Module **SuggestedModule) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
@@ -673,6 +765,26 @@ LookupSubframeworkHeader(StringRef Filename,
// of evaluation.
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
getFileInfo(FE).DirInfo = DirInfo;
+
+ // If we're supposed to suggest a module, look for one now.
+ if (SuggestedModule) {
+ // Find the top-level framework based on this framework.
+ FrameworkName.pop_back(); // remove the trailing '/'
+ SmallVector<std::string, 4> SubmodulePath;
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
+
+ // Determine the name of the top-level framework.
+ StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+ // Load this framework module. If that succeeds, find the suggested module
+ // for this header, if any.
+ bool IsSystem = false;
+ if (loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
+ *SuggestedModule = findModuleForHeader(FE);
+ }
+ }
+
return FE;
}
@@ -708,6 +820,7 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
const HeaderFileInfo &OtherHFI) {
HFI.isImport |= OtherHFI.isImport;
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
+ HFI.isModuleHeader |= OtherHFI.isModuleHeader;
HFI.NumIncludes += OtherHFI.NumIncludes;
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
@@ -749,7 +862,16 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
if (ExternalSource && !HFI.Resolved)
mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File));
- return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
+ return HFI.isPragmaOnce || HFI.isImport ||
+ HFI.ControllingMacro || HFI.ControllingMacroID;
+}
+
+void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE) {
+ if (FE->getUID() >= FileInfo.size())
+ FileInfo.resize(FE->getUID()+1);
+
+ HeaderFileInfo &HFI = FileInfo[FE->getUID()];
+ HFI.isModuleHeader = true;
}
void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
@@ -809,7 +931,7 @@ StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root) {
- llvm::SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
+ SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
StringRef DirName = FileName;
do {
@@ -849,7 +971,12 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
} while (true);
}
-Module *HeaderSearch::findModuleForHeader(const FileEntry *File) {
+Module *HeaderSearch::findModuleForHeader(const FileEntry *File) const {
+ if (ExternalSource) {
+ // Make sure the external source has handled header info about this file,
+ // which includes whether the file is part of a module.
+ (void)getFileInfo(File);
+ }
if (Module *Mod = ModMap.findModuleForHeader(File))
return Mod;
@@ -897,80 +1024,21 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
return ModMap.findModule(Name);
}
- // The top-level framework directory, from which we'll infer a framework
- // module.
- const DirectoryEntry *TopFrameworkDir = Dir;
-
- // The path from the module we're actually looking for back to the top-level
- // framework name.
- llvm::SmallVector<StringRef, 2> SubmodulePath;
+ // 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);
-
- // Walk the directory structure to find any enclosing frameworks.
-#ifdef LLVM_ON_UNIX
- // 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.
- char RealDirName[PATH_MAX];
- StringRef DirName;
- if (realpath(Dir->getName(), RealDirName))
- DirName = RealDirName;
- else
- DirName = Dir->getName();
-#else
- StringRef DirName = Dir->getName();
-#endif
- do {
- // Get the parent directory name.
- DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.empty())
- break;
-
- // Determine whether this directory exists.
- Dir = FileMgr.getDirectory(DirName);
- if (!Dir)
- break;
-
- // If this is a framework directory, then we're a subframework of this
- // framework.
- if (llvm::sys::path::extension(DirName) == ".framework") {
- SubmodulePath.push_back(llvm::sys::path::stem(DirName));
- TopFrameworkDir = Dir;
- }
- } while (true);
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, Dir->getName(), SubmodulePath);
- // Determine whether we're allowed to infer a module map.
- bool canInfer = false;
- if (llvm::sys::path::has_parent_path(TopFrameworkDir->getName())) {
- // Figure out the parent path.
- StringRef Parent = llvm::sys::path::parent_path(TopFrameworkDir->getName());
- if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
- // If there's a module map file in the parent directory, it can
- // explicitly allow us to infer framework modules.
- switch (loadModuleMapFile(ParentDir)) {
- case LMM_AlreadyLoaded:
- case LMM_NewlyLoaded: {
- StringRef Name = llvm::sys::path::stem(TopFrameworkDir->getName());
- canInfer = ModMap.canInferFrameworkModule(ParentDir, Name, IsSystem);
- break;
- }
- case LMM_InvalidModuleMap:
- case LMM_NoDirectory:
- break;
- }
- }
- }
-
- // If we're not allowed to infer a module map, we're done.
- if (!canInfer)
- return 0;
// 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.
@@ -1034,7 +1102,7 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
return LMM_InvalidModuleMap;
}
-void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
+void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
Modules.clear();
// Load module maps for each of the header search directories.
@@ -1072,13 +1140,7 @@ void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
// Try to load module map files for immediate subdirectories of this search
// directory.
- llvm::error_code EC;
- SmallString<128> DirNative;
- llvm::sys::path::native(SearchDirs[Idx].getDir()->getName(), DirNative);
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
- Dir != DirEnd && !EC; Dir.increment(EC)) {
- loadModuleMapFile(Dir->path());
- }
+ loadSubdirectoryModuleMaps(SearchDirs[Idx]);
}
// Populate the list of modules.
@@ -1088,3 +1150,18 @@ void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
Modules.push_back(M->getValue());
}
}
+
+void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
+ if (SearchDir.haveSearchedAllModuleMaps())
+ return;
+
+ llvm::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.setSearchedAllModuleMaps(true);
+}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a5ba7dbe0a93..ed4666aa2117 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -25,19 +25,21 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Lexer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "UnicodeCharSets.h"
#include <cstring>
using namespace clang;
-static void InitCharacterInfo();
-
//===----------------------------------------------------------------------===//
// Token Class Implementation
//===----------------------------------------------------------------------===//
@@ -64,8 +66,6 @@ void Lexer::anchor() { }
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
- InitCharacterInfo();
-
BufferStart = BufStart;
BufferPtr = BufPtr;
BufferEnd = BufEnd;
@@ -122,8 +122,15 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
InputFile->getBufferEnd());
- // Default to keeping comments if the preprocessor wants them.
- SetCommentRetentionState(PP.getCommentRetentionState());
+ resetExtendedTokenMode();
+}
+
+void Lexer::resetExtendedTokenMode() {
+ assert(PP && "Cannot reset token mode without a preprocessor");
+ if (LangOpts.TraditionalCPP)
+ SetKeepWhitespaceMode(true);
+ else
+ SetCommentRetentionState(PP->getCommentRetentionState());
}
/// Lexer constructor - Create a new raw lexer object. This object is only
@@ -233,16 +240,67 @@ void Lexer::Stringify(SmallVectorImpl<char> &Str) {
// Token Spelling
//===----------------------------------------------------------------------===//
+/// \brief Slow case of getSpelling. Extract the characters comprising the
+/// spelling of this token from the provided input buffer.
+static size_t getSpellingSlow(const Token &Tok, const char *BufPtr,
+ const LangOptions &LangOpts, char *Spelling) {
+ assert(Tok.needsCleaning() && "getSpellingSlow called on simple token");
+
+ size_t Length = 0;
+ const char *BufEnd = BufPtr + Tok.getLength();
+
+ if (Tok.is(tok::string_literal)) {
+ // Munch the encoding-prefix and opening double-quote.
+ while (BufPtr < BufEnd) {
+ unsigned Size;
+ Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts);
+ BufPtr += Size;
+
+ if (Spelling[Length - 1] == '"')
+ break;
+ }
+
+ // Raw string literals need special handling; trigraph expansion and line
+ // splicing do not occur within their d-char-sequence nor within their
+ // r-char-sequence.
+ if (Length >= 2 &&
+ Spelling[Length - 2] == 'R' && Spelling[Length - 1] == '"') {
+ // Search backwards from the end of the token to find the matching closing
+ // quote.
+ const char *RawEnd = BufEnd;
+ do --RawEnd; while (*RawEnd != '"');
+ size_t RawLength = RawEnd - BufPtr + 1;
+
+ // Everything between the quotes is included verbatim in the spelling.
+ memcpy(Spelling + Length, BufPtr, RawLength);
+ Length += RawLength;
+ BufPtr += RawLength;
+
+ // The rest of the token is lexed normally.
+ }
+ }
+
+ while (BufPtr < BufEnd) {
+ unsigned Size;
+ Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts);
+ BufPtr += Size;
+ }
+
+ assert(Length < Tok.getLength() &&
+ "NeedsCleaning flag set on token that didn't need cleaning!");
+ return Length;
+}
+
/// getSpelling() - Return the 'spelling' of this token. The spelling of a
/// token are the characters used to represent the token in the source file
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
StringRef Lexer::getSpelling(SourceLocation loc,
- SmallVectorImpl<char> &buffer,
- const SourceManager &SM,
- const LangOptions &options,
- bool *invalid) {
+ SmallVectorImpl<char> &buffer,
+ const SourceManager &SM,
+ const LangOptions &options,
+ bool *invalid) {
// Break down the source location.
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
@@ -267,17 +325,10 @@ StringRef Lexer::getSpelling(SourceLocation loc,
// Common case: no need for cleaning.
if (!token.needsCleaning())
return StringRef(tokenBegin, length);
-
- // Hard case, we need to relex the characters into the string.
- buffer.clear();
- buffer.reserve(length);
-
- for (const char *ti = tokenBegin, *te = ti + length; ti != te; ) {
- unsigned charSize;
- buffer.push_back(Lexer::getCharAndSizeNoWarn(ti, charSize, options));
- ti += charSize;
- }
+ // Hard case, we need to relex the characters into the string.
+ buffer.resize(length);
+ buffer.resize(getSpellingSlow(token, tokenBegin, options, buffer.data()));
return StringRef(buffer.data(), buffer.size());
}
@@ -289,31 +340,22 @@ StringRef Lexer::getSpelling(SourceLocation loc,
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
-
- // If this token contains nothing interesting, return it directly.
+
bool CharDataInvalid = false;
- const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
+ const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
&CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
if (CharDataInvalid)
return std::string();
-
+
+ // If this token contains nothing interesting, return it directly.
if (!Tok.needsCleaning())
- return std::string(TokStart, TokStart+Tok.getLength());
-
+ return std::string(TokStart, TokStart + Tok.getLength());
+
std::string Result;
- Result.reserve(Tok.getLength());
-
- // Otherwise, hard case, relex the characters into the string.
- for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
- Ptr != End; ) {
- unsigned CharSize;
- Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts));
- Ptr += CharSize;
- }
- assert(Result.size() != unsigned(Tok.getLength()) &&
- "NeedsCleaning flag set on something that didn't need cleaning!");
+ Result.resize(Tok.getLength());
+ Result.resize(getSpellingSlow(Tok, TokStart, LangOpts, &*Result.begin()));
return Result;
}
@@ -336,10 +378,12 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
// NOTE: this has to be checked *before* testing for an IdentifierInfo.
if (Tok.is(tok::raw_identifier))
TokStart = Tok.getRawIdentifierData();
- else if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
- // Just return the string from the identifier table, which is very quick.
- Buffer = II->getNameStart();
- return II->getLength();
+ else if (!Tok.hasUCN()) {
+ if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ // Just return the string from the identifier table, which is very quick.
+ Buffer = II->getNameStart();
+ return II->getLength();
+ }
}
// NOTE: this can be checked even after testing for an IdentifierInfo.
@@ -365,23 +409,10 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
}
// Otherwise, hard case, relex the characters into the string.
- char *OutBuf = const_cast<char*>(Buffer);
- for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
- Ptr != End; ) {
- unsigned CharSize;
- *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts);
- Ptr += CharSize;
- }
- assert(unsigned(OutBuf-Buffer) != Tok.getLength() &&
- "NeedsCleaning flag set on something that didn't need cleaning!");
-
- return OutBuf-Buffer;
+ return getSpellingSlow(Tok, TokStart, LangOpts, const_cast<char*>(Buffer));
}
-
-static bool isWhitespace(unsigned char c);
-
/// MeasureTokenLength - Relex the token at the specified location and return
/// its length in bytes in the input file. If the token needs cleaning (e.g.
/// includes a trigraph or an escaped newline) then this count includes bytes
@@ -389,6 +420,17 @@ static bool isWhitespace(unsigned char c);
unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
+ Token TheTok;
+ if (getRawToken(Loc, TheTok, SM, LangOpts))
+ return 0;
+ return TheTok.getLength();
+}
+
+/// \brief Relex the token at the specified location.
+/// \returns true if there was a failure, false on success.
+bool Lexer::getRawToken(SourceLocation Loc, Token &Result,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
// TODO: this could be special cased for common tokens like identifiers, ')',
// etc to make this faster, if it mattered. Just look at StrData[0] to handle
// all obviously single-char tokens. This could use
@@ -402,20 +444,19 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
- return 0;
+ return true;
const char *StrData = Buffer.data()+LocInfo.second;
if (isWhitespace(StrData[0]))
- return 0;
+ return true;
// Create a lexer starting at the beginning of this token.
Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
Buffer.begin(), StrData, Buffer.end());
TheLexer.SetCommentRetentionState(true);
- Token TheTok;
- TheLexer.LexFromRawLexer(TheTok);
- return TheTok.getLength();
+ TheLexer.LexFromRawLexer(Result);
+ return false;
}
static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
@@ -969,163 +1010,8 @@ StringRef Lexer::getImmediateMacroName(SourceLocation Loc,
return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
-//===----------------------------------------------------------------------===//
-// Character information.
-//===----------------------------------------------------------------------===//
-
-enum {
- CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0'
- CHAR_VERT_WS = 0x02, // '\r', '\n'
- CHAR_LETTER = 0x04, // a-z,A-Z
- CHAR_NUMBER = 0x08, // 0-9
- CHAR_UNDER = 0x10, // _
- CHAR_PERIOD = 0x20, // .
- CHAR_RAWDEL = 0x40 // {}[]#<>%:;?*+-/^&|~!=,"'
-};
-
-// Statically initialize CharInfo table based on ASCII character set
-// Reference: FreeBSD 7.2 /usr/share/misc/ascii
-static const unsigned char CharInfo[256] =
-{
-// 0 NUL 1 SOH 2 STX 3 ETX
-// 4 EOT 5 ENQ 6 ACK 7 BEL
- 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
-// 8 BS 9 HT 10 NL 11 VT
-//12 NP 13 CR 14 SO 15 SI
- 0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS,
- CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 ,
-//16 DLE 17 DC1 18 DC2 19 DC3
-//20 DC4 21 NAK 22 SYN 23 ETB
- 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
-//24 CAN 25 EM 26 SUB 27 ESC
-//28 FS 29 GS 30 RS 31 US
- 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
-//32 SP 33 ! 34 " 35 #
-//36 $ 37 % 38 & 39 '
- CHAR_HORZ_WS, CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
- 0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
-//40 ( 41 ) 42 * 43 +
-//44 , 45 - 46 . 47 /
- 0 , 0 , CHAR_RAWDEL , CHAR_RAWDEL ,
- CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL ,
-//48 0 49 1 50 2 51 3
-//52 4 53 5 54 6 55 7
- CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
- CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
-//56 8 57 9 58 : 59 ;
-//60 < 61 = 62 > 63 ?
- CHAR_NUMBER , CHAR_NUMBER , CHAR_RAWDEL , CHAR_RAWDEL ,
- CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
-//64 @ 65 A 66 B 67 C
-//68 D 69 E 70 F 71 G
- 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//72 H 73 I 74 J 75 K
-//76 L 77 M 78 N 79 O
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//80 P 81 Q 82 R 83 S
-//84 T 85 U 86 V 87 W
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//88 X 89 Y 90 Z 91 [
-//92 \ 93 ] 94 ^ 95 _
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
- 0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER ,
-//96 ` 97 a 98 b 99 c
-//100 d 101 e 102 f 103 g
- 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//104 h 105 i 106 j 107 k
-//108 l 109 m 110 n 111 o
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//112 p 113 q 114 r 115 s
-//116 t 117 u 118 v 119 w
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//120 x 121 y 122 z 123 {
-//124 | 125 } 126 ~ 127 DEL
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
- CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0
-};
-
-static void InitCharacterInfo() {
- static bool isInited = false;
- if (isInited) return;
- // check the statically-initialized CharInfo table
- assert(CHAR_HORZ_WS == CharInfo[(int)' ']);
- assert(CHAR_HORZ_WS == CharInfo[(int)'\t']);
- assert(CHAR_HORZ_WS == CharInfo[(int)'\f']);
- assert(CHAR_HORZ_WS == CharInfo[(int)'\v']);
- assert(CHAR_VERT_WS == CharInfo[(int)'\n']);
- assert(CHAR_VERT_WS == CharInfo[(int)'\r']);
- assert(CHAR_UNDER == CharInfo[(int)'_']);
- assert(CHAR_PERIOD == CharInfo[(int)'.']);
- for (unsigned i = 'a'; i <= 'z'; ++i) {
- assert(CHAR_LETTER == CharInfo[i]);
- assert(CHAR_LETTER == CharInfo[i+'A'-'a']);
- }
- for (unsigned i = '0'; i <= '9'; ++i)
- assert(CHAR_NUMBER == CharInfo[i]);
-
- isInited = true;
-}
-
-
-/// isIdentifierHead - Return true if this is the first character of an
-/// identifier, which is [a-zA-Z_].
-static inline bool isIdentifierHead(unsigned char c) {
- return (CharInfo[c] & (CHAR_LETTER|CHAR_UNDER)) ? true : false;
-}
-
-/// isIdentifierBody - Return true if this is the body character of an
-/// identifier, which is [a-zA-Z0-9_].
-static inline bool isIdentifierBody(unsigned char c) {
- return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER)) ? true : false;
-}
-
-/// isHorizontalWhitespace - Return true if this character is horizontal
-/// whitespace: ' ', '\\t', '\\f', '\\v'. Note that this returns false for
-/// '\\0'.
-static inline bool isHorizontalWhitespace(unsigned char c) {
- return (CharInfo[c] & CHAR_HORZ_WS) ? true : false;
-}
-
-/// isVerticalWhitespace - Return true if this character is vertical
-/// whitespace: '\\n', '\\r'. Note that this returns false for '\\0'.
-static inline bool isVerticalWhitespace(unsigned char c) {
- return (CharInfo[c] & CHAR_VERT_WS) ? true : false;
-}
-
-/// isWhitespace - Return true if this character is horizontal or vertical
-/// whitespace: ' ', '\\t', '\\f', '\\v', '\\n', '\\r'. Note that this returns
-/// false for '\\0'.
-static inline bool isWhitespace(unsigned char c) {
- return (CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS)) ? true : false;
-}
-
-/// isNumberBody - Return true if this is the body character of an
-/// preprocessing number, which is [a-zA-Z0-9_.].
-static inline bool isNumberBody(unsigned char c) {
- return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ?
- true : false;
-}
-
-/// isRawStringDelimBody - Return true if this is the body character of a
-/// raw string delimiter.
-static inline bool isRawStringDelimBody(unsigned char c) {
- return (CharInfo[c] &
- (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL)) ?
- true : false;
-}
-
-// Allow external clients to make use of CharInfo.
bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) {
- return isIdentifierBody(c) || (c == '$' && LangOpts.DollarIdents);
+ return isIdentifierBody(c, LangOpts.DollarIdents);
}
@@ -1293,7 +1179,7 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
// Try to load the file buffer.
bool InvalidTemp = false;
- llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+ StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
if (InvalidTemp)
return SourceLocation();
@@ -1319,8 +1205,15 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
C = *(++TokenEnd);
NumWhitespaceChars++;
}
- if (isVerticalWhitespace(C))
+
+ // Skip \r, \n, \r\n, or \n\r
+ if (C == '\n' || C == '\r') {
+ char PrevC = C;
+ C = *(++TokenEnd);
NumWhitespaceChars++;
+ if ((C == '\n' || C == '\r') && C != PrevC)
+ NumWhitespaceChars++;
+ }
}
return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars);
@@ -1334,7 +1227,6 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
/// 2. If this is an escaped newline (potentially with whitespace between
/// the backslash and newline), implicitly skip the newline and return
/// the char after it.
-/// 3. If this is a UCN, return it. FIXME: C++ UCN's?
///
/// This handles the slow/uncommon case of the getCharAndSize method. Here we
/// know that we can accumulate into Size, and that we have already incremented
@@ -1467,6 +1359,62 @@ void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
IsAtStartOfLine = StartOfLine;
}
+static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11)
+ return isCharInSet(C, C11AllowedIDChars);
+ else if (LangOpts.CPlusPlus)
+ return isCharInSet(C, CXX03AllowedIDChars);
+ else
+ return isCharInSet(C, C99AllowedIDChars);
+}
+
+static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
+ assert(isAllowedIDChar(C, LangOpts));
+ if (LangOpts.CPlusPlus11 || LangOpts.C11)
+ return !isCharInSet(C, C11DisallowedInitialIDChars);
+ else if (LangOpts.CPlusPlus)
+ return true;
+ else
+ return !isCharInSet(C, C99DisallowedInitialIDChars);
+}
+
+static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin,
+ const char *End) {
+ return CharSourceRange::getCharRange(L.getSourceLocation(Begin),
+ L.getSourceLocation(End));
+}
+
+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) {
+ enum {
+ CannotAppearInIdentifier = 0,
+ CannotStartIdentifier
+ };
+
+ if (!isCharInSet(C, C99AllowedIDChars)) {
+ Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
+ << Range
+ << CannotAppearInIdentifier;
+ } else if (IsFirst && isCharInSet(C, C99DisallowedInitialIDChars)) {
+ Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
+ << Range
+ << CannotStartIdentifier;
+ }
+ }
+
+ // Check C++98 compatibility.
+ if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_unicode_id,
+ Range.getBegin()) > DiagnosticsEngine::Ignored) {
+ if (!isCharInSet(C, CXX03AllowedIDChars)) {
+ Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id)
+ << Range;
+ }
+ }
+ }
+
void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
unsigned Size;
@@ -1478,11 +1426,11 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Fast path, no $,\,? in identifier found. '\' might be an escaped newline
// or UCN, and ? might be a trigraph for '\', an escaped newline or UCN.
- // FIXME: UCNs.
//
- // TODO: Could merge these checks into a CharInfo flag to make the comparison
- // cheaper
- if (C != '\\' && C != '?' && (C != '$' || !LangOpts.DollarIdents)) {
+ // TODO: Could merge these checks into an InfoTable flag to make the
+ // comparison cheaper
+ if (isASCII(C) && C != '\\' && C != '?' &&
+ (C != '$' || !LangOpts.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::raw_identifier);
@@ -1519,8 +1467,51 @@ FinishIdentifier:
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
continue;
- } else if (!isIdentifierBody(C)) { // FIXME: UCNs.
- // Found end of identifier.
+
+ } 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);
+
+ 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;
+ C = getCharAndSize(CurPtr, Size);
+ continue;
+ } else if (!isIdentifierBody(C)) {
goto FinishIdentifier;
}
@@ -1528,7 +1519,7 @@ FinishIdentifier:
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
- while (isIdentifierBody(C)) { // FIXME: UCNs.
+ while (isIdentifierBody(C)) {
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
}
@@ -1553,7 +1544,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
- while (isNumberBody(C)) { // FIXME: UCNs.
+ while (isPreprocessingNumberBody(C)) { // FIXME: UCNs in ud-suffix.
CurPtr = ConsumeChar(CurPtr, Size, Result);
PrevCh = C;
C = getCharAndSize(CurPtr, Size);
@@ -1598,7 +1589,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
if (isIdentifierHead(C)) {
- if (!getLangOpts().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus11) {
if (!isLexingRawMode())
Diag(CurPtr,
C == '_' ? diag::warn_cxx11_compat_user_defined_literal
@@ -1639,7 +1630,9 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
(Kind == tok::utf8_string_literal ||
Kind == tok::utf16_string_literal ||
Kind == tok::utf32_string_literal))
- Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '"') {
@@ -1804,7 +1797,9 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
if (!isLexingRawMode() &&
(Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
- Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
@@ -1860,6 +1855,8 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
///
bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
// Whitespace - Skip it, then return the token after the whitespace.
+ bool SawNewline = isVerticalWhitespace(CurPtr[-1]);
+
unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently.
while (1) {
// Skip horizontal whitespace very aggressively.
@@ -1867,7 +1864,7 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
Char = *++CurPtr;
// Otherwise if we have something other than whitespace, we're done.
- if (Char != '\n' && Char != '\r')
+ if (!isVerticalWhitespace(Char))
break;
if (ParsingPreprocessorDirective) {
@@ -1877,24 +1874,27 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
}
// ok, but handle newline.
- // The returned token is at the start of the line.
- Result.setFlag(Token::StartOfLine);
- // No leading whitespace seen so far.
- Result.clearFlag(Token::LeadingSpace);
+ SawNewline = true;
Char = *++CurPtr;
}
- // If this isn't immediately after a newline, there is leading space.
- char PrevChar = CurPtr[-1];
- if (PrevChar != '\n' && PrevChar != '\r')
- Result.setFlag(Token::LeadingSpace);
-
// If the client wants us to return whitespace, return it now.
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
+ if (SawNewline)
+ IsAtStartOfLine = true;
+ // FIXME: The next token will not have LeadingSpace set.
return true;
}
+ // If this isn't immediately after a newline, there is leading space.
+ char PrevChar = CurPtr[-1];
+ bool HasLeadingSpace = !isVerticalWhitespace(PrevChar);
+
+ Result.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+ if (SawNewline)
+ Result.setFlag(Token::StartOfLine);
+
BufferPtr = CurPtr;
return false;
}
@@ -2285,7 +2285,6 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// efficiently now. This is safe even in KeepWhitespaceMode because we would
// have already returned above with the comment as a token.
if (isHorizontalWhitespace(*CurPtr)) {
- Result.setFlag(Token::LeadingSpace);
SkipWhitespace(Result, CurPtr+1);
return false;
}
@@ -2367,7 +2366,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, CurPtr, tok::eod);
// Restore comment saving mode, in case it was disabled for directive.
- SetCommentRetentionState(PP->getCommentRetentionState());
+ resetExtendedTokenMode();
return true; // Have a token.
}
@@ -2393,7 +2392,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
// a pedwarn.
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
- Diag(BufferEnd, LangOpts.CPlusPlus0x ? // C++11 [lex.phases] 2.2 p2
+ Diag(BufferEnd, LangOpts.CPlusPlus11 ? // C++11 [lex.phases] 2.2 p2
diag::warn_cxx98_compat_no_newline_eof : diag::ext_no_newline_eof)
<< FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
@@ -2550,6 +2549,164 @@ bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
return false;
}
+uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc,
+ Token *Result) {
+ unsigned CharSize;
+ char Kind = getCharAndSize(StartPtr, CharSize);
+
+ unsigned NumHexDigits;
+ if (Kind == 'u')
+ NumHexDigits = 4;
+ else if (Kind == 'U')
+ NumHexDigits = 8;
+ else
+ return 0;
+
+ if (!LangOpts.CPlusPlus && !LangOpts.C99) {
+ if (Result && !isLexingRawMode())
+ Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89);
+ return 0;
+ }
+
+ const char *CurPtr = StartPtr + CharSize;
+ const char *KindLoc = &CurPtr[-1];
+
+ uint32_t CodePoint = 0;
+ for (unsigned i = 0; i < NumHexDigits; ++i) {
+ char C = getCharAndSize(CurPtr, CharSize);
+
+ unsigned Value = llvm::hexDigitValue(C);
+ if (Value == -1U) {
+ if (Result && !isLexingRawMode()) {
+ if (i == 0) {
+ Diag(BufferPtr, diag::warn_ucn_escape_no_digits)
+ << StringRef(KindLoc, 1);
+ } else {
+ Diag(BufferPtr, diag::warn_ucn_escape_incomplete);
+
+ // If the user wrote \U1234, suggest a fixit to \u.
+ if (i == 4 && NumHexDigits == 8) {
+ CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1);
+ Diag(KindLoc, diag::note_ucn_four_not_eight)
+ << FixItHint::CreateReplacement(URange, "u");
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ CodePoint <<= 4;
+ CodePoint += Value;
+
+ CurPtr += CharSize;
+ }
+
+ if (Result) {
+ Result->setFlag(Token::HasUCN);
+ if (CurPtr - StartPtr == (ptrdiff_t)NumHexDigits + 2)
+ StartPtr = CurPtr;
+ else
+ while (StartPtr != CurPtr)
+ (void)getAndAdvanceChar(StartPtr, *Result);
+ } else {
+ StartPtr = CurPtr;
+ }
+
+ // C99 6.4.3p2: A universal character name shall not specify a character whose
+ // short identifier is less than 00A0 other than 0024 ($), 0040 (@), or
+ // 0060 (`), nor one in the range D800 through DFFF inclusive.)
+ // C++11 [lex.charset]p2: If the hexadecimal value for a
+ // universal-character-name corresponds to a surrogate code point (in the
+ // range 0xD800-0xDFFF, inclusive), the program is ill-formed. Additionally,
+ // if the hexadecimal value for a universal-character-name outside the
+ // c-char-sequence, s-char-sequence, or r-char-sequence of a character or
+ // string literal corresponds to a control character (in either of the
+ // ranges 0x00-0x1F or 0x7F-0x9F, both inclusive) or to a character in the
+ // basic source character set, the program is ill-formed.
+ if (CodePoint < 0xA0) {
+ if (CodePoint == 0x24 || CodePoint == 0x40 || CodePoint == 0x60)
+ return CodePoint;
+
+ // We don't use isLexingRawMode() here because we need to warn about bad
+ // UCNs even when skipping preprocessing tokens in a #if block.
+ if (Result && PP) {
+ if (CodePoint < 0x20 || CodePoint >= 0x7F)
+ Diag(BufferPtr, diag::err_ucn_control_character);
+ else {
+ char C = static_cast<char>(CodePoint);
+ Diag(BufferPtr, diag::err_ucn_escape_basic_scs) << StringRef(&C, 1);
+ }
+ }
+
+ return 0;
+
+ } else if (CodePoint >= 0xD800 && CodePoint <= 0xDFFF) {
+ // C++03 allows UCNs representing surrogate characters. C99 and C++11 don't.
+ // We don't use isLexingRawMode() here because we need to diagnose bad
+ // UCNs even when skipping preprocessing tokens in a #if block.
+ if (Result && PP) {
+ if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus11)
+ Diag(BufferPtr, diag::warn_ucn_escape_surrogate);
+ else
+ Diag(BufferPtr, diag::err_ucn_escape_invalid);
+ }
+ return 0;
+ }
+
+ return CodePoint;
+}
+
+void Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) {
+ if (!isLexingRawMode() && !PP->isPreprocessedOutput() &&
+ isCharInSet(C, UnicodeWhitespaceChars)) {
+ Diag(BufferPtr, diag::ext_unicode_whitespace)
+ << makeCharRange(*this, BufferPtr, CurPtr);
+
+ Result.setFlag(Token::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr))
+ return; // KeepWhitespaceMode
+
+ return LexTokenInternal(Result);
+ }
+
+ if (isAllowedIDChar(C, LangOpts) && isAllowedInitiallyIDChar(C, LangOpts)) {
+ if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
+ !PP->isPreprocessedOutput()) {
+ maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C,
+ makeCharRange(*this, BufferPtr, CurPtr),
+ /*IsFirst=*/true);
+ }
+
+ MIOpt.ReadToken();
+ return LexIdentifier(Result, CurPtr);
+ }
+
+ if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
+ !PP->isPreprocessedOutput() &&
+ !isASCII(*BufferPtr) && !isAllowedIDChar(C, LangOpts)) {
+ // Non-ASCII characters tend to creep into source code unintentionally.
+ // Instead of letting the parser complain about the unknown token,
+ // just drop the character.
+ // Note that we can /only/ do this when the non-ASCII character is actually
+ // spelled as Unicode, not written as a UCN. The standard requires that
+ // we not throw away any possible preprocessor tokens, but there's a
+ // loophole in the mapping of Unicode characters to basic character set
+ // characters that allows us to map these particular characters to, say,
+ // whitespace.
+ Diag(BufferPtr, diag::err_non_ascii)
+ << FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr));
+
+ BufferPtr = CurPtr;
+ return LexTokenInternal(Result);
+ }
+
+ // Otherwise, we have an explicit UCN or a character that's unlikely to show
+ // up by accident.
+ MIOpt.ReadToken();
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+}
+
/// LexTokenInternal - This implements a simple C family lexer. It is an
/// extremely performance critical piece of code. This assumes that the buffer
@@ -2576,6 +2733,7 @@ LexNextToken:
// whitespace.
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
+ // FIXME: The next token will not have LeadingSpace set.
return;
}
@@ -2643,7 +2801,7 @@ LexNextToken:
// Restore comment saving mode, in case it was disabled for directive.
if (PP)
- SetCommentRetentionState(PP->getCommentRetentionState());
+ resetExtendedTokenMode();
// Since we consumed a newline, we are back at the start of a line.
IsAtStartOfLine = true;
@@ -2651,8 +2809,7 @@ LexNextToken:
Kind = tok::eod;
break;
}
- // The returned token is at the start of the line.
- Result.setFlag(Token::StartOfLine);
+
// No leading whitespace seen so far.
Result.clearFlag(Token::LeadingSpace);
@@ -2695,11 +2852,11 @@ LexNextToken:
MIOpt.ReadToken();
return LexNumericConstant(Result, CurPtr);
- case 'u': // Identifier (uber) or C++0x UTF-8 or UTF-16 string literal
+ case 'u': // Identifier (uber) or C11/C++11 UTF-8 or UTF-16 string literal
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-16 string literal
@@ -2713,7 +2870,8 @@ LexNextToken:
tok::utf16_char_constant);
// UTF-16 raw string literal
- if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ if (Char == 'R' && LangOpts.CPlusPlus11 &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
@@ -2729,7 +2887,7 @@ LexNextToken:
SizeTmp2, Result),
tok::utf8_string_literal);
- if (Char2 == 'R') {
+ if (Char2 == 'R' && LangOpts.CPlusPlus11) {
unsigned SizeTmp3;
char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
// UTF-8 raw string literal
@@ -2747,11 +2905,11 @@ LexNextToken:
// treat u like the start of an identifier.
return LexIdentifier(Result, CurPtr);
- case 'U': // Identifier (Uber) or C++0x UTF-32 string literal
+ case 'U': // Identifier (Uber) or C11/C++11 UTF-32 string literal
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-32 string literal
@@ -2765,7 +2923,8 @@ LexNextToken:
tok::utf32_char_constant);
// UTF-32 raw string literal
- if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ if (Char == 'R' && LangOpts.CPlusPlus11 &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
@@ -2779,7 +2938,7 @@ LexNextToken:
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
@@ -2802,7 +2961,7 @@ LexNextToken:
tok::wide_string_literal);
// Wide raw string literal.
- if (LangOpts.CPlusPlus0x && Char == 'R' &&
+ if (LangOpts.CPlusPlus11 && Char == 'R' &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
@@ -2968,10 +3127,13 @@ LexNextToken:
// this as "foo / bar" and langauges with Line comments would lex it as
// "foo". Check to see if the character after the second slash is a '*'.
// If so, we will lex that as a "/" instead of the start of a comment.
- // However, we never do this in -traditional-cpp mode.
- if ((LangOpts.LineComment ||
- getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
- !LangOpts.TraditionalCPP) {
+ // However, we never do this if we are just preprocessing.
+ bool TreatAsComment = LangOpts.LineComment && !LangOpts.TraditionalCPP;
+ if (!TreatAsComment)
+ if (!(PP && PP->isPreprocessedOutput()))
+ TreatAsComment = getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*';
+
+ if (TreatAsComment) {
if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
@@ -3020,26 +3182,8 @@ LexNextToken:
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
// FIXME: -fpreprocessed mode??
- if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer) {
- FormTokenWithChars(Result, CurPtr, tok::hash);
- PP->HandleDirective(Result);
-
- // As an optimization, if the preprocessor didn't switch lexers, tail
- // recurse.
- if (PP->isCurrentLexer(this)) {
- // Start a new token. If this is a #include or something, the PP may
- // want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag and clear LeadingSpace.
- if (IsAtStartOfLine) {
- Result.setFlag(Token::StartOfLine);
- Result.clearFlag(Token::LeadingSpace);
- IsAtStartOfLine = false;
- }
- goto LexNextToken; // GCC isn't tail call eliminating.
- }
-
- return PP->Lex(Result);
- }
+ if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
+ goto HandleDirective;
Kind = tok::hash;
}
@@ -3077,7 +3221,7 @@ LexNextToken:
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
} else if (LangOpts.Digraphs && Char == ':') { // '<:' -> '['
- if (LangOpts.CPlusPlus0x &&
+ if (LangOpts.CPlusPlus11 &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') {
// C++0x [lex.pptoken]p3:
// Otherwise, if the next three characters are <:: and the subsequent
@@ -3204,25 +3348,8 @@ LexNextToken:
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
// FIXME: -fpreprocessed mode??
- if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer) {
- FormTokenWithChars(Result, CurPtr, tok::hash);
- PP->HandleDirective(Result);
-
- // As an optimization, if the preprocessor didn't switch lexers, tail
- // recurse.
- if (PP->isCurrentLexer(this)) {
- // Start a new token. If this is a #include or something, the PP may
- // want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag and clear LeadingSpace.
- if (IsAtStartOfLine) {
- Result.setFlag(Token::StartOfLine);
- Result.clearFlag(Token::LeadingSpace);
- IsAtStartOfLine = false;
- }
- goto LexNextToken; // GCC isn't tail call eliminating.
- }
- return PP->Lex(Result);
- }
+ if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
+ goto HandleDirective;
Kind = tok::hash;
}
@@ -3236,12 +3363,48 @@ LexNextToken:
Kind = tok::unknown;
break;
+ // UCNs (C99 6.4.3, C++11 [lex.charset]p2)
case '\\':
- // FIXME: UCN's.
- // FALL THROUGH.
- default:
+ if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result))
+ return LexUnicode(Result, CodePoint, CurPtr);
+
Kind = tok::unknown;
break;
+
+ default: {
+ if (isASCII(Char)) {
+ Kind = tok::unknown;
+ break;
+ }
+
+ UTF32 CodePoint;
+
+ // We can't just reset CurPtr to BufferPtr because BufferPtr may point to
+ // an escaped newline.
+ --CurPtr;
+ ConversionResult Status =
+ llvm::convertUTF8Sequence((const UTF8 **)&CurPtr,
+ (const UTF8 *)BufferEnd,
+ &CodePoint,
+ strictConversion);
+ if (Status == conversionOK)
+ return LexUnicode(Result, CodePoint, CurPtr);
+
+ if (isLexingRawMode() || ParsingPreprocessorDirective ||
+ PP->isPreprocessedOutput()) {
+ ++CurPtr;
+ Kind = tok::unknown;
+ break;
+ }
+
+ // Non-ASCII characters tend to creep into source code unintentionally.
+ // Instead of letting the parser complain about the unknown token,
+ // just diagnose the invalid UTF-8, then drop the character.
+ Diag(CurPtr, diag::err_invalid_utf8);
+
+ BufferPtr = CurPtr+1;
+ goto LexNextToken;
+ }
}
// Notify MIOpt that we read a non-whitespace/non-comment token.
@@ -3249,4 +3412,26 @@ LexNextToken:
// Update the location of token as well as BufferPtr.
FormTokenWithChars(Result, CurPtr, Kind);
+ return;
+
+HandleDirective:
+ // We parsed a # character and it's the start of a preprocessing directive.
+
+ FormTokenWithChars(Result, CurPtr, tok::hash);
+ PP->HandleDirective(Result);
+
+ // As an optimization, if the preprocessor didn't switch lexers, tail
+ // recurse.
+ if (PP->isCurrentLexer(this)) {
+ // Start a new token. If this is a #include or something, the PP may
+ // want us starting at the beginning of the line again. If so, set
+ // the StartOfLine flag and clear LeadingSpace.
+ if (IsAtStartOfLine) {
+ Result.setFlag(Token::StartOfLine);
+ Result.clearFlag(Token::LeadingSpace);
+ IsAtStartOfLine = false;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+ return PP->Lex(Result);
}
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index e30612e57c5b..91da8223c184 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -13,22 +13,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/ConvertUTF.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
-using namespace clang;
-/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
-/// not valid.
-static int HexDigitValue(char C) {
- if (C >= '0' && C <= '9') return C-'0';
- if (C >= 'a' && C <= 'f') return C-'a'+10;
- if (C >= 'A' && C <= 'F') return C-'A'+10;
- return -1;
-}
+using namespace clang;
static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
switch (kind) {
@@ -136,10 +129,10 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
break;
case 'x': { // Hex escape.
ResultChar = 0;
- if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
+ if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) {
if (Diags)
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::err_hex_escape_no_digits);
+ diag::err_hex_escape_no_digits) << "x";
HadError = 1;
break;
}
@@ -147,7 +140,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
// Hex escapes are a maximal series of hex digits.
bool Overflow = false;
for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) {
- int CharVal = HexDigitValue(ThisTokBuf[0]);
+ int CharVal = llvm::hexDigitValue(ThisTokBuf[0]);
if (CharVal == -1) break;
// About to shift out a digit?
Overflow |= (ResultChar & 0xF0000000) ? true : false;
@@ -205,7 +198,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
if (Diags == 0)
break;
- if (isgraph(ResultChar))
+ if (isPrintable(ResultChar))
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
diag::ext_unknown_escape)
<< std::string(1, ResultChar);
@@ -232,16 +225,16 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// Skip the '\u' char's.
ThisTokBuf += 2;
- if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
+ if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) {
if (Diags)
Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
- diag::err_ucn_escape_no_digits);
+ diag::err_hex_escape_no_digits) << StringRef(&ThisTokBuf[-1], 1);
return false;
}
UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8);
unsigned short UcnLenSave = UcnLen;
for (; ThisTokBuf != ThisTokEnd && UcnLenSave; ++ThisTokBuf, UcnLenSave--) {
- int CharVal = HexDigitValue(ThisTokBuf[0]);
+ int CharVal = llvm::hexDigitValue(ThisTokBuf[0]);
if (CharVal == -1) break;
UcnVal <<= 4;
UcnVal |= CharVal;
@@ -267,7 +260,7 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// characters inside character and string literals
if (UcnVal < 0xa0 &&
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, `
- bool IsError = (!Features.CPlusPlus0x || !in_char_string_literal);
+ bool IsError = (!Features.CPlusPlus11 || !in_char_string_literal);
if (Diags) {
char BasicSCSChar = UcnVal;
if (UcnVal >= 0x20 && UcnVal < 0x7f)
@@ -286,7 +279,7 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if (!Features.CPlusPlus && !Features.C99 && Diags)
Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
- diag::warn_ucn_not_valid_in_c89);
+ diag::warn_ucn_not_valid_in_c89_literal);
return true;
}
@@ -467,8 +460,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// and FP constants (specifically, the 'pp-number' regex), and assumes that
// the byte at "*end" is both valid and not part of the regex. Because of
// this, it doesn't have to check for 'overscan' in various places.
- assert(!isalnum(*ThisTokEnd) && *ThisTokEnd != '.' && *ThisTokEnd != '_' &&
- "Lexer didn't maximally munch?");
+ assert(!isPreprocessingNumberBody(*ThisTokEnd) && "didn't maximally munch?");
s = DigitsBegin = ThisTokBegin;
saw_exponent = false;
@@ -491,7 +483,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
s = SkipDigits(s);
if (s == ThisTokEnd) {
// Done.
- } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
+ } else if (isHexDigit(*s) && !(*s == 'e' || *s == 'E')) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_invalid_decimal_digit) << StringRef(s, 1);
hadError = true;
@@ -616,7 +608,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
if (s != ThisTokEnd) {
- if (PP.getLangOpts().CPlusPlus0x && s == SuffixBegin && *s == '_') {
+ if (PP.getLangOpts().CPlusPlus11 && s == SuffixBegin && *s == '_') {
// We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting
// with an '_' are ill-formed.
saw_ud_suffix = true;
@@ -643,7 +635,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s++;
// Handle a hex number like 0x1234.
- if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
+ if ((*s == 'x' || *s == 'X') && (isHexDigit(s[1]) || s[1] == '.')) {
s++;
radix = 16;
DigitsBegin = s;
@@ -702,7 +694,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s = SkipBinaryDigits(s);
if (s == ThisTokEnd) {
// Done.
- } else if (isxdigit(*s)) {
+ } else if (isHexDigit(*s)) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
diag::err_invalid_binary_digit) << StringRef(s, 1);
hadError = true;
@@ -722,7 +714,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// If we have some other non-octal digit that *is* a decimal digit, see if
// this is part of a floating point number like 094.123 or 09e1.
- if (isdigit(*s)) {
+ if (isDigit(*s)) {
const char *EndDecimal = SkipDigits(s);
if (EndDecimal[0] == '.' || EndDecimal[0] == 'e' || EndDecimal[0] == 'E') {
s = EndDecimal;
@@ -732,7 +724,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// If we have a hex digit other than 'e' (which denotes a FP exponent) then
// the code is using an incorrect base.
- if (isxdigit(*s) && *s != 'e' && *s != 'E') {
+ if (isHexDigit(*s) && *s != 'e' && *s != 'E') {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
diag::err_invalid_octal_digit) << StringRef(s, 1);
hadError = true;
@@ -792,7 +784,7 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
if (alwaysFitsInto64Bits(radix, NumDigits)) {
uint64_t N = 0;
for (const char *Ptr = DigitsBegin; Ptr != SuffixBegin; ++Ptr)
- N = N * radix + HexDigitValue(*Ptr);
+ N = N * radix + llvm::hexDigitValue(*Ptr);
// This will truncate the value to Val's input width. Simply check
// for overflow by comparing.
@@ -809,7 +801,7 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
bool OverflowOccurred = false;
while (Ptr < SuffixBegin) {
- unsigned C = HexDigitValue(*Ptr++);
+ unsigned C = llvm::hexDigitValue(*Ptr++);
// If this letter is out of bound for this radix, reject it.
assert(C < radix && "NumericLiteralParser ctor should have rejected this");
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index ed8873d08612..f6e781a936d4 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "MacroArgs.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/SaveAndRestore.h"
#include <algorithm>
@@ -23,7 +23,7 @@ using namespace clang;
/// MacroArgs ctor function - This destroys the vector passed in.
MacroArgs *MacroArgs::create(const MacroInfo *MI,
- llvm::ArrayRef<Token> UnexpArgTokens,
+ ArrayRef<Token> UnexpArgTokens,
bool VarargsElided, Preprocessor &PP) {
assert(MI->isFunctionLike() &&
"Can't have args for an object-like macro!");
@@ -215,15 +215,11 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
// If this is a string or character constant, escape the token as specified
// by 6.10.3.2p2.
- if (Tok.is(tok::string_literal) || // "foo"
- Tok.is(tok::wide_string_literal) || // L"foo"
- Tok.is(tok::utf8_string_literal) || // u8"foo"
- Tok.is(tok::utf16_string_literal) || // u"foo"
- Tok.is(tok::utf32_string_literal) || // U"foo"
- Tok.is(tok::char_constant) || // 'x'
- Tok.is(tok::wide_char_constant) || // L'x'.
- Tok.is(tok::utf16_char_constant) || // u'x'.
- Tok.is(tok::utf32_char_constant)) { // U'x'.
+ if (tok::isStringLiteral(Tok.getKind()) || // "foo", u8R"x(foo)x"_bar, etc.
+ Tok.is(tok::char_constant) || // 'x'
+ Tok.is(tok::wide_char_constant) || // L'x'.
+ Tok.is(tok::utf16_char_constant) || // u'x'.
+ Tok.is(tok::utf32_char_constant)) { // U'x'.
bool Invalid = false;
std::string TokStr = PP.getSpelling(Tok, &Invalid);
if (!Invalid) {
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index cf86d710adb7..1fd295ebfa9e 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_MACROARGS_H
#define LLVM_CLANG_MACROARGS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
-
#include <vector>
namespace clang {
@@ -60,7 +60,7 @@ public:
/// MacroArgs ctor function - Create a new MacroArgs object with the specified
/// macro and argument info.
static MacroArgs *create(const MacroInfo *MI,
- llvm::ArrayRef<Token> UnexpArgTokens,
+ ArrayRef<Token> UnexpArgTokens,
bool VarargsElided, Preprocessor &PP);
/// destroy - Destroy and deallocate the memory for this object.
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 904f04e4f836..b61ff71d1767 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -17,7 +17,6 @@ using namespace clang;
MacroInfo::MacroInfo(SourceLocation DefLoc)
: Location(DefLoc),
- PreviousDefinition(0),
ArgumentList(0),
NumArguments(0),
IsDefinitionLengthCached(false),
@@ -25,53 +24,12 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
IsC99Varargs(false),
IsGNUVarargs(false),
IsBuiltinMacro(false),
- IsFromAST(false),
- ChangedAfterLoad(false),
+ HasCommaPasting(false),
IsDisabled(false),
IsUsed(false),
IsAllowRedefinitionsWithoutWarning(false),
IsWarnIfUnused(false),
- IsPublic(true),
- IsHidden(false),
- IsAmbiguous(false) {
-}
-
-MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator)
- : Location(MI.Location),
- EndLocation(MI.EndLocation),
- UndefLocation(MI.UndefLocation),
- PreviousDefinition(0),
- ArgumentList(0),
- NumArguments(0),
- ReplacementTokens(MI.ReplacementTokens),
- DefinitionLength(MI.DefinitionLength),
- IsDefinitionLengthCached(MI.IsDefinitionLengthCached),
- IsFunctionLike(MI.IsFunctionLike),
- IsC99Varargs(MI.IsC99Varargs),
- IsGNUVarargs(MI.IsGNUVarargs),
- IsBuiltinMacro(MI.IsBuiltinMacro),
- IsFromAST(MI.IsFromAST),
- ChangedAfterLoad(MI.ChangedAfterLoad),
- IsDisabled(MI.IsDisabled),
- IsUsed(MI.IsUsed),
- IsAllowRedefinitionsWithoutWarning(MI.IsAllowRedefinitionsWithoutWarning),
- IsWarnIfUnused(MI.IsWarnIfUnused),
- IsPublic(MI.IsPublic),
- IsHidden(MI.IsHidden),
- IsAmbiguous(MI.IsAmbiguous) {
- setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
-}
-
-const MacroInfo *MacroInfo::findDefinitionAtLoc(SourceLocation L,
- SourceManager &SM) const {
- assert(L.isValid() && "SourceLocation is invalid.");
- for (const MacroInfo *MI = this; MI; MI = MI->PreviousDefinition) {
- if (MI->Location.isInvalid() || // For macros defined on the command line.
- SM.isBeforeInTranslationUnit(MI->Location, L))
- return (MI->UndefLocation.isInvalid() ||
- SM.isBeforeInTranslationUnit(L, MI->UndefLocation)) ? MI : NULL;
- }
- return NULL;
+ FromASTFile(false) {
}
unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
@@ -103,11 +61,17 @@ unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
return DefinitionLength;
}
-/// isIdenticalTo - Return true if the specified macro definition is equal to
-/// this macro in spelling, arguments, and whitespace. This is used to emit
-/// duplicate definition warnings. This implements the rules in C99 6.10.3.
+/// \brief Return true if the specified macro definition is equal to
+/// this macro in spelling, arguments, and whitespace.
///
-bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
+/// \param Syntactically if true, the macro definitions can be identical even
+/// if they use different identifiers for the function macro parameters.
+/// Otherwise the comparison is lexical and this implements the rules in
+/// C99 6.10.3.
+bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
+ bool Syntactically) const {
+ bool Lexically = !Syntactically;
+
// Check # tokens in replacement, number of args, and various flags all match.
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
getNumArgs() != Other.getNumArgs() ||
@@ -116,10 +80,12 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
isGNUVarargs() != Other.isGNUVarargs())
return false;
- // Check arguments.
- for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
- I != E; ++I, ++OI)
- if (*I != *OI) return false;
+ if (Lexically) {
+ // Check arguments.
+ for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
+ I != E; ++I, ++OI)
+ if (*I != *OI) return false;
+ }
// Check all the tokens.
for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
@@ -137,7 +103,16 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
// If this is an identifier, it is easy.
if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
- if (A.getIdentifierInfo() != B.getIdentifierInfo())
+ if (A.getIdentifierInfo() == B.getIdentifierInfo())
+ continue;
+ if (Lexically)
+ return false;
+ // With syntactic equivalence the parameter names can be different as long
+ // as they are used in the same place.
+ int AArgNum = getArgumentNum(A.getIdentifierInfo());
+ if (AArgNum == -1)
+ return false;
+ if (AArgNum != Other.getArgumentNum(B.getIdentifierInfo()))
return false;
continue;
}
@@ -149,3 +124,41 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
return true;
}
+
+MacroDirective::DefInfo MacroDirective::getDefinition(bool AllowHidden) {
+ 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());
+
+ if (UndefMacroDirective *UndefMD = dyn_cast<UndefMacroDirective>(MD)) {
+ UndefLoc = UndefMD->getLocation();
+ continue;
+ }
+
+ VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
+ if (!isPublic.hasValue())
+ isPublic = VisMD->isPublic();
+ }
+
+ return DefInfo();
+}
+
+const MacroDirective::DefInfo
+MacroDirective::findDirectiveAtLoc(SourceLocation L, SourceManager &SM) const {
+ assert(L.isValid() && "SourceLocation is invalid.");
+ for (DefInfo Def = getDefinition(); Def; Def = Def.getPreviousDefinition()) {
+ if (Def.getLocation().isInvalid() || // For macros defined on the command line.
+ SM.isBeforeInTranslationUnit(Def.getLocation(), L))
+ return (!Def.isUndefined() ||
+ SM.isBeforeInTranslationUnit(L, Def.getUndefLocation()))
+ ? Def : DefInfo();
+ }
+ return DefInfo();
+}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 8a936fa8e145..0c03201aa6d4 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -12,68 +12,82 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/ModuleMap.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include <stdlib.h>
+#if defined(LLVM_ON_UNIX)
+#include <limits.h>
+#endif
using namespace clang;
Module::ExportDecl
ModuleMap::resolveExport(Module *Mod,
const Module::UnresolvedExportDecl &Unresolved,
- bool Complain) {
+ bool Complain) const {
// We may have just a wildcard.
if (Unresolved.Id.empty()) {
assert(Unresolved.Wildcard && "Invalid unresolved export");
return Module::ExportDecl(0, true);
}
+ // Resolve the module-id.
+ Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain);
+ if (!Context)
+ return Module::ExportDecl();
+
+ return Module::ExportDecl(Context, Unresolved.Wildcard);
+}
+
+Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
+ bool Complain) const {
// Find the starting module.
- Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
+ Module *Context = lookupModuleUnqualified(Id[0].first, Mod);
if (!Context) {
if (Complain)
- Diags->Report(Unresolved.Id[0].second,
- diag::err_mmap_missing_module_unqualified)
- << Unresolved.Id[0].first << Mod->getFullModuleName();
-
- return Module::ExportDecl();
+ Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified)
+ << Id[0].first << Mod->getFullModuleName();
+
+ return 0;
}
// Dig into the module path.
- for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
- Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
- Context);
+ for (unsigned I = 1, N = Id.size(); I != N; ++I) {
+ Module *Sub = lookupModuleQualified(Id[I].first, Context);
if (!Sub) {
if (Complain)
- Diags->Report(Unresolved.Id[I].second,
- diag::err_mmap_missing_module_qualified)
- << Unresolved.Id[I].first << Context->getFullModuleName()
- << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second);
-
- return Module::ExportDecl();
+ 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;
}
-
+
Context = Sub;
}
-
- return Module::ExportDecl(Context, Unresolved.Wildcard);
+
+ return Context;
}
ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
- const LangOptions &LangOpts, const TargetInfo *Target)
- : LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0)
+ const LangOptions &LangOpts, const TargetInfo *Target,
+ HeaderSearch &HeaderInfo)
+ : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo),
+ BuiltinIncludeDir(0)
{
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
@@ -104,26 +118,15 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
if (Name.empty())
return Name;
- // Check whether the filename is already an identifier; this is the common
- // case.
- bool isIdentifier = true;
- for (unsigned I = 0, N = Name.size(); I != N; ++I) {
- if (isalpha(Name[I]) || Name[I] == '_' || (isdigit(Name[I]) && I > 0))
- continue;
-
- isIdentifier = false;
- break;
- }
-
- if (!isIdentifier) {
+ if (!isValidIdentifier(Name)) {
// If we don't already have something with the form of an identifier,
// create a buffer with the sanitized name.
Buffer.clear();
- if (isdigit(Name[0]))
+ if (isDigit(Name[0]))
Buffer.push_back('_');
Buffer.reserve(Buffer.size() + Name.size());
for (unsigned I = 0, N = Name.size(); I != N; ++I) {
- if (isalnum(Name[I]) || isspace(Name[I]))
+ if (isIdentifierBody(Name[I]))
Buffer.push_back(Name[I]);
else
Buffer.push_back('_');
@@ -157,8 +160,13 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
const DirectoryEntry *Dir = File->getDir();
- llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
- StringRef DirName = Dir->getName();
+ 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.
@@ -204,7 +212,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
llvm::sys::path::stem(File->getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
- Result->TopHeaders.insert(File);
+ Result->addTopHeader(File);
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
@@ -241,19 +249,19 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
return 0;
}
-bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
- HeadersMap::iterator Known = Headers.find(Header);
+bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
+ HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end())
return !Known->second.isAvailable();
const DirectoryEntry *Dir = Header->getDir();
- llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ SmallVector<const DirectoryEntry *, 2> SkippedDirs;
StringRef DirName = Dir->getName();
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
do {
- llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+ llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir
= UmbrellaDirs.find(Dir);
if (KnownDir != UmbrellaDirs.end()) {
Module *Found = KnownDir->second;
@@ -307,15 +315,16 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
return false;
}
-Module *ModuleMap::findModule(StringRef Name) {
- llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
+Module *ModuleMap::findModule(StringRef Name) const {
+ llvm::StringMap<Module *>::const_iterator Known = Modules.find(Name);
if (Known != Modules.end())
return Known->getValue();
return 0;
}
-Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
+Module *ModuleMap::lookupModuleUnqualified(StringRef Name,
+ Module *Context) const {
for(; Context; Context = Context->Parent) {
if (Module *Sub = lookupModuleQualified(Name, Context))
return Sub;
@@ -324,7 +333,7 @@ Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
return findModule(Name);
}
-Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) {
+Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
if (!Context)
return findModule(Name);
@@ -347,10 +356,10 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
}
bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
- StringRef Name, bool &IsSystem) {
+ StringRef Name, bool &IsSystem) const {
// Check whether we have already looked into the parent directory
// for a module map.
- llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
inferred = InferredDirectories.find(ParentDir);
if (inferred == InferredDirectories.end())
return false;
@@ -370,6 +379,23 @@ bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
return canInfer;
}
+/// \brief For a framework module, infer the framework against which we
+/// should link.
+static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
+ FileManager &FileMgr) {
+ assert(Mod->IsFramework && "Can only infer linking for framework modules");
+ assert(!Mod->isSubFramework() &&
+ "Can only infer linking for top-level frameworks");
+
+ SmallString<128> LibName;
+ LibName += FrameworkDir->getName();
+ llvm::sys::path::append(LibName, Mod->Name);
+ if (FileMgr.getFile(LibName)) {
+ Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name,
+ /*IsFramework=*/true));
+ }
+}
+
Module *
ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir,
@@ -384,14 +410,23 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
if (!Parent) {
+ // Determine whether we're allowed to infer a module map.
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // we might be looking at an embedded framework that symlinks out to a
+ // top-level framework, and we need to infer as if we were naming the
+ // top-level framework.
+ StringRef FrameworkDirName
+ = SourceMgr->getFileManager().getCanonicalName(FrameworkDir);
+
bool canInfer = false;
- if (llvm::sys::path::has_parent_path(FrameworkDir->getName())) {
+ if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// Figure out the parent path.
- StringRef Parent = llvm::sys::path::parent_path(FrameworkDir->getName());
+ StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);
if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
// Check whether we have already looked into the parent directory
// for a module map.
- llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
inferred = InferredDirectories.find(ParentDir);
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
@@ -411,7 +446,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (inferred->second.InferModules) {
// We're allowed to infer for this directory, but make sure it's okay
// to infer this particular module.
- StringRef Name = llvm::sys::path::filename(FrameworkDir->getName());
+ StringRef Name = llvm::sys::path::stem(FrameworkDirName);
canInfer = std::find(inferred->second.ExcludedModules.begin(),
inferred->second.ExcludedModules.end(),
Name) == inferred->second.ExcludedModules.end();
@@ -480,29 +515,23 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// check whether it is actually a subdirectory of the parent directory.
// This will not be the case if the 'subframework' is actually a symlink
// out to a top-level framework.
-#ifdef LLVM_ON_UNIX
- char RealSubframeworkDirName[PATH_MAX];
- if (realpath(Dir->path().c_str(), RealSubframeworkDirName)) {
- StringRef SubframeworkDirName = RealSubframeworkDirName;
-
- bool FoundParent = false;
- do {
- // Get the parent directory name.
- SubframeworkDirName
- = llvm::sys::path::parent_path(SubframeworkDirName);
- if (SubframeworkDirName.empty())
- break;
-
- if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
- FoundParent = true;
- break;
- }
- } while (true);
+ StringRef SubframeworkDirName = FileMgr.getCanonicalName(SubframeworkDir);
+ bool FoundParent = false;
+ do {
+ // Get the parent directory name.
+ SubframeworkDirName
+ = llvm::sys::path::parent_path(SubframeworkDirName);
+ if (SubframeworkDirName.empty())
+ break;
+
+ if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
+ FoundParent = true;
+ break;
+ }
+ } while (true);
- if (!FoundParent)
- continue;
- }
-#endif
+ if (!FoundParent)
+ continue;
// FIXME: Do we want to warn about subframeworks without umbrella headers?
SmallString<32> NameBuf;
@@ -512,6 +541,12 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
}
+ // If the module is a top-level framework, automatically link against the
+ // framework.
+ if (!Result->isSubFramework()) {
+ inferFrameworkLink(Result, FrameworkDir, FileMgr);
+ }
+
return Result;
}
@@ -528,15 +563,17 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
bool Excluded) {
- if (Excluded)
+ if (Excluded) {
Mod->ExcludedHeaders.push_back(Header);
- else
+ } else {
Mod->Headers.push_back(Header);
+ HeaderInfo.MarkFileModuleHeader(Header);
+ }
Headers[Header] = KnownHeader(Mod, Excluded);
}
const FileEntry *
-ModuleMap::getContainingModuleMapFile(Module *Module) {
+ModuleMap::getContainingModuleMapFile(Module *Module) const {
if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
return 0;
@@ -573,6 +610,25 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
return HadError;
}
+bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
+ bool HadError = false;
+ for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
+ Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id,
+ Mod, Complain);
+ if (!OtherMod) {
+ HadError = true;
+ continue;
+ }
+
+ Module::Conflict Conflict;
+ Conflict.Other = OtherMod;
+ Conflict.Message = Mod->UnresolvedConflicts[I].Message;
+ Mod->Conflicts.push_back(Conflict);
+ }
+ Mod->UnresolvedConflicts.clear();
+ return HadError;
+}
+
Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
if (Loc.isInvalid())
return 0;
@@ -613,6 +669,8 @@ namespace clang {
struct MMToken {
enum TokenKind {
Comma,
+ ConfigMacros,
+ Conflict,
EndOfFile,
HeaderKeyword,
Identifier,
@@ -620,6 +678,7 @@ namespace clang {
ExplicitKeyword,
ExportKeyword,
FrameworkKeyword,
+ LinkKeyword,
ModuleKeyword,
Period,
UmbrellaKeyword,
@@ -656,10 +715,13 @@ namespace clang {
/// \brief The set of attributes that can be attached to a module.
struct Attributes {
- Attributes() : IsSystem() { }
+ Attributes() : IsSystem(), IsExhaustive() { }
/// \brief Whether this is a system module.
unsigned IsSystem : 1;
+
+ /// \brief Whether this is an exhaustive set of configuration macros.
+ unsigned IsExhaustive : 1;
};
@@ -700,14 +762,16 @@ namespace clang {
/// (or the end of the file).
void skipUntil(MMToken::TokenKind K);
- typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
- ModuleId;
+ typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseRequiresDecl();
void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
+ void parseLinkDecl();
+ void parseConfigMacros();
+ void parseConflict();
void parseInferredModuleDecl(bool Framework, bool Explicit);
bool parseOptionalAttributes(Attributes &Attrs);
@@ -745,11 +809,14 @@ retry:
Tok.StringData = LToken.getRawIdentifierData();
Tok.StringLength = LToken.getLength();
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
- .Case("header", MMToken::HeaderKeyword)
+ .Case("config_macros", MMToken::ConfigMacros)
+ .Case("conflict", MMToken::Conflict)
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
+ .Case("header", MMToken::HeaderKeyword)
+ .Case("link", MMToken::LinkKeyword)
.Case("module", MMToken::ModuleKeyword)
.Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
@@ -905,7 +972,9 @@ namespace {
/// \brief An unknown attribute.
AT_unknown,
/// \brief The 'system' attribute.
- AT_system
+ AT_system,
+ /// \brief The 'exhaustive' attribute.
+ AT_exhaustive
};
}
@@ -920,6 +989,7 @@ namespace {
/// header-declaration
/// submodule-declaration
/// export-declaration
+/// link-declaration
///
/// submodule-declaration:
/// module-declaration
@@ -1061,7 +1131,15 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::RBrace:
Done = true;
break;
-
+
+ case MMToken::ConfigMacros:
+ parseConfigMacros();
+ break;
+
+ case MMToken::Conflict:
+ parseConflict();
+ break;
+
case MMToken::ExplicitKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
@@ -1099,7 +1177,11 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::HeaderKeyword:
parseHeaderDecl(SourceLocation(), SourceLocation());
break;
-
+
+ case MMToken::LinkKeyword:
+ parseLinkDecl();
+ break;
+
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
consumeToken();
@@ -1115,6 +1197,13 @@ void ModuleMapParser::parseModuleDecl() {
HadError = true;
}
+ // If the active module is a top-level framework, and there are no link
+ // libraries, automatically link against the framework.
+ if (ActiveModule->IsFramework && !ActiveModule->isSubFramework() &&
+ ActiveModule->LinkLibraries.empty()) {
+ inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
+ }
+
// We're done parsing this module. Pop back to the previous module.
ActiveModule = PreviousActiveModule;
}
@@ -1159,9 +1248,9 @@ void ModuleMapParser::parseRequiresDecl() {
/// \brief Append to \p Paths the set of paths needed to get to the
/// subframework in which the given module lives.
static void appendSubframeworkPaths(Module *Mod,
- llvm::SmallVectorImpl<char> &Path) {
+ SmallVectorImpl<char> &Path) {
// Collect the framework names from the given module to the top-level module.
- llvm::SmallVector<StringRef, 2> Paths;
+ SmallVector<StringRef, 2> Paths;
for (; Mod; Mod = Mod->Parent) {
if (Mod->IsFramework)
Paths.push_back(Mod->Name);
@@ -1307,7 +1396,9 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
if (BuiltinFile)
Map.addHeader(ActiveModule, BuiltinFile, Exclude);
}
- } else {
+ } else if (!Exclude) {
+ // Ignore excluded header files. They're optional anyway.
+
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
<< Umbrella << FileName;
HadError = true;
@@ -1414,7 +1505,139 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
-/// \brief Parse an inferried module declaration (wildcard modules).
+/// \brief Parse a link declaration.
+///
+/// module-declaration:
+/// 'link' 'framework'[opt] string-literal
+void ModuleMapParser::parseLinkDecl() {
+ assert(Tok.is(MMToken::LinkKeyword));
+ SourceLocation LinkLoc = consumeToken();
+
+ // Parse the optional 'framework' keyword.
+ bool IsFramework = false;
+ if (Tok.is(MMToken::FrameworkKeyword)) {
+ consumeToken();
+ IsFramework = true;
+ }
+
+ // Parse the library name
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)
+ << IsFramework << SourceRange(LinkLoc);
+ HadError = true;
+ return;
+ }
+
+ std::string LibraryName = Tok.getString();
+ consumeToken();
+ ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName,
+ IsFramework));
+}
+
+/// \brief Parse a configuration macro declaration.
+///
+/// module-declaration:
+/// 'config_macros' attributes[opt] config-macro-list?
+///
+/// config-macro-list:
+/// identifier (',' identifier)?
+void ModuleMapParser::parseConfigMacros() {
+ assert(Tok.is(MMToken::ConfigMacros));
+ SourceLocation ConfigMacrosLoc = consumeToken();
+
+ // Only top-level modules can have configuration macros.
+ if (ActiveModule->Parent) {
+ Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule);
+ }
+
+ // Parse the optional attributes.
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
+ if (Attrs.IsExhaustive && !ActiveModule->Parent) {
+ ActiveModule->ConfigMacrosExhaustive = true;
+ }
+
+ // If we don't have an identifier, we're done.
+ if (!Tok.is(MMToken::Identifier))
+ return;
+
+ // Consume the first identifier.
+ if (!ActiveModule->Parent) {
+ ActiveModule->ConfigMacros.push_back(Tok.getString().str());
+ }
+ consumeToken();
+
+ do {
+ // If there's a comma, consume it.
+ if (!Tok.is(MMToken::Comma))
+ break;
+ consumeToken();
+
+ // We expect to see a macro name here.
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
+ break;
+ }
+
+ // Consume the macro name.
+ if (!ActiveModule->Parent) {
+ ActiveModule->ConfigMacros.push_back(Tok.getString().str());
+ }
+ consumeToken();
+ } while (true);
+}
+
+/// \brief Format a module-id into a string.
+static std::string formatModuleId(const ModuleId &Id) {
+ std::string result;
+ {
+ llvm::raw_string_ostream OS(result);
+
+ for (unsigned I = 0, N = Id.size(); I != N; ++I) {
+ if (I)
+ OS << ".";
+ OS << Id[I].first;
+ }
+ }
+
+ return result;
+}
+
+/// \brief Parse a conflict declaration.
+///
+/// module-declaration:
+/// 'conflict' module-id ',' string-literal
+void ModuleMapParser::parseConflict() {
+ assert(Tok.is(MMToken::Conflict));
+ SourceLocation ConflictLoc = consumeToken();
+ Module::UnresolvedConflict Conflict;
+
+ // Parse the module-id.
+ if (parseModuleId(Conflict.Id))
+ return;
+
+ // Parse the ','.
+ if (!Tok.is(MMToken::Comma)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
+ << SourceRange(ConflictLoc);
+ return;
+ }
+ consumeToken();
+
+ // Parse the message.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
+ << formatModuleId(Conflict.Id);
+ return;
+ }
+ Conflict.Message = Tok.getString().str();
+ consumeToken();
+
+ // Add this unresolved conflict.
+ ActiveModule->UnresolvedConflicts.push_back(Conflict);
+}
+
+/// \brief Parse an inferred module declaration (wildcard modules).
///
/// module-declaration:
/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]
@@ -1593,6 +1816,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
// Decode the attribute name.
AttributeKind Attribute
= llvm::StringSwitch<AttributeKind>(Tok.getString())
+ .Case("exhaustive", AT_exhaustive)
.Case("system", AT_system)
.Default(AT_unknown);
switch (Attribute) {
@@ -1604,6 +1828,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
case AT_system:
Attrs.IsSystem = true;
break;
+
+ case AT_exhaustive:
+ Attrs.IsExhaustive = true;
+ break;
}
consumeToken();
@@ -1653,13 +1881,16 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::FrameworkKeyword:
parseModuleDecl();
break;
-
+
case MMToken::Comma:
+ case MMToken::ConfigMacros:
+ case MMToken::Conflict:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
case MMToken::LBrace:
+ case MMToken::LinkKeyword:
case MMToken::LSquare:
case MMToken::Period:
case MMToken::RBrace:
@@ -1677,11 +1908,16 @@ bool ModuleMapParser::parseModuleMapFile() {
}
bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, bool>::iterator Known
+ = ParsedModuleMap.find(File);
+ if (Known != ParsedModuleMap.end())
+ return Known->second;
+
assert(Target != 0 && "Missing target information");
FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
if (!Buffer)
- return true;
+ return ParsedModuleMap[File] = true;
// Parse this module map file.
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
@@ -1690,6 +1926,6 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
BuiltinIncludeDir);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
-
+ ParsedModuleMap[File] = Result;
return Result;
}
diff --git a/lib/Lex/PPConditionalDirectiveRecord.cpp b/lib/Lex/PPConditionalDirectiveRecord.cpp
new file mode 100644
index 000000000000..16ce3efb0461
--- /dev/null
+++ b/lib/Lex/PPConditionalDirectiveRecord.cpp
@@ -0,0 +1,120 @@
+//===--- PPConditionalDirectiveRecord.h - Preprocessing Directives-*- 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 PPConditionalDirectiveRecord class, which maintains
+// a record of conditional directive regions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
+#include "llvm/Support/Capacity.h"
+
+using namespace clang;
+
+PPConditionalDirectiveRecord::PPConditionalDirectiveRecord(SourceManager &SM)
+ : SourceMgr(SM) {
+ CondDirectiveStack.push_back(SourceLocation());
+}
+
+bool PPConditionalDirectiveRecord::rangeIntersectsConditionalDirective(
+ SourceRange Range) const {
+ if (Range.isInvalid())
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
+ if (low == CondDirectiveLocs.end())
+ return false;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ upp = std::upper_bound(low, CondDirectiveLocs.end(),
+ Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
+ SourceLocation uppRegion;
+ if (upp != CondDirectiveLocs.end())
+ uppRegion = upp->getRegionLoc();
+
+ return low->getRegionLoc() != uppRegion;
+}
+
+SourceLocation PPConditionalDirectiveRecord::findConditionalDirectiveRegionLoc(
+ SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return SourceLocation();
+ if (CondDirectiveLocs.empty())
+ return SourceLocation();
+
+ if (SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
+ Loc))
+ return CondDirectiveStack.back();
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Loc, CondDirectiveLoc::Comp(SourceMgr));
+ assert(low != CondDirectiveLocs.end());
+ return low->getRegionLoc();
+}
+
+void PPConditionalDirectiveRecord::addCondDirectiveLoc(
+ CondDirectiveLoc DirLoc) {
+ // Ignore directives in system headers.
+ if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
+ return;
+
+ assert(CondDirectiveLocs.empty() ||
+ SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
+ DirLoc.getLoc()));
+ CondDirectiveLocs.push_back(DirLoc);
+}
+
+void PPConditionalDirectiveRecord::If(SourceLocation Loc,
+ SourceRange ConditionRange) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(Loc);
+}
+
+void PPConditionalDirectiveRecord::Ifdef(SourceLocation Loc,
+ const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(Loc);
+}
+
+void PPConditionalDirectiveRecord::Ifndef(SourceLocation Loc,
+ const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(Loc);
+}
+
+void PPConditionalDirectiveRecord::Elif(SourceLocation Loc,
+ SourceRange ConditionRange,
+ SourceLocation IfLoc) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.back() = Loc;
+}
+
+void PPConditionalDirectiveRecord::Else(SourceLocation Loc,
+ SourceLocation IfLoc) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.back() = Loc;
+}
+
+void PPConditionalDirectiveRecord::Endif(SourceLocation Loc,
+ SourceLocation IfLoc) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ assert(!CondDirectiveStack.empty());
+ CondDirectiveStack.pop_back();
+}
+
+size_t PPConditionalDirectiveRecord::getTotalMemory() const {
+ return llvm::capacity_in_bytes(CondDirectiveLocs);
+}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index b7c1846e82be..07c186701000 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -13,17 +13,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Pragma.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -56,12 +57,42 @@ MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
return MI;
}
-MacroInfo *Preprocessor::CloneMacroInfo(const MacroInfo &MacroToClone) {
- MacroInfo *MI = AllocateMacroInfo();
- new (MI) MacroInfo(MacroToClone, BP);
+MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L,
+ unsigned SubModuleID) {
+ LLVM_STATIC_ASSERT(llvm::AlignOf<MacroInfo>::Alignment >= sizeof(SubModuleID),
+ "alignment for MacroInfo is less than the ID");
+ MacroInfo *MI =
+ (MacroInfo*)BP.Allocate(sizeof(MacroInfo) + sizeof(SubModuleID),
+ llvm::AlignOf<MacroInfo>::Alignment);
+ new (MI) MacroInfo(L);
+ MI->FromASTFile = true;
+ MI->setOwningModuleID(SubModuleID);
return MI;
}
+DefMacroDirective *
+Preprocessor::AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc,
+ bool isImported) {
+ DefMacroDirective *MD = BP.Allocate<DefMacroDirective>();
+ new (MD) DefMacroDirective(MI, Loc, isImported);
+ return MD;
+}
+
+UndefMacroDirective *
+Preprocessor::AllocateUndefMacroDirective(SourceLocation UndefLoc) {
+ UndefMacroDirective *MD = BP.Allocate<UndefMacroDirective>();
+ new (MD) UndefMacroDirective(UndefLoc);
+ return MD;
+}
+
+VisibilityMacroDirective *
+Preprocessor::AllocateVisibilityMacroDirective(SourceLocation Loc,
+ bool isPublic) {
+ VisibilityMacroDirective *MD = BP.Allocate<VisibilityMacroDirective>();
+ new (MD) VisibilityMacroDirective(Loc, isPublic);
+ return MD;
+}
+
/// \brief Release the specified MacroInfo to be reused for allocating
/// new MacroInfo objects.
void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) {
@@ -140,15 +171,14 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
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.
+ // Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
Diag(MacroNameTok, diag::err_defined_macro_name);
- } else if (isDefineUndef && II->hasMacroDefinition() &&
+ } else if (isDefineUndef == 2 && II->hasMacroDefinition() &&
getMacroInfo(II)->isBuiltinMacro()) {
- // Error if defining "__LINE__" and other builtins: C99 6.10.8.4.
- if (isDefineUndef == 1)
- Diag(MacroNameTok, diag::pp_redef_builtin_macro);
- else
- Diag(MacroNameTok, diag::pp_undef_builtin_macro);
+ // 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);
+ return;
} else {
// Okay, we got a good identifier node. Return it.
return;
@@ -255,7 +285,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// directive mode. Tell the lexer this so any newlines we see will be
// converted into an EOD token (this terminates the macro).
CurPPLexer->ParsingPreprocessorDirective = true;
- if (CurLexer) CurLexer->SetCommentRetentionState(false);
+ if (CurLexer) CurLexer->SetKeepWhitespaceMode(false);
// Read the next token, the directive flavor.
@@ -266,7 +296,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
if (Tok.isNot(tok::raw_identifier)) {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
continue;
}
@@ -282,7 +312,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
FirstChar != 'i' && FirstChar != 'e') {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
continue;
}
@@ -299,7 +329,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
if (IdLen >= 20) {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
continue;
}
memcpy(DirectiveBuf, &DirectiveStr[0], IdLen);
@@ -405,7 +435,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
}
// Finally, if we are out of the conditional (saw an #endif or ran off the end
@@ -536,11 +566,11 @@ const FileEntry *Preprocessor::LookupFile(
// 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.
- // FIXME: SuggestedModule!
if (IsFileLexer()) {
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
- SearchPath, RelativePath)))
+ SearchPath, RelativePath,
+ SuggestedModule)))
return FE;
}
@@ -550,7 +580,8 @@ const FileEntry *Preprocessor::LookupFile(
if ((CurFileEnt =
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
if ((FE = HeaderInfo.LookupSubframeworkHeader(
- Filename, CurFileEnt, SearchPath, RelativePath)))
+ Filename, CurFileEnt, SearchPath, RelativePath,
+ SuggestedModule)))
return FE;
}
}
@@ -590,6 +621,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// mode. Tell the lexer this so any newlines we see will be converted into an
// EOD token (which terminates the directive).
CurPPLexer->ParsingPreprocessorDirective = true;
+ if (CurLexer) CurLexer->SetKeepWhitespaceMode(false);
++NumDirectives;
@@ -634,14 +666,9 @@ void Preprocessor::HandleDirective(Token &Result) {
// and reset to previous state when returning from this function.
ResetMacroExpansionHelper helper(this);
-TryAgain:
switch (Result.getKind()) {
case tok::eod:
return; // null directive.
- case tok::comment:
- // Handle stuff like "# /*foo*/ define X" in -E -C mode.
- LexUnexpandedToken(Result);
- goto TryAgain;
case tok::code_completion:
if (CodeComplete)
CodeComplete->CodeCompleteDirective(
@@ -788,7 +815,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
// here.
Val = 0;
for (unsigned i = 0; i != ActualLength; ++i) {
- if (!isdigit(DigitTokBegin[i])) {
+ if (!isDigit(DigitTokBegin[i])) {
PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i),
diag::err_pp_line_digit_sequence);
PP.DiscardUntilEndOfDirective();
@@ -834,11 +861,11 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
// Enforce C99 6.10.4p3: "The digit sequence shall not specify ... a
// number greater than 2147483647". C90 requires that the line # be <= 32767.
unsigned LineLimit = 32768U;
- if (LangOpts.C99 || LangOpts.CPlusPlus0x)
+ if (LangOpts.C99 || LangOpts.CPlusPlus11)
LineLimit = 2147483648U;
if (LineNo >= LineLimit)
Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
- else if (LangOpts.CPlusPlus0x && LineNo >= 32768U)
+ else if (LangOpts.CPlusPlus11 && LineNo >= 32768U)
Diag(DigitTok, diag::warn_cxx98_compat_pp_line_too_big);
int FilenameID = -1;
@@ -1107,23 +1134,19 @@ void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
// Check to see if this is the last token on the #__public_macro line.
CheckEndOfDirective("__public_macro");
+ IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
// Okay, we finally have a valid identifier to undef.
- MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+ MacroDirective *MD = getMacroDirective(II);
// If the macro is not defined, this is an error.
- if (MI == 0) {
- Diag(MacroNameTok, diag::err_pp_visibility_non_macro)
- << MacroNameTok.getIdentifierInfo();
+ if (MD == 0) {
+ Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II;
return;
}
// Note that this macro has now been exported.
- MI->setVisibility(/*IsPublic=*/true, MacroNameTok.getLocation());
-
- // If this macro definition came from a PCH file, mark it
- // as having changed since serialization.
- if (MI->isFromAST())
- MI->setChangedAfterLoad();
+ appendMacroDirective(II, AllocateVisibilityMacroDirective(
+ MacroNameTok.getLocation(), /*IsPublic=*/true));
}
/// \brief Handle a #private directive.
@@ -1138,23 +1161,19 @@ void Preprocessor::HandleMacroPrivateDirective(Token &Tok) {
// Check to see if this is the last token on the #__private_macro line.
CheckEndOfDirective("__private_macro");
+ IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
// Okay, we finally have a valid identifier to undef.
- MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+ MacroDirective *MD = getMacroDirective(II);
// If the macro is not defined, this is an error.
- if (MI == 0) {
- Diag(MacroNameTok, diag::err_pp_visibility_non_macro)
- << MacroNameTok.getIdentifierInfo();
+ if (MD == 0) {
+ Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II;
return;
}
// Note that this macro has now been marked private.
- MI->setVisibility(/*IsPublic=*/false, MacroNameTok.getLocation());
-
- // If this macro definition came from a PCH file, mark it
- // as having changed since serialization.
- if (MI->isFromAST())
- MI->setChangedAfterLoad();
+ appendMacroDirective(II, AllocateVisibilityMacroDirective(
+ MacroNameTok.getLocation(), /*IsPublic=*/false));
}
//===----------------------------------------------------------------------===//
@@ -1375,7 +1394,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
if (const DirectoryEntry *DE = FileMgr.getDirectory(RecoveryPath)) {
// Add the recovery path to the list of search paths.
- DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+ DirectoryLookup DL(DE, SrcMgr::C_User, false);
HeaderInfo.AddSearchPath(DL, isAngled);
// Try the lookup again, skipping the cache.
@@ -1426,7 +1445,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Compute the module access path corresponding to this module.
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
- llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
for (Module *Mod = SuggestedModule; Mod; Mod = Mod->Parent)
Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
FilenameTok.getLocation()));
@@ -1476,14 +1495,14 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Diag(HashLoc, diag::warn_auto_module_import)
<< IncludeKind << PathString
<< FixItHint::CreateReplacement(ReplaceRange,
- "@__experimental_modules_import " + PathString.str().str() + ";");
+ "@import " + PathString.str().str() + ";");
}
// Load the module.
// If this was an #__include_macros directive, only make macros visible.
Module::NameVisibilityKind Visibility
= (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
- Module *Imported
+ ModuleLoadResult Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
assert((Imported == 0 || Imported == SuggestedModule) &&
@@ -1498,6 +1517,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
return;
}
+
+ // If we failed to find a submodule that we expected to find, we can
+ // continue. Otherwise, there's an error in the included file, so we
+ // don't want to include it.
+ if (!BuildingImportedModule && !Imported.isMissingExpected()) {
+ return;
+ }
}
if (Callbacks && SuggestedModule) {
@@ -1637,10 +1663,16 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
return true;
case tok::ellipsis: // #define X(... -> C99 varargs
if (!LangOpts.C99)
- Diag(Tok, LangOpts.CPlusPlus0x ?
+ Diag(Tok, LangOpts.CPlusPlus11 ?
diag::warn_cxx98_compat_variadic_macro :
diag::ext_variadic_macro);
+ // OpenCL v1.2 s6.9.e: variadic macros are not supported.
+ if (LangOpts.OpenCL) {
+ Diag(Tok, diag::err_pp_opencl_variadic_macros);
+ return true;
+ }
+
// Lex the token after the identifier.
LexUnexpandedToken(Tok);
if (Tok.isNot(tok::r_paren)) {
@@ -1763,7 +1795,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Read the first token after the arg list for down below.
LexUnexpandedToken(Tok);
- } else if (LangOpts.C99 || LangOpts.CPlusPlus0x) {
+ } else if (LangOpts.C99 || LangOpts.CPlusPlus11) {
// C99 requires whitespace between the macro definition and the body. Emit
// a diagnostic for something like "#define X+".
Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name);
@@ -1809,8 +1841,37 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
while (Tok.isNot(tok::eod)) {
LastTok = Tok;
- if (Tok.isNot(tok::hash)) {
+ if (Tok.isNot(tok::hash) && Tok.isNot(tok::hashhash)) {
+ MI->AddTokenToBody(Tok);
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ continue;
+ }
+
+ if (Tok.is(tok::hashhash)) {
+
+ // If we see token pasting, check if it looks like the gcc comma
+ // pasting extension. We'll use this information to suppress
+ // diagnostics later on.
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+
+ if (Tok.is(tok::eod)) {
+ MI->AddTokenToBody(LastTok);
+ break;
+ }
+
+ unsigned NumTokens = MI->getNumTokens();
+ if (NumTokens && Tok.getIdentifierInfo() == Ident__VA_ARGS__ &&
+ MI->getReplacementToken(NumTokens-1).is(tok::comma))
+ MI->setHasCommaPasting();
+
+ // Things look ok, add the '##' and param name tokens to the macro.
+ MI->AddTokenToBody(LastTok);
MI->AddTokenToBody(Tok);
+ LastTok = Tok;
// Get the next token of the macro.
LexUnexpandedToken(Tok);
@@ -1874,7 +1935,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Finally, if this identifier already had a macro defined for it, verify that
// the macro bodies are identical, and issue diagnostics if they are not.
- if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) {
+ if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) {
// It is very common for system headers to have tons of macro redefinitions
// and for warnings to be disabled in system headers. If this is the case,
// then don't bother calling MacroInfo::isIdenticalTo.
@@ -1883,10 +1944,14 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
if (!OtherMI->isUsed() && OtherMI->isWarnIfUnused())
Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
+ // Warn if defining "__LINE__" and other builtins, per C99 6.10.8/4 and
+ // C++ [cpp.predefined]p4, but allow it as an extension.
+ if (OtherMI->isBuiltinMacro())
+ Diag(MacroNameTok, diag::ext_pp_redef_builtin_macro);
// Macros must be identical. This means all tokens and whitespace
- // separation must be the same. C99 6.10.3.2.
- if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
- !MI->isIdenticalTo(*OtherMI, *this)) {
+ // separation must be the same. C99 6.10.3p2.
+ else if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
+ !MI->isIdenticalTo(*OtherMI, *this, /*Syntactic=*/LangOpts.MicrosoftExt)) {
Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef)
<< MacroNameTok.getIdentifierInfo();
Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition);
@@ -1896,7 +1961,8 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
WarnUnusedMacroLocs.erase(OtherMI->getDefinitionLoc());
}
- setMacroInfo(MacroNameTok.getIdentifierInfo(), MI);
+ DefMacroDirective *MD =
+ appendDefMacroDirective(MacroNameTok.getIdentifierInfo(), MI);
assert(!MI->isUsed());
// If we need warning for not using the macro, add its location in the
@@ -1910,7 +1976,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// If the callbacks want to know, tell them about the macro definition.
if (Callbacks)
- Callbacks->MacroDefined(MacroNameTok, MI);
+ Callbacks->MacroDefined(MacroNameTok, MD);
}
/// HandleUndefDirective - Implements \#undef.
@@ -1929,7 +1995,13 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
CheckEndOfDirective("undef");
// Okay, we finally have a valid identifier to undef.
- MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+ MacroDirective *MD = getMacroDirective(MacroNameTok.getIdentifierInfo());
+ const MacroInfo *MI = MD ? MD->getMacroInfo() : 0;
+
+ // If the callbacks want to know, tell them about the macro #undef.
+ // Note: no matter if the macro was defined or not.
+ if (Callbacks)
+ Callbacks->MacroUndefined(MacroNameTok, MD);
// If the macro is not defined, this is a noop undef, just return.
if (MI == 0) return;
@@ -1937,27 +2009,11 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
if (!MI->isUsed() && MI->isWarnIfUnused())
Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
- // If the callbacks want to know, tell them about the macro #undef.
- if (Callbacks)
- Callbacks->MacroUndefined(MacroNameTok, MI);
-
if (MI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
- UndefineMacro(MacroNameTok.getIdentifierInfo(), MI,
- MacroNameTok.getLocation());
-}
-
-void Preprocessor::UndefineMacro(IdentifierInfo *II, MacroInfo *MI,
- SourceLocation UndefLoc) {
- MI->setUndefLoc(UndefLoc);
- if (MI->isFromAST()) {
- MI->setChangedAfterLoad();
- if (Listener)
- Listener->UndefinedMacro(MI);
- }
-
- clearMacroInfo(II);
+ appendMacroDirective(MacroNameTok.getIdentifierInfo(),
+ AllocateUndefMacroDirective(MacroNameTok.getLocation()));
}
@@ -1991,7 +2047,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
- MacroInfo *MI = getMacroInfo(MII);
+ MacroDirective *MD = getMacroDirective(MII);
+ MacroInfo *MI = MD ? MD->getMacroInfo() : 0;
if (CurPPLexer->getConditionalStackDepth() == 0) {
// If the start of a top-level #ifdef and if the macro is not defined,
@@ -2011,9 +2068,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
if (Callbacks) {
if (isIfndef)
- Callbacks->Ifndef(DirectiveTok.getLocation(), MacroNameTok);
+ Callbacks->Ifndef(DirectiveTok.getLocation(), MacroNameTok, MD);
else
- Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok);
+ Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok, MD);
}
// Should we include the stuff contained by this directive?
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index d5a88db470d8..d9ce8bff237c 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -17,13 +17,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
namespace {
@@ -111,15 +112,21 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.Val = II->hasMacroDefinition();
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+ MacroDirective *Macro = 0;
// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive) {
- MacroInfo *Macro = PP.getMacroInfo(II);
- PP.markMacroAsUsed(Macro);
+ Macro = PP.getMacroDirective(II);
+ PP.markMacroAsUsed(Macro->getMacroInfo());
}
// Invoke the 'defined' callback.
- if (PPCallbacks *Callbacks = PP.getPPCallbacks())
- Callbacks->Defined(PeekTok);
+ if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
+ MacroDirective *MD = Macro;
+ // Pass the MacroInfo for the macro name even if the value is dead.
+ if (!MD && Result.Val != 0)
+ MD = PP.getMacroDirective(II);
+ Callbacks->Defined(PeekTok, MD);
+ }
// If we are in parens, ensure we have a trailing ).
if (LParenLoc.isValid()) {
@@ -224,7 +231,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (!PP.getLangOpts().C99 && Literal.isLongLong) {
if (PP.getLangOpts().CPlusPlus)
PP.Diag(PeekTok,
- PP.getLangOpts().CPlusPlus0x ?
+ PP.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
PP.Diag(PeekTok, diag::ext_c99_longlong);
@@ -258,9 +265,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
return false;
}
case tok::char_constant: // 'x'
- case tok::wide_char_constant: { // L'x'
+ case tok::wide_char_constant: // L'x'
case tok::utf16_char_constant: // u'x'
- case tok::utf32_char_constant: // U'x'
+ case tok::utf32_char_constant: { // U'x'
// Complain about, and drop, any ud-suffix.
if (PeekTok.hasUDSuffix())
PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0;
@@ -724,6 +731,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
/// to "!defined(X)" return X in IfNDefMacro.
bool Preprocessor::
EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
+ SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
// Save the current state of 'DisableMacroExpansion' and reset it to false. If
// 'DisableMacroExpansion' is true, then we must be in a macro argument list
// in which case a directive is undefined behavior. We want macros to be able
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index d827f58a485f..be4defe78648 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -13,15 +13,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroInfo.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PathV2.h"
-#include "llvm/ADT/StringSwitch.h"
using namespace clang;
PPCallbacks::~PPCallbacks() {}
@@ -158,15 +158,17 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
/// tokens from it instead of the current buffer.
void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
MacroInfo *Macro, MacroArgs *Args) {
- PushIncludeMacroStack();
- CurDirLookup = 0;
-
+ TokenLexer *TokLexer;
if (NumCachedTokenLexers == 0) {
- CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Macro, Args, *this));
+ TokLexer = new TokenLexer(Tok, ILEnd, Macro, Args, *this);
} else {
- CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
- CurTokenLexer->Init(Tok, ILEnd, Macro, Args);
+ TokLexer = TokenLexerCache[--NumCachedTokenLexers];
+ TokLexer->Init(Tok, ILEnd, Macro, Args);
}
+
+ PushIncludeMacroStack();
+ CurDirLookup = 0;
+ CurTokenLexer.reset(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
}
@@ -186,18 +188,20 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
bool DisableMacroExpansion,
bool OwnsTokens) {
- // Save our current state.
- PushIncludeMacroStack();
- CurDirLookup = 0;
-
// Create a macro expander to expand from the specified token stream.
+ TokenLexer *TokLexer;
if (NumCachedTokenLexers == 0) {
- CurTokenLexer.reset(new TokenLexer(Toks, NumToks, DisableMacroExpansion,
- OwnsTokens, *this));
+ TokLexer = new TokenLexer(Toks, NumToks, DisableMacroExpansion,
+ OwnsTokens, *this);
} else {
- CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
- CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
+ TokLexer = TokenLexerCache[--NumCachedTokenLexers];
+ TokLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
}
+
+ // Save our current state.
+ PushIncludeMacroStack();
+ CurDirLookup = 0;
+ CurTokenLexer.reset(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
}
@@ -328,6 +332,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
CurLexer->BufferPtr = EndPos;
CurLexer->FormTokenWithChars(Result, EndPos, tok::eof);
+ if (isCodeCompletionEnabled()) {
+ // Inserting the code-completion point increases the source buffer by 1,
+ // but the main FileID was created before inserting the point.
+ // Compensate by reducing the EOF location by 1, otherwise the location
+ // will point to the next FileID.
+ // FIXME: This is hacky, the code-completion point should probably be
+ // inserted before the main FileID is created.
+ if (CurLexer->getFileLoc() == CodeCompletionFileLoc)
+ Result.setLocation(Result.getLocation().getLocWithOffset(-1));
+ }
+
if (!isIncrementalProcessingEnabled())
// We're done with lexing.
CurLexer.reset();
@@ -380,7 +395,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SmallString<128> RelativePath;
computeRelativePath(FileMgr, Dir, Header, RelativePath);
Diag(StartLoc, diag::warn_uncovered_module_header)
- << RelativePath;
+ << Mod->getFullModuleName() << RelativePath;
}
}
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index eee4342e27ca..21451f581f3a 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -14,25 +14,26 @@
#include "clang/Lex/Preprocessor.h"
#include "MacroArgs.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <ctime>
using namespace clang;
-MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const {
+MacroDirective *
+Preprocessor::getMacroDirectiveHistory(const IdentifierInfo *II) const {
assert(II->hadMacroDefinition() && "Identifier has not been not a macro!");
macro_iterator Pos = Macros.find(II);
@@ -40,125 +41,31 @@ MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const {
return Pos->second;
}
-/// setMacroInfo - Specify a macro for this identifier.
-///
-void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
- assert(MI && "MacroInfo should be non-zero!");
- assert(MI->getUndefLoc().isInvalid() &&
- "Undefined macros cannot be registered");
-
- MacroInfo *&StoredMI = Macros[II];
- MI->setPreviousDefinition(StoredMI);
- StoredMI = MI;
- II->setHasMacroDefinition(MI->getUndefLoc().isInvalid());
- if (II->isFromAST())
- II->setChangedSinceDeserialization();
-}
-
-void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI,
- MacroInfo *Hint) {
- assert(MI && "Missing macro?");
- assert(MI->isFromAST() && "Macro is not from an AST?");
- assert(!MI->getPreviousDefinition() && "Macro already in chain?");
-
- MacroInfo *&StoredMI = Macros[II];
-
- // Easy case: this is the first macro definition for this macro.
- if (!StoredMI) {
- StoredMI = MI;
-
- if (MI->isDefined())
- II->setHasMacroDefinition(true);
- return;
- }
-
- // If this macro is a definition and this identifier has been neither
- // defined nor undef'd in the current translation unit, add this macro
- // to the end of the chain of definitions.
- if (MI->isDefined() && StoredMI->isFromAST()) {
- // Simple case: if this is the first actual definition, just put it at
- // th beginning.
- if (!StoredMI->isDefined()) {
- MI->setPreviousDefinition(StoredMI);
- StoredMI = MI;
-
- II->setHasMacroDefinition(true);
- return;
- }
-
- // Find the end of the definition chain.
- MacroInfo *Prev;
- MacroInfo *PrevPrev = StoredMI;
- bool Ambiguous = StoredMI->isAmbiguous();
- bool MatchedOther = false;
- do {
- Prev = PrevPrev;
-
- // If the macros are not identical, we have an ambiguity.
- if (!Prev->isIdenticalTo(*MI, *this)) {
- if (!Ambiguous) {
- Ambiguous = true;
- StoredMI->setAmbiguous(true);
- }
- } else {
- MatchedOther = true;
- }
- } while ((PrevPrev = Prev->getPreviousDefinition()) &&
- PrevPrev->isDefined());
-
- // If there are ambiguous definitions, and we didn't match any other
- // definition, then mark us as ambiguous.
- if (Ambiguous && !MatchedOther)
- MI->setAmbiguous(true);
-
- // Wire this macro information into the chain.
- MI->setPreviousDefinition(Prev->getPreviousDefinition());
- Prev->setPreviousDefinition(MI);
- return;
- }
-
- // The macro is not a definition; put it at the end of the list.
- MacroInfo *Prev = Hint? Hint : StoredMI;
- while (Prev->getPreviousDefinition())
- Prev = Prev->getPreviousDefinition();
- Prev->setPreviousDefinition(MI);
-}
-
-void Preprocessor::makeLoadedMacroInfoVisible(IdentifierInfo *II,
- MacroInfo *MI) {
- assert(MI->isFromAST() && "Macro must be from the AST");
-
- MacroInfo *&StoredMI = Macros[II];
- if (StoredMI == MI) {
- // Easy case: this is the first macro anyway.
- II->setHasMacroDefinition(MI->isDefined());
- return;
- }
-
- // Go find the macro and pull it out of the list.
- // FIXME: Yes, this is O(N), and making a pile of macros visible or hidden
- // would be quadratic, but it's extremely rare.
- MacroInfo *Prev = StoredMI;
- while (Prev->getPreviousDefinition() != MI)
- Prev = Prev->getPreviousDefinition();
- Prev->setPreviousDefinition(MI->getPreviousDefinition());
- MI->setPreviousDefinition(0);
-
- // Add the macro back to the list.
- addLoadedMacroInfo(II, MI);
-
- II->setHasMacroDefinition(StoredMI->isDefined());
- if (II->isFromAST())
+void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){
+ assert(MD && "MacroDirective should be non-zero!");
+ assert(!MD->getPrevious() && "Already attached to a MacroDirective history.");
+
+ MacroDirective *&StoredMD = Macros[II];
+ MD->setPrevious(StoredMD);
+ StoredMD = MD;
+ II->setHasMacroDefinition(MD->isDefined());
+ bool isImportedMacro = isa<DefMacroDirective>(MD) &&
+ cast<DefMacroDirective>(MD)->isImported();
+ if (II->isFromAST() && !isImportedMacro)
II->setChangedSinceDeserialization();
}
-/// \brief Undefine a macro for this identifier.
-void Preprocessor::clearMacroInfo(IdentifierInfo *II) {
- assert(II->hasMacroDefinition() && "Macro is not defined!");
- assert(Macros[II]->getUndefLoc().isValid() && "Macro is still defined!");
- II->setHasMacroDefinition(false);
- if (II->isFromAST())
- II->setChangedSinceDeserialization();
+void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II,
+ MacroDirective *MD) {
+ assert(II && MD);
+ MacroDirective *&StoredMD = Macros[II];
+ assert(!StoredMD &&
+ "the macro history was modified before initializing it from a pch");
+ StoredMD = MD;
+ // Setup the identifier as having associated macro history.
+ II->setHasMacroDefinition(true);
+ if (!MD->isDefined())
+ II->setHasMacroDefinition(false);
}
/// RegisterBuiltinMacro - Register the specified identifier in the identifier
@@ -170,7 +77,7 @@ static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){
// Mark it as being a macro that is builtin.
MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation());
MI->setIsBuiltinMacro();
- PP.setMacroInfo(Id, MI);
+ PP.appendDefMacroDirective(Id, MI);
return Id;
}
@@ -303,7 +210,11 @@ bool Preprocessor::isNextPPTokenLParen() {
/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be
/// expanded as a macro, handle it and return the next token as 'Identifier'.
bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
- MacroInfo *MI) {
+ MacroDirective *MD) {
+ MacroDirective::DefInfo Def = MD->getDefinition();
+ assert(Def.isValid());
+ MacroInfo *MI = Def.getMacroInfo();
+
// If this is a macro expansion in the "#if !defined(x)" line for the file,
// then the macro could expand to different things in other contexts, we need
// to disable the optimization in this case.
@@ -311,7 +222,7 @@ 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, MI,
+ if (Callbacks) Callbacks->MacroExpands(Identifier, MD,
Identifier.getLocation());
ExpandBuiltinMacro(Identifier);
return false;
@@ -364,13 +275,13 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// MacroExpands callbacks still happen in source order, queue this
// callback to have it happen after the function macro callback.
DelayedMacroExpandsCallbacks.push_back(
- MacroExpandsInfo(Identifier, MI, ExpansionRange));
+ MacroExpandsInfo(Identifier, MD, ExpansionRange));
} else {
- Callbacks->MacroExpands(Identifier, MI, ExpansionRange);
+ Callbacks->MacroExpands(Identifier, MD, ExpansionRange);
if (!DelayedMacroExpandsCallbacks.empty()) {
for (unsigned i=0, e = DelayedMacroExpandsCallbacks.size(); i!=e; ++i) {
MacroExpandsInfo &Info = DelayedMacroExpandsCallbacks[i];
- Callbacks->MacroExpands(Info.Tok, Info.MI, Info.Range);
+ Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range);
}
DelayedMacroExpandsCallbacks.clear();
}
@@ -378,16 +289,17 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
// If the macro definition is ambiguous, complain.
- if (MI->isAmbiguous()) {
+ if (Def.getDirective()->isAmbiguous()) {
Diag(Identifier, diag::warn_pp_ambiguous_macro)
<< Identifier.getIdentifierInfo();
Diag(MI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_chosen)
<< Identifier.getIdentifierInfo();
- for (MacroInfo *PrevMI = MI->getPreviousDefinition();
- PrevMI && PrevMI->isDefined();
- PrevMI = PrevMI->getPreviousDefinition()) {
- if (PrevMI->isAmbiguous()) {
- Diag(PrevMI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_other)
+ 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();
}
}
@@ -455,7 +367,10 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
if (MacroInfo *NewMI = getMacroInfo(NewII))
if (!NewMI->isEnabled() || NewMI == MI) {
Identifier.setFlag(Token::DisableExpand);
- Diag(Identifier, diag::pp_disabled_macro_expansion);
+ // Don't warn for "#define X X" like "#define bool bool" from
+ // stdbool.h.
+ if (NewMI != MI || MI->isFunctionLike())
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
}
}
@@ -497,9 +412,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// argument is separated by an EOF token. Use a SmallVector so we can avoid
// heap allocations in the common case.
SmallVector<Token, 64> ArgTokens;
+ bool ContainsCodeCompletionTok = false;
unsigned NumActuals = 0;
while (Tok.isNot(tok::r_paren)) {
+ if (ContainsCodeCompletionTok && (Tok.is(tok::eof) || Tok.is(tok::eod)))
+ break;
+
assert((Tok.is(tok::l_paren) || Tok.is(tok::comma)) &&
"only expect argument separators here");
@@ -516,10 +435,20 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
LexUnexpandedToken(Tok);
if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n"
- Diag(MacroName, diag::err_unterm_macro_invoc);
- // Do not lose the EOF/EOD. Return it to the client.
- MacroName = Tok;
- return 0;
+ if (!ContainsCodeCompletionTok) {
+ Diag(MacroName, diag::err_unterm_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+ // Do not lose the EOF/EOD. Return it to the client.
+ MacroName = Tok;
+ return 0;
+ } else {
+ // Do not lose the EOF/EOD.
+ Token *Toks = new Token[1];
+ Toks[0] = Tok;
+ EnterTokenStream(Toks, 1, true, true);
+ break;
+ }
} else if (Tok.is(tok::r_paren)) {
// If we found the ) token, the macro arg list is done.
if (NumParens-- == 0) {
@@ -550,6 +479,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (!MI->isEnabled())
Tok.setFlag(Token::DisableExpand);
} else if (Tok.is(tok::code_completion)) {
+ ContainsCodeCompletionTok = true;
if (CodeComplete)
CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(),
MI, NumActuals);
@@ -572,16 +502,20 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (ArgTokens.size() != ArgTokenStart)
ArgStartLoc = ArgTokens[ArgTokenStart].getLocation();
- // Emit the diagnostic at the macro name in case there is a missing ).
- // Emitting it at the , could be far away from the macro name.
- Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
- return 0;
+ if (!ContainsCodeCompletionTok) {
+ // Emit the diagnostic at the macro name in case there is a missing ).
+ // Emitting it at the , could be far away from the macro name.
+ Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+ return 0;
+ }
}
// Empty arguments are standard in C99 and C++0x, and are supported as an extension in
// other modes.
if (ArgTokens.size() == ArgTokenStart && !LangOpts.C99)
- Diag(Tok, LangOpts.CPlusPlus0x ?
+ Diag(Tok, LangOpts.CPlusPlus11 ?
diag::warn_cxx98_compat_empty_fnmacro_arg :
diag::ext_empty_fnmacro_arg);
@@ -593,8 +527,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
EOFTok.setLength(0);
ArgTokens.push_back(EOFTok);
++NumActuals;
- assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
- --NumFixedArgsLeft;
+ if (!ContainsCodeCompletionTok || NumFixedArgsLeft != 0) {
+ assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
+ --NumFixedArgsLeft;
+ }
}
// Okay, we either found the r_paren. Check to see if we parsed too few
@@ -604,6 +540,17 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// See MacroArgs instance var for description of this.
bool isVarargsElided = false;
+ if (ContainsCodeCompletionTok) {
+ // Recover from not-fully-formed macro invocation during code-completion.
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(Tok.getLocation());
+ EOFTok.setLength(0);
+ for (; NumActuals < MinArgsExpected; ++NumActuals)
+ ArgTokens.push_back(EOFTok);
+ }
+
if (NumActuals < MinArgsExpected) {
// There are several cases where too few arguments is ok, handle them now.
if (NumActuals == 0 && MinArgsExpected == 1) {
@@ -619,9 +566,14 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Varargs where the named vararg parameter is missing: OK as extension.
// #define A(x, ...)
// A("blah")
- Diag(Tok, diag::ext_missing_varargs_arg);
- Diag(MI->getDefinitionLoc(), diag::note_macro_here)
- << MacroName.getIdentifierInfo();
+ //
+ // If the macro contains the comma pasting extension, the diagnostic
+ // is suppressed; we know we'll get another diagnostic later.
+ if (!MI->hasCommaPasting()) {
+ Diag(Tok, diag::ext_missing_varargs_arg);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+ }
// Remember this occurred, allowing us to elide the comma when used for
// cases like:
@@ -630,9 +582,11 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// #define C(...) blah(a, ## __VA_ARGS__)
// A(x) B(x) C()
isVarargsElided = true;
- } else {
+ } else if (!ContainsCodeCompletionTok) {
// Otherwise, emit the error.
Diag(Tok, diag::err_too_few_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
return 0;
}
@@ -648,10 +602,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (NumActuals == 0 && MinArgsExpected == 2)
ArgTokens.push_back(Tok);
- } else if (NumActuals > MinArgsExpected && !MI->isVariadic()) {
+ } else if (NumActuals > MinArgsExpected && !MI->isVariadic() &&
+ !ContainsCodeCompletionTok) {
// Emit the diagnostic at the macro name in case there is a missing ).
// Emitting it at the , could be far away from the macro name.
Diag(MacroName, diag::err_too_many_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
return 0;
}
@@ -745,7 +702,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
Feature = Feature.substr(2, Feature.size() - 4);
return llvm::StringSwitch<bool>(Feature)
- .Case("address_sanitizer", LangOpts.SanitizeAddress)
+ .Case("address_sanitizer", LangOpts.Sanitize.Address)
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
.Case("attribute_availability_with_message", true)
@@ -767,6 +724,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
+ .Case("memory_sanitizer", LangOpts.Sanitize.Memory)
+ .Case("thread_sanitizer", LangOpts.Sanitize.Thread)
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
@@ -776,6 +735,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_instancetype", LangOpts.ObjC2)
.Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
.Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
+ .Case("objc_property_explicit_atomic", true) // Does clang support explicit "atomic" keyword?
.Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
.Case("ownership_holds", true)
.Case("ownership_returns", true)
@@ -792,41 +752,41 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("c_generic_selections", LangOpts.C11)
.Case("c_static_assert", LangOpts.C11)
// C++11 features
- .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
- .Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
- .Case("cxx_alignas", LangOpts.CPlusPlus0x)
- .Case("cxx_atomic", LangOpts.CPlusPlus0x)
- .Case("cxx_attributes", LangOpts.CPlusPlus0x)
- .Case("cxx_auto_type", LangOpts.CPlusPlus0x)
- .Case("cxx_constexpr", LangOpts.CPlusPlus0x)
- .Case("cxx_decltype", LangOpts.CPlusPlus0x)
- .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus0x)
- .Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x)
- .Case("cxx_defaulted_functions", LangOpts.CPlusPlus0x)
- .Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x)
- .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
- .Case("cxx_explicit_conversions", LangOpts.CPlusPlus0x)
- .Case("cxx_generalized_initializers", LangOpts.CPlusPlus0x)
- .Case("cxx_implicit_moves", LangOpts.CPlusPlus0x)
+ .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11)
+ .Case("cxx_alias_templates", LangOpts.CPlusPlus11)
+ .Case("cxx_alignas", LangOpts.CPlusPlus11)
+ .Case("cxx_atomic", LangOpts.CPlusPlus11)
+ .Case("cxx_attributes", LangOpts.CPlusPlus11)
+ .Case("cxx_auto_type", LangOpts.CPlusPlus11)
+ .Case("cxx_constexpr", LangOpts.CPlusPlus11)
+ .Case("cxx_decltype", LangOpts.CPlusPlus11)
+ .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus11)
+ .Case("cxx_default_function_template_args", LangOpts.CPlusPlus11)
+ .Case("cxx_defaulted_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_delegating_constructors", LangOpts.CPlusPlus11)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11)
+ .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11)
+ .Case("cxx_implicit_moves", LangOpts.CPlusPlus11)
//.Case("cxx_inheriting_constructors", false)
- .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
- .Case("cxx_lambdas", LangOpts.CPlusPlus0x)
- .Case("cxx_local_type_template_args", LangOpts.CPlusPlus0x)
- .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus0x)
- .Case("cxx_noexcept", LangOpts.CPlusPlus0x)
- .Case("cxx_nullptr", LangOpts.CPlusPlus0x)
- .Case("cxx_override_control", LangOpts.CPlusPlus0x)
- .Case("cxx_range_for", LangOpts.CPlusPlus0x)
- .Case("cxx_raw_string_literals", LangOpts.CPlusPlus0x)
- .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
- .Case("cxx_rvalue_references", LangOpts.CPlusPlus0x)
- .Case("cxx_strong_enums", LangOpts.CPlusPlus0x)
- .Case("cxx_static_assert", LangOpts.CPlusPlus0x)
- .Case("cxx_trailing_return", LangOpts.CPlusPlus0x)
- .Case("cxx_unicode_literals", LangOpts.CPlusPlus0x)
- .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus0x)
- .Case("cxx_user_literals", LangOpts.CPlusPlus0x)
- .Case("cxx_variadic_templates", LangOpts.CPlusPlus0x)
+ .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11)
+ .Case("cxx_lambdas", LangOpts.CPlusPlus11)
+ .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11)
+ .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus11)
+ .Case("cxx_noexcept", LangOpts.CPlusPlus11)
+ .Case("cxx_nullptr", LangOpts.CPlusPlus11)
+ .Case("cxx_override_control", LangOpts.CPlusPlus11)
+ .Case("cxx_range_for", LangOpts.CPlusPlus11)
+ .Case("cxx_raw_string_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_rvalue_references", LangOpts.CPlusPlus11)
+ .Case("cxx_strong_enums", LangOpts.CPlusPlus11)
+ .Case("cxx_static_assert", LangOpts.CPlusPlus11)
+ .Case("cxx_trailing_return", LangOpts.CPlusPlus11)
+ .Case("cxx_unicode_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11)
+ .Case("cxx_user_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_variadic_templates", LangOpts.CPlusPlus11)
// Type traits
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
.Case("has_nothrow_copy", LangOpts.CPlusPlus)
@@ -840,10 +800,6 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_base_of", LangOpts.CPlusPlus)
.Case("is_class", LangOpts.CPlusPlus)
.Case("is_convertible_to", LangOpts.CPlusPlus)
- // __is_empty is available only if the horrible
- // "struct __is_empty" parsing hack hasn't been needed in this
- // translation unit. If it has, __is_empty reverts to a normal
- // identifier and __has_feature(is_empty) evaluates false.
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_final", LangOpts.CPlusPlus)
@@ -926,9 +882,15 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
IdentifierInfo *II, Preprocessor &PP,
const DirectoryLookup *LookupFrom) {
// Save the location of the current token. If a '(' is later found, use
- // that location. If no, use the end of this location instead.
+ // that location. If not, use the end of this location instead.
SourceLocation LParenLoc = Tok.getLocation();
+ // These expressions are only allowed within a preprocessor directive.
+ if (!PP.isParsingIfOrElifDirective()) {
+ PP.Diag(LParenLoc, diag::err_pp_directive_required) << II->getName();
+ return false;
+ }
+
// Get '('.
PP.LexNonComment(Tok);
@@ -946,8 +908,14 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Save '(' location for possible missing ')' message.
LParenLoc = Tok.getLocation();
- // Get the file name.
- PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ if (PP.getCurrentLexer()) {
+ // Get the file name.
+ PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ } else {
+ // We're in a macro, so we can't use LexIncludeFilename; just
+ // grab the next token.
+ PP.Lex(Tok);
+ }
}
// Reserve a buffer to get the spelling.
@@ -1223,15 +1191,15 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
IdentifierInfo *FeatureII = 0;
// Read the '('.
- Lex(Tok);
+ LexUnexpandedToken(Tok);
if (Tok.is(tok::l_paren)) {
// Read the identifier
- Lex(Tok);
+ LexUnexpandedToken(Tok);
if (Tok.is(tok::identifier) || Tok.is(tok::kw_const)) {
FeatureII = Tok.getIdentifierInfo();
// Read the ')'.
- Lex(Tok);
+ LexUnexpandedToken(Tok);
if (Tok.is(tok::r_paren))
IsValid = true;
}
@@ -1275,69 +1243,49 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
bool IsValid = false;
bool Value = false;
// Read the '('.
- Lex(Tok);
+ LexUnexpandedToken(Tok);
do {
- if (Tok.is(tok::l_paren)) {
- // Read the string.
- Lex(Tok);
-
- // We need at least one string literal.
- if (!Tok.is(tok::string_literal)) {
- StartLoc = Tok.getLocation();
- IsValid = false;
- // Eat tokens until ')'.
- do Lex(Tok); while (!(Tok.is(tok::r_paren) || Tok.is(tok::eod)));
- break;
- }
-
- // String concatenation allows multiple strings, which can even come
- // from macro expansion.
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- // Complain about, and drop, any ud-suffix.
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- StrToks.push_back(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(StartLoc, diag::err_warning_check_malformed);
+ break;
+ }
+
+ LexUnexpandedToken(Tok);
+ std::string WarningName;
+ SourceLocation StrStartLoc = Tok.getLocation();
+ if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'",
+ /*MacroExpansion=*/false)) {
+ // Eat tokens until ')'.
+ while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
+ Tok.isNot(tok::eof))
LexUnexpandedToken(Tok);
- }
-
- // Is the end a ')'?
- if (!(IsValid = Tok.is(tok::r_paren)))
- break;
-
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- break;
- if (Literal.Pascal) {
- Diag(Tok, diag::warn_pragma_diagnostic_invalid);
- break;
- }
-
- StringRef WarningName(Literal.GetString());
-
- if (WarningName.size() < 3 || WarningName[0] != '-' ||
- WarningName[1] != 'W') {
- Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option);
- break;
- }
-
- // Finally, check if the warning flags maps to a diagnostic group.
- // We construct a SmallVector here to talk to getDiagnosticIDs().
- // Although we don't use the result, this isn't a hot path, and not
- // worth special casing.
- llvm::SmallVector<diag::kind, 10> Diags;
- Value = !getDiagnostics().getDiagnosticIDs()->
- getDiagnosticsInGroup(WarningName.substr(2), Diags);
+ break;
+ }
+
+ // Is the end a ')'?
+ if (!(IsValid = Tok.is(tok::r_paren))) {
+ Diag(StartLoc, diag::err_warning_check_malformed);
+ break;
+ }
+
+ if (WarningName.size() < 3 || WarningName[0] != '-' ||
+ WarningName[1] != 'W') {
+ Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
+ break;
}
+
+ // Finally, check if the warning flags maps to a diagnostic group.
+ // We construct a SmallVector here to talk to getDiagnosticIDs().
+ // Although we don't use the result, this isn't a hot path, and not
+ // worth special casing.
+ SmallVector<diag::kind, 10> Diags;
+ Value = !getDiagnostics().getDiagnosticIDs()->
+ getDiagnosticsInGroup(WarningName.substr(2), Diags);
} while (false);
-
- if (!IsValid)
- Diag(StartLoc, diag::err_warning_check_malformed);
OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ if (IsValid)
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__building_module) {
// The argument to this builtin should be an identifier. The
// builtin evaluates to 1 when that identifier names the module we are
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index b1671721b630..e8f43f7e50a7 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -11,17 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/PTHLexer.h"
#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/PTHLexer.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PTHManager.h"
-#include "clang/Lex/Token.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"
@@ -679,13 +678,13 @@ public:
~PTHStatCache() {}
LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
+ bool isFile, int *FileDescriptor) {
// 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, StatBuf, FileDescriptor);
+ return statChained(Path, StatBuf, isFile, FileDescriptor);
const PTHStatData &Data = *I;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index e7e6c3705376..95e8a8ca8fc8 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -13,13 +13,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Pragma.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
@@ -184,7 +184,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Read the '"..."'.
Lex(Tok);
- if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
+ if (!tok::isStringLiteral(Tok.getKind())) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
// Skip this token, and the ')', if present.
if (Tok.isNot(tok::r_paren))
@@ -219,15 +219,50 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
SourceLocation RParenLoc = Tok.getLocation();
std::string StrVal = getSpelling(StrTok);
- // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1:
- // "The string literal is destringized by deleting the L prefix, if present,
+ // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1:
+ // "The string literal is destringized by deleting any encoding prefix,
// deleting the leading and trailing double-quotes, replacing each escape
// sequence \" by a double-quote, and replacing each escape sequence \\ by a
// single backslash."
- if (StrVal[0] == 'L') // Remove L prefix.
+ if (StrVal[0] == 'L' || StrVal[0] == 'U' ||
+ (StrVal[0] == 'u' && StrVal[1] != '8'))
StrVal.erase(StrVal.begin());
- assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
- "Invalid string token!");
+ else if (StrVal[0] == 'u')
+ StrVal.erase(StrVal.begin(), StrVal.begin() + 2);
+
+ if (StrVal[0] == 'R') {
+ // FIXME: C++11 does not specify how to handle raw-string-literals here.
+ // We strip off the 'R', the quotes, the d-char-sequences, and the parens.
+ assert(StrVal[1] == '"' && StrVal[StrVal.size() - 1] == '"' &&
+ "Invalid raw string token!");
+
+ // Measure the length of the d-char-sequence.
+ unsigned NumDChars = 0;
+ while (StrVal[2 + NumDChars] != '(') {
+ assert(NumDChars < (StrVal.size() - 5) / 2 &&
+ "Invalid raw string token!");
+ ++NumDChars;
+ }
+ assert(StrVal[StrVal.size() - 2 - NumDChars] == ')');
+
+ // Remove 'R " d-char-sequence' and 'd-char-sequence "'. We'll replace the
+ // parens below.
+ StrVal.erase(0, 2 + NumDChars);
+ StrVal.erase(StrVal.size() - 1 - NumDChars);
+ } else {
+ assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
+ "Invalid string token!");
+
+ // Remove escaped quotes and escapes.
+ for (unsigned i = 1, e = StrVal.size(); i < e-2; ++i) {
+ if (StrVal[i] == '\\' &&
+ (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
+ // \\ -> '\' and \" -> '"'.
+ StrVal.erase(StrVal.begin()+i);
+ --e;
+ }
+ }
+ }
// Remove the front quote, replacing it with a space, so that the pragma
// contents appear to have a space before them.
@@ -236,16 +271,6 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Replace the terminating quote with a \n.
StrVal[StrVal.size()-1] = '\n';
- // Remove escaped quotes and escapes.
- for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) {
- if (StrVal[i] == '\\' &&
- (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
- // \\ -> '\' and \" -> '"'.
- StrVal.erase(StrVal.begin()+i);
- --e;
- }
- }
-
// Plop the string (including the newline and trailing null) into a buffer
// where we can lex it.
Token TmpTok;
@@ -470,7 +495,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
///
/// The syntax is:
/// \code
-/// \#pragma comment(linker, "foo")
+/// #pragma comment(linker, "foo")
/// \endcode
/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user.
/// "foo" is a string, which is fully macro expanded, and permits string
@@ -502,38 +527,10 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
// Read the optional string if present.
Lex(Tok);
std::string ArgumentString;
- if (Tok.is(tok::comma)) {
- Lex(Tok); // eat the comma.
-
- // We need at least one string.
- if (Tok.isNot(tok::string_literal)) {
- Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
- return;
- }
-
- // String concatenation allows multiple strings, which can even come from
- // macro expansion.
- // "foo " "bar" "Baz"
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- StrToks.push_back(Tok);
- Lex(Tok);
- }
-
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- return;
- if (Literal.Pascal) {
- Diag(StrToks[0].getLocation(), diag::err_pragma_comment_malformed);
- return;
- }
-
- ArgumentString = Literal.GetString();
- }
+ if (Tok.is(tok::comma) && !LexStringLiteral(Tok, ArgumentString,
+ "pragma comment",
+ /*MacroExpansion=*/true))
+ return;
// FIXME: If the kind is "compiler" warn if the string is present (it is
// ignored).
@@ -560,11 +557,11 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
/// HandlePragmaMessage - Handle the microsoft and gcc \#pragma message
/// extension. The syntax is:
/// \code
-/// \#pragma message(string)
+/// #pragma message(string)
/// \endcode
/// OR, in GCC mode:
/// \code
-/// \#pragma message string
+/// #pragma message string
/// \endcode
/// string is a string, which is fully macro expanded, and permits string
/// concatenation, embedded escape characters, etc... See MSDN for more details.
@@ -587,34 +584,10 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
return;
}
- // We need at least one string.
- if (Tok.isNot(tok::string_literal)) {
- Diag(Tok.getLocation(), diag::err_pragma_message_malformed);
- return;
- }
-
- // String concatenation allows multiple strings, which can even come from
- // macro expansion.
- // "foo " "bar" "Baz"
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- StrToks.push_back(Tok);
- Lex(Tok);
- }
-
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- return;
- if (Literal.Pascal) {
- Diag(StrToks[0].getLocation(), diag::err_pragma_message_malformed);
+ std::string MessageString;
+ if (!FinishLexStringLiteral(Tok, MessageString, "pragma message",
+ /*MacroExpansion=*/true))
return;
- }
-
- StringRef MessageString(Literal.GetString());
if (ExpectClosingParen) {
if (Tok.isNot(tok::r_paren)) {
@@ -692,7 +665,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
///
/// The syntax is:
/// \code
-/// \#pragma push_macro("macro")
+/// #pragma push_macro("macro")
/// \endcode
void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) {
// Parse the pragma directive and get the macro IdentifierInfo*.
@@ -702,17 +675,13 @@ void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) {
// Get the MacroInfo associated with IdentInfo.
MacroInfo *MI = getMacroInfo(IdentInfo);
- MacroInfo *MacroCopyToPush = 0;
if (MI) {
- // Make a clone of MI.
- MacroCopyToPush = CloneMacroInfo(*MI);
-
// Allow the original MacroInfo to be redefined later.
MI->setIsAllowRedefinitionsWithoutWarning(true);
}
// Push the cloned MacroInfo so we can retrieve it later.
- PragmaPushMacroInfo[IdentInfo].push_back(MacroCopyToPush);
+ PragmaPushMacroInfo[IdentInfo].push_back(MI);
}
/// \brief Handle \#pragma pop_macro.
@@ -733,10 +702,11 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
PragmaPushMacroInfo.find(IdentInfo);
if (iter != PragmaPushMacroInfo.end()) {
// Forget the MacroInfo currently associated with IdentInfo.
- if (MacroInfo *CurrentMI = getMacroInfo(IdentInfo)) {
- if (CurrentMI->isWarnIfUnused())
- WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc());
- UndefineMacro(IdentInfo, CurrentMI, MessageLoc);
+ if (MacroDirective *CurrentMD = getMacroDirective(IdentInfo)) {
+ MacroInfo *MI = CurrentMD->getMacroInfo();
+ if (MI->isWarnIfUnused())
+ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+ appendMacroDirective(IdentInfo, AllocateUndefMacroDirective(MessageLoc));
}
// Get the MacroInfo we want to reinstall.
@@ -744,9 +714,8 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
if (MacroToReInstall) {
// Reinstall the previously pushed macro.
- setMacroInfo(IdentInfo, MacroToReInstall);
- } else if (IdentInfo->hasMacroDefinition()) {
- clearMacroInfo(IdentInfo);
+ appendDefMacroDirective(IdentInfo, MacroToReInstall, MessageLoc,
+ /*isImported=*/false);
}
// Pop PragmaPushMacroInfo stack.
@@ -1090,50 +1059,28 @@ public:
}
PP.LexUnexpandedToken(Tok);
+ SourceLocation StringLoc = Tok.getLocation();
- // We need at least one string.
- if (Tok.isNot(tok::string_literal)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
+ std::string WarningName;
+ if (!PP.FinishLexStringLiteral(Tok, WarningName, "pragma diagnostic",
+ /*MacroExpansion=*/false))
return;
- }
-
- // String concatenation allows multiple strings, which can even come from
- // macro expansion.
- // "foo " "bar" "Baz"
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- StrToks.push_back(Tok);
- PP.LexUnexpandedToken(Tok);
- }
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
return;
}
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- return;
- if (Literal.Pascal) {
- PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
- return;
- }
-
- StringRef WarningName(Literal.GetString());
-
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
- PP.Diag(StrToks[0].getLocation(),
- diag::warn_pragma_diagnostic_invalid_option);
+ PP.Diag(StringLoc, diag::warn_pragma_diagnostic_invalid_option);
return;
}
if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2),
Map, DiagLoc))
- PP.Diag(StrToks[0].getLocation(),
- diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
+ PP.Diag(StringLoc, diag::warn_pragma_diagnostic_unknown_warning)
+ << WarningName;
else if (Callbacks)
Callbacks->PragmaDiagnostic(DiagLoc, Namespace, Map, WarningName);
}
@@ -1277,6 +1224,29 @@ struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
}
};
+ /// \brief Handle "\#pragma region [...]"
+ ///
+ /// The syntax is
+ /// \code
+ /// #pragma region [optional name]
+ /// #pragma endregion [optional comment]
+ /// \endcode
+ ///
+ /// \note This is
+ /// <a href="http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx">editor-only</a>
+ /// pragma, just skipped by compiler.
+ struct PragmaRegionHandler : public PragmaHandler {
+ PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) { }
+
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) {
+ // #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
+ // to handle a _Pragma differently.
+ }
+ };
+
} // end anonymous namespace
@@ -1310,5 +1280,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
if (LangOpts.MicrosoftExt) {
AddPragmaHandler(new PragmaCommentHandler());
AddPragmaHandler(new PragmaIncludeAliasHandler());
+ AddPragmaHandler(new PragmaRegionHandler("region"));
+ AddPragmaHandler(new PragmaRegionHandler("endregion"));
}
}
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 01f3665e76bd..b10e7f7beeec 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -14,8 +14,8 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Token.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -38,14 +38,9 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
this->FileName = StringRef(Memory, FileName.size());
}
-PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
- bool RecordConditionalDirectives)
+PreprocessingRecord::PreprocessingRecord(SourceManager &SM)
: SourceMgr(SM),
- RecordCondDirectives(RecordConditionalDirectives), CondDirectiveNextIdx(0),
- ExternalSource(0)
-{
- if (RecordCondDirectives)
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ ExternalSource(0) {
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
@@ -97,8 +92,10 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
int Pos = PPEI.Position;
if (Pos < 0) {
- assert(unsigned(-Pos-1) < LoadedPreprocessedEntities.size() &&
- "Out-of bounds loaded preprocessed entity");
+ if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) {
+ assert(0 && "Out-of bounds loaded preprocessed entity");
+ return false;
+ }
assert(ExternalSource && "No external source to load from");
unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;
if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
@@ -106,8 +103,8 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
// See if the external source can see if the entity is in the file without
// deserializing it.
- llvm::Optional<bool>
- IsInFile = ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
+ Optional<bool> IsInFile =
+ ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
if (IsInFile.hasValue())
return IsInFile.getValue();
@@ -118,8 +115,10 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
FID, SourceMgr);
}
- assert(unsigned(Pos) < PreprocessedEntities.size() &&
- "Out-of bounds local preprocessed entity");
+ if (unsigned(Pos) >= PreprocessedEntities.size()) {
+ assert(0 && "Out-of bounds local preprocessed entity");
+ return false;
+ }
return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos],
FID, SourceMgr);
}
@@ -249,11 +248,11 @@ PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
assert(Entity);
SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
- if (!isa<class InclusionDirective>(Entity)) {
+ if (isa<MacroDefinition>(Entity)) {
assert((PreprocessedEntities.empty() ||
!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
PreprocessedEntities.back()->getSourceRange().getBegin())) &&
- "a macro directive was encountered out-of-order");
+ "a macro definition was encountered out-of-order");
PreprocessedEntities.push_back(Entity);
return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
}
@@ -268,7 +267,15 @@ PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
// The entity's location is not after the previous one; this can happen with
// include directives that form the filename using macros, e.g:
- // "#include MACRO(STUFF)".
+ // "#include MACRO(STUFF)"
+ // or with macro expansions inside macro arguments where the arguments are
+ // not expanded in the same order as listed, e.g:
+ // \code
+ // #define M1 1
+ // #define M2 2
+ // #define FM(x,y) y x
+ // FM(M1, M2)
+ // \endcode
typedef std::vector<PreprocessedEntity *>::iterator pp_iter;
@@ -313,8 +320,8 @@ unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
}
void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
- PPEntityID PPID) {
- MacroDefinitions[Macro] = PPID;
+ MacroDefinition *Def) {
+ MacroDefinitions[Macro] = Def;
}
/// \brief Retrieve the preprocessed entity at the given ID.
@@ -351,19 +358,17 @@ PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {
}
MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
- llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos
+ llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos == MacroDefinitions.end())
return 0;
-
- PreprocessedEntity *Entity = getPreprocessedEntity(Pos->second);
- if (Entity->isInvalid())
- return 0;
- return cast<MacroDefinition>(Entity);
+
+ return Pos->second;
}
-void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
- SourceRange Range) {
+void PreprocessingRecord::addMacroExpansion(const Token &Id,
+ const MacroInfo *MI,
+ SourceRange Range) {
// We don't record nested macro expansions.
if (Id.getLocation().isMacroID())
return;
@@ -376,17 +381,50 @@ void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
new (*this) MacroExpansion(Def, Range));
}
+void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ // This is not actually a macro expansion but record it as a macro reference.
+ if (MD)
+ addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
+ MacroNameTok.getLocation());
+}
+
+void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ // This is not actually a macro expansion but record it as a macro reference.
+ if (MD)
+ addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
+ MacroNameTok.getLocation());
+}
+
+void PreprocessingRecord::Defined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ // This is not actually a macro expansion but record it as a macro reference.
+ if (MD)
+ addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
+ MacroNameTok.getLocation());
+}
+
+void PreprocessingRecord::MacroExpands(const Token &Id,const MacroDirective *MD,
+ SourceRange Range) {
+ addMacroExpansion(Id, MD->getMacroInfo(), Range);
+}
+
void PreprocessingRecord::MacroDefined(const Token &Id,
- const MacroInfo *MI) {
+ const MacroDirective *MD) {
+ const MacroInfo *MI = MD->getMacroInfo();
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
MacroDefinition *Def
= new (*this) MacroDefinition(Id.getIdentifierInfo(), R);
- MacroDefinitions[MI] = addPreprocessedEntity(Def);
+ addPreprocessedEntity(Def);
+ MacroDefinitions[MI] = Def;
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
- const MacroInfo *MI) {
- MacroDefinitions.erase(MI);
+ const MacroDirective *MD) {
+ // Note: MI may be null (when #undef'ining an undefined macro).
+ if (MD)
+ MacroDefinitions.erase(MD->getMacroInfo());
}
void PreprocessingRecord::InclusionDirective(
@@ -438,95 +476,6 @@ void PreprocessingRecord::InclusionDirective(
addPreprocessedEntity(ID);
}
-bool PreprocessingRecord::rangeIntersectsConditionalDirective(
- SourceRange Range) const {
- if (Range.isInvalid())
- return false;
-
- CondDirectiveLocsTy::const_iterator
- low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
- Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
- if (low == CondDirectiveLocs.end())
- return false;
-
- if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
- return false;
-
- CondDirectiveLocsTy::const_iterator
- upp = std::upper_bound(low, CondDirectiveLocs.end(),
- Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
- unsigned uppIdx;
- if (upp != CondDirectiveLocs.end())
- uppIdx = upp->getIdx();
- else
- uppIdx = 0;
-
- return low->getIdx() != uppIdx;
-}
-
-unsigned PreprocessingRecord::findCondDirectiveIdx(SourceLocation Loc) const {
- if (Loc.isInvalid())
- return 0;
-
- CondDirectiveLocsTy::const_iterator
- low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
- Loc, CondDirectiveLoc::Comp(SourceMgr));
- if (low == CondDirectiveLocs.end())
- return 0;
- return low->getIdx();
-}
-
-void PreprocessingRecord::addCondDirectiveLoc(CondDirectiveLoc DirLoc) {
- // Ignore directives in system headers.
- if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
- return;
-
- assert(CondDirectiveLocs.empty() ||
- SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
- DirLoc.getLoc()));
- CondDirectiveLocs.push_back(DirLoc);
-}
-
-void PreprocessingRecord::If(SourceLocation Loc, SourceRange ConditionRange) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
- }
-}
-
-void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
- }
-}
-
-void PreprocessingRecord::Ifndef(SourceLocation Loc,const Token &MacroNameTok) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
- }
-}
-
-void PreprocessingRecord::Elif(SourceLocation Loc, SourceRange ConditionRange,
- SourceLocation IfLoc) {
- if (RecordCondDirectives)
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
-}
-
-void PreprocessingRecord::Else(SourceLocation Loc, SourceLocation IfLoc) {
- if (RecordCondDirectives)
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
-}
-
-void PreprocessingRecord::Endif(SourceLocation Loc, SourceLocation IfLoc) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- assert(!CondDirectiveStack.empty());
- CondDirectiveStack.pop_back();
- }
-}
-
size_t PreprocessingRecord::getTotalMemory() const {
return BumpAlloc.getTotalMemory()
+ llvm::capacity_in_bytes(MacroDefinitions)
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 3b070ce049db..53c45dca01f9 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -26,50 +26,48 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
#include "MacroArgs.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/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/ScratchBuffer.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/CodeCompletionHandler.h"
-#include "clang/Lex/ModuleLoader.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Capacity.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Capacity.h"
using namespace clang;
//===----------------------------------------------------------------------===//
ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
-PPMutationListener::~PPMutationListener() { }
-
-Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
+Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target, SourceManager &SM,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
- IdentifierInfoLookup* IILookup,
- bool OwnsHeaders,
- bool DelayInitialization,
- bool IncrProcessing)
- : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target),
- FileMgr(Headers.getFileMgr()),
- SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
- ExternalSource(0), Identifiers(opts, IILookup),
- IncrementalProcessing(IncrProcessing), CodeComplete(0),
- CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0),
- SkipMainFilePreamble(0, true), CurPPLexer(0),
- CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0),
- MacroArgCache(0), Record(0), MIChainHead(0), MICache(0)
-{
+ IdentifierInfoLookup *IILookup, bool OwnsHeaders,
+ bool DelayInitialization, bool IncrProcessing)
+ : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target),
+ FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers),
+ TheModuleLoader(TheModuleLoader), ExternalSource(0),
+ Identifiers(opts, IILookup), IncrementalProcessing(IncrProcessing),
+ CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0),
+ CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
+ CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0),
+ MacroArgCache(0), Record(0), MIChainHead(0), MICache(0) {
OwnsHeaderSearch = OwnsHeaders;
ScratchBuf = new ScratchBuffer(SourceMgr);
@@ -96,9 +94,11 @@ Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
InMacroArgPreExpansion = false;
NumCachedTokenLexers = 0;
PragmasEnabled = true;
+ ParsingIfOrElifDirective = false;
+ PreprocessedOutput = false;
CachedLexPos = 0;
-
+
// We haven't read anything from the external source.
ReadMacrosFromExternalSource = false;
@@ -292,7 +292,7 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const {
/// \brief Compares macro tokens with a specified token value sequence.
static bool MacroDefinitionEquals(const MacroInfo *MI,
- llvm::ArrayRef<TokenValue> Tokens) {
+ ArrayRef<TokenValue> Tokens) {
return Tokens.size() == MI->getNumTokens() &&
std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin());
}
@@ -304,14 +304,15 @@ StringRef Preprocessor::getLastMacroWithSpelling(
StringRef BestSpelling;
for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end();
I != E; ++I) {
- if (!I->second->isObjectLike())
+ if (!I->second->getMacroInfo()->isObjectLike())
continue;
- const MacroInfo *MI = I->second->findDefinitionAtLoc(Loc, SourceMgr);
- if (!MI)
+ const MacroDirective::DefInfo
+ Def = I->second->findDirectiveAtLoc(Loc, SourceMgr);
+ if (!Def)
continue;
- if (!MacroDefinitionEquals(MI, Tokens))
+ if (!MacroDefinitionEquals(Def.getMacroInfo(), Tokens))
continue;
- SourceLocation Location = I->second->getDefinitionLoc();
+ SourceLocation Location = Def.getLocation();
// Choose the macro defined latest.
if (BestLocation.isInvalid() ||
(Location.isValid() &&
@@ -398,7 +399,7 @@ StringRef Preprocessor::getSpelling(const Token &Tok,
SmallVectorImpl<char> &Buffer,
bool *Invalid) const {
// NOTE: this has to be checked *before* testing for an IdentifierInfo.
- if (Tok.isNot(tok::raw_identifier)) {
+ if (Tok.isNot(tok::raw_identifier) && !Tok.hasUCN()) {
// Try the fast path.
if (const IdentifierInfo *II = Tok.getIdentifierInfo())
return II->getName();
@@ -481,6 +482,7 @@ void Preprocessor::EnterMainSourceFile() {
assert(SB && "Cannot create predefined source buffer");
FileID FID = SourceMgr.createFileIDForMemBuffer(SB);
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
+ setPredefinesFileID(FID);
// Start parsing the predefines.
EnterSourceFile(FID, 0, SourceLocation());
@@ -496,6 +498,48 @@ 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.
@@ -504,15 +548,22 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
// Look up this token, see if it is a macro, or if it is a language keyword.
IdentifierInfo *II;
- if (!Identifier.needsCleaning()) {
+ if (!Identifier.needsCleaning() && !Identifier.hasUCN()) {
// No cleaning needed, just use the characters from the lexed buffer.
II = getIdentifierInfo(StringRef(Identifier.getRawIdentifierData(),
- Identifier.getLength()));
+ Identifier.getLength()));
} else {
// Cleaning needed, alloca a buffer, clean into it, then use the buffer.
SmallString<64> IdentifierBuffer;
StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer);
- II = getIdentifierInfo(CleanedStr);
+
+ if (Identifier.hasUCN()) {
+ SmallString<64> UCNIdentifierBuffer;
+ expandUCNs(UCNIdentifierBuffer, CleanedStr);
+ II = getIdentifierInfo(UCNIdentifierBuffer);
+ } else {
+ II = getIdentifierInfo(CleanedStr);
+ }
}
// Update the token info (identifier info and appropriate token kind).
@@ -589,19 +640,19 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
}
// If this is a macro to be expanded, do it.
- if (MacroInfo *MI = getMacroInfo(&II)) {
+ if (MacroDirective *MD = getMacroDirective(&II)) {
+ MacroInfo *MI = MD->getMacroInfo();
if (!DisableMacroExpansion) {
- if (Identifier.isExpandDisabled()) {
- Diag(Identifier, diag::pp_disabled_macro_expansion);
- } else if (MI->isEnabled()) {
- if (!HandleMacroExpandedIdentifier(Identifier, MI))
+ if (!Identifier.isExpandDisabled() && MI->isEnabled()) {
+ if (!HandleMacroExpandedIdentifier(Identifier, MD))
return;
} else {
// C99 6.10.3.4p2 says that a disabled macro may never again be
// expanded, even if it's in a context where it could be expanded in the
// future.
Identifier.setFlag(Token::DisableExpand);
- Diag(Identifier, diag::pp_disabled_macro_expansion);
+ if (MI->isObjectLike() || isNextPPTokenLParen())
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
}
}
}
@@ -630,10 +681,10 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
- // If this is the '__experimental_modules_import' contextual keyword, note
+ // If this is the 'import' contextual keyword, note
// that the next token indicates a module name.
//
- // Note that we do not treat '__experimental_modules_import' as a contextual
+ // Note that we do not treat 'import' as a contextual
// keyword when we're in a caching lexer, because caching lexers only get
// used in contexts where import declarations are disallowed.
if (II.isModulesImport() && !InMacroArgs && !DisableMacroExpansion &&
@@ -689,6 +740,47 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
}
}
+bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String,
+ const char *DiagnosticTag,
+ bool AllowMacroExpansion) {
+ // We need at least one string literal.
+ if (Result.isNot(tok::string_literal)) {
+ Diag(Result, diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << DiagnosticTag;
+ return false;
+ }
+
+ // Lex string literal tokens, optionally with macro expansion.
+ SmallVector<Token, 4> StrToks;
+ do {
+ StrToks.push_back(Result);
+
+ if (Result.hasUDSuffix())
+ Diag(Result, diag::err_invalid_string_udl);
+
+ if (AllowMacroExpansion)
+ Lex(Result);
+ else
+ LexUnexpandedToken(Result);
+ } while (Result.is(tok::string_literal));
+
+ // Concatenate and parse the strings.
+ StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
+
+ if (Literal.hadError)
+ return false;
+
+ if (Literal.Pascal) {
+ Diag(StrToks[0].getLocation(), diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << DiagnosticTag;
+ return false;
+ }
+
+ String = Literal.GetString();
+ return true;
+}
+
void Preprocessor::addCommentHandler(CommentHandler *Handler) {
assert(Handler && "NULL comment handler");
assert(std::find(CommentHandlers.begin(), CommentHandlers.end(), Handler) ==
@@ -723,11 +815,10 @@ CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord(bool RecordConditionalDirectives) {
+void Preprocessor::createPreprocessingRecord() {
if (Record)
return;
- Record = new PreprocessingRecord(getSourceManager(),
- RecordConditionalDirectives);
+ Record = new PreprocessingRecord(getSourceManager());
addPPCallbacks(Record);
}
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index a64c84d6bbd3..5a59849720f6 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/PreprocessorLexer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
void PreprocessorLexer::anchor() { }
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index dd7ebb0ce337..0a66bba91fcd 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -12,25 +12,25 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
using namespace clang;
/// IsStringPrefix - Return true if Str is a string prefix.
/// 'L', 'u', 'U', or 'u8'. Including raw versions.
-static bool IsStringPrefix(StringRef Str, bool CPlusPlus0x) {
+static bool IsStringPrefix(StringRef Str, bool CPlusPlus11) {
if (Str[0] == 'L' ||
- (CPlusPlus0x && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) {
+ (CPlusPlus11 && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) {
if (Str.size() == 1)
return true; // "L", "u", "U", and "R"
// Check for raw flavors. Need to make sure the first character wasn't
- // already R. Need CPlusPlus0x check for "LR".
- if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus0x)
+ // already R. Need CPlusPlus11 check for "LR".
+ if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus11)
return true; // "LR", "uR", "UR"
// Check for "u8" and "u8R"
@@ -54,17 +54,17 @@ bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const {
SourceManager &SM = PP.getSourceManager();
const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation()));
return IsStringPrefix(StringRef(Ptr, Tok.getLength()),
- LangOpts.CPlusPlus0x);
+ LangOpts.CPlusPlus11);
}
if (Tok.getLength() < 256) {
char Buffer[256];
const char *TokPtr = Buffer;
unsigned length = PP.getSpelling(Tok, TokPtr);
- return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus0x);
+ return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus11);
}
- return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus0x);
+ return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus11);
}
TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
@@ -87,7 +87,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
// These tokens have custom code in C++11 mode.
- if (PP.getLangOpts().CPlusPlus0x) {
+ if (PP.getLangOpts().CPlusPlus11) {
TokenInfo[tok::string_literal ] |= aci_custom;
TokenInfo[tok::wide_string_literal ] |= aci_custom;
TokenInfo[tok::utf8_string_literal ] |= aci_custom;
@@ -156,9 +156,10 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
// First, check to see if the tokens were directly adjacent in the original
// source. If they were, it must be okay to stick them together: if there
// were an issue, the tokens would have been lexed differently.
- if (PrevTok.getLocation().isFileID() && Tok.getLocation().isFileID() &&
- PrevTok.getLocation().getLocWithOffset(PrevTok.getLength()) ==
- Tok.getLocation())
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation PrevSpellLoc = SM.getSpellingLoc(PrevTok.getLocation());
+ SourceLocation SpellLoc = SM.getSpellingLoc(Tok.getLocation());
+ if (PrevSpellLoc.getLocWithOffset(PrevTok.getLength()) == SpellLoc)
return false;
tok::TokenKind PrevKind = PrevTok.getKind();
@@ -206,7 +207,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
case tok::wide_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
- if (!PP.getLangOpts().CPlusPlus0x)
+ if (!PP.getLangOpts().CPlusPlus11)
return false;
// In C++11, a string or character literal followed by an identifier is a
@@ -239,13 +240,12 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
return IsIdentifierStringPrefix(PrevTok);
case tok::numeric_constant:
- return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
- FirstChar == '+' || FirstChar == '-' || FirstChar == '.' ||
- (PP.getLangOpts().CPlusPlus0x && FirstChar == '_');
+ return isPreprocessingNumberBody(FirstChar) ||
+ FirstChar == '+' || FirstChar == '-';
case tok::period: // ..., .*, .1234
return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
- isdigit(FirstChar) ||
- (PP.getLangOpts().CPlusPlus && FirstChar == '*');
+ isDigit(FirstChar) ||
+ (PP.getLangOpts().CPlusPlus && FirstChar == '*');
case tok::amp: // &&
return FirstChar == '&';
case tok::plus: // ++
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 59b747814a51..5b41fe9b8d3f 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -13,10 +13,10 @@
#include "clang/Lex/TokenLexer.h"
#include "MacroArgs.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -647,6 +647,12 @@ bool TokenLexer::PasteTokens(Token &Tok) {
StartLoc = getExpansionLocForMacroDefLoc(StartLoc);
if (EndLoc.isFileID())
EndLoc = getExpansionLocForMacroDefLoc(EndLoc);
+ FileID MacroFID = SM.getFileID(MacroExpansionStart);
+ while (SM.getFileID(StartLoc) != MacroFID)
+ StartLoc = SM.getImmediateExpansionRange(StartLoc).first;
+ while (SM.getFileID(EndLoc) != MacroFID)
+ EndLoc = SM.getImmediateExpansionRange(EndLoc).second;
+
Tok.setLocation(SM.createExpansionLoc(Tok.getLocation(), StartLoc, EndLoc,
Tok.getLength()));
@@ -743,14 +749,18 @@ static void updateConsecutiveMacroArgTokens(SourceManager &SM,
Token *NextTok = begin_tokens + 1;
for (; NextTok < end_tokens; ++NextTok) {
+ SourceLocation NextLoc = NextTok->getLocation();
+ if (CurLoc.isFileID() != NextLoc.isFileID())
+ break; // Token from different kind of FileID.
+
int RelOffs;
- if (!SM.isInSameSLocAddrSpace(CurLoc, NextTok->getLocation(), &RelOffs))
+ if (!SM.isInSameSLocAddrSpace(CurLoc, NextLoc, &RelOffs))
break; // Token from different local/loaded location.
// Check that token is not before the previous token or more than 50
// "characters" away.
if (RelOffs < 0 || RelOffs > 50)
break;
- CurLoc = NextTok->getLocation();
+ CurLoc = NextLoc;
}
// For the consecutive tokens, find the length of the SLocEntry to contain
diff --git a/lib/Lex/UnicodeCharSets.h b/lib/Lex/UnicodeCharSets.h
new file mode 100644
index 000000000000..37ff8af10f68
--- /dev/null
+++ b/lib/Lex/UnicodeCharSets.h
@@ -0,0 +1,496 @@
+//===--- UnicodeCharSets.h - Contains important sets of characters --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_LEX_UNICODECHARSETS_H
+#define CLANG_LEX_UNICODECHARSETS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+ struct UnicodeCharRange {
+ uint32_t Lower;
+ uint32_t Upper;
+ };
+ typedef llvm::ArrayRef<UnicodeCharRange> UnicodeCharSet;
+
+ typedef llvm::SmallPtrSet<const UnicodeCharRange *, 16> ValidatedCharSetsTy;
+}
+
+static inline ValidatedCharSetsTy &getValidatedCharSets() {
+ static ValidatedCharSetsTy Validated;
+ return Validated;
+}
+
+/// Returns true if each of the ranges in \p CharSet is a proper closed range
+/// [min, max], and if the ranges themselves are ordered and non-overlapping.
+static inline bool isValidCharSet(UnicodeCharSet CharSet) {
+#ifndef NDEBUG
+ static llvm::sys::Mutex ValidationMutex;
+
+ // Check the validation cache.
+ {
+ llvm::MutexGuard Guard(ValidationMutex);
+ if (getValidatedCharSets().count(CharSet.data()))
+ return true;
+ }
+
+ // Walk through the ranges.
+ uint32_t Prev = 0;
+ for (UnicodeCharSet::iterator I = CharSet.begin(), E = CharSet.end();
+ I != E; ++I) {
+ if (Prev >= I->Lower) {
+ DEBUG(llvm::dbgs() << "Upper bound 0x");
+ DEBUG(llvm::dbgs().write_hex(Prev));
+ DEBUG(llvm::dbgs() << " should be less than succeeding lower bound 0x");
+ DEBUG(llvm::dbgs().write_hex(I->Lower) << "\n");
+ return false;
+ }
+ if (I->Upper < I->Lower) {
+ DEBUG(llvm::dbgs() << "Upper bound 0x");
+ DEBUG(llvm::dbgs().write_hex(I->Lower));
+ DEBUG(llvm::dbgs() << " should not be less than lower bound 0x");
+ DEBUG(llvm::dbgs().write_hex(I->Upper) << "\n");
+ return false;
+ }
+ Prev = I->Upper;
+ }
+
+ // Update the validation cache.
+ {
+ llvm::MutexGuard Guard(ValidationMutex);
+ getValidatedCharSets().insert(CharSet.data());
+ }
+#endif
+ return true;
+}
+
+/// Returns true if the Unicode code point \p C is within the set of
+/// characters specified by \p CharSet.
+LLVM_READONLY static inline bool isCharInSet(uint32_t C,
+ UnicodeCharSet CharSet) {
+ assert(isValidCharSet(CharSet));
+
+ size_t LowPoint = 0;
+ size_t HighPoint = CharSet.size();
+
+ // Binary search the set of char ranges.
+ while (HighPoint != LowPoint) {
+ size_t MidPoint = (HighPoint + LowPoint) / 2;
+ if (C < CharSet[MidPoint].Lower)
+ HighPoint = MidPoint;
+ else if (C > CharSet[MidPoint].Upper)
+ LowPoint = MidPoint + 1;
+ else
+ return true;
+ }
+
+ return false;
+}
+
+
+// C11 D.1, C++11 [charname.allowed]
+static const UnicodeCharRange C11AllowedIDChars[] = {
+ // 1
+ { 0x00A8, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AD, 0x00AD },
+ { 0x00AF, 0x00AF }, { 0x00B2, 0x00B5 }, { 0x00B7, 0x00BA },
+ { 0x00BC, 0x00BE }, { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 },
+ { 0x00F8, 0x00FF },
+ // 2
+ { 0x0100, 0x167F }, { 0x1681, 0x180D }, { 0x180F, 0x1FFF },
+ // 3
+ { 0x200B, 0x200D }, { 0x202A, 0x202E }, { 0x203F, 0x2040 },
+ { 0x2054, 0x2054 }, { 0x2060, 0x206F },
+ // 4
+ { 0x2070, 0x218F }, { 0x2460, 0x24FF }, { 0x2776, 0x2793 },
+ { 0x2C00, 0x2DFF }, { 0x2E80, 0x2FFF },
+ // 5
+ { 0x3004, 0x3007 }, { 0x3021, 0x302F }, { 0x3031, 0x303F },
+ // 6
+ { 0x3040, 0xD7FF },
+ // 7
+ { 0xF900, 0xFD3D }, { 0xFD40, 0xFDCF }, { 0xFDF0, 0xFE44 },
+ { 0xFE47, 0xFFFD },
+ // 8
+ { 0x10000, 0x1FFFD }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD },
+ { 0x40000, 0x4FFFD }, { 0x50000, 0x5FFFD }, { 0x60000, 0x6FFFD },
+ { 0x70000, 0x7FFFD }, { 0x80000, 0x8FFFD }, { 0x90000, 0x9FFFD },
+ { 0xA0000, 0xAFFFD }, { 0xB0000, 0xBFFFD }, { 0xC0000, 0xCFFFD },
+ { 0xD0000, 0xDFFFD }, { 0xE0000, 0xEFFFD }
+};
+
+// C++03 [extendid]
+// Note that this is not the same as C++98, but we don't distinguish C++98
+// and C++03 in Clang.
+static const UnicodeCharRange CXX03AllowedIDChars[] = {
+ // Latin
+ { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 },
+ { 0x01FA, 0x0217 }, { 0x0250, 0x02A8 },
+
+ // Greek
+ { 0x0384, 0x0384 }, { 0x0388, 0x038A }, { 0x038C, 0x038C },
+ { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, { 0x03D0, 0x03D6 },
+ { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
+ { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 },
+
+ // Cyrillic
+ { 0x0401, 0x040D }, { 0x040F, 0x044F }, { 0x0451, 0x045C },
+ { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 },
+ { 0x04F8, 0x04F9 },
+
+ // Armenian
+ { 0x0531, 0x0556 }, { 0x0561, 0x0587 },
+
+ // Hebrew
+ { 0x05D0, 0x05EA }, { 0x05F0, 0x05F4 },
+
+ // Arabic
+ { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0670, 0x06B7 },
+ { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06E5, 0x06E7 },
+
+ // Devanagari
+ { 0x0905, 0x0939 }, { 0x0958, 0x0962 },
+
+ // Bengali
+ { 0x0985, 0x098C }, { 0x098F, 0x0990 }, { 0x0993, 0x09A8 },
+ { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 },
+ { 0x09DC, 0x09DD }, { 0x09DF, 0x09E1 }, { 0x09F0, 0x09F1 },
+
+ // Gurmukhi
+ { 0x0A05, 0x0A0A }, { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 },
+ { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 }, { 0x0A35, 0x0A36 },
+ { 0x0A38, 0x0A39 }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E },
+
+ // Gujarti
+ { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D }, { 0x0A8F, 0x0A91 },
+ { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 },
+ { 0x0AB5, 0x0AB9 }, { 0x0AE0, 0x0AE0 },
+
+ // Oriya
+ { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 },
+ { 0x0B2A, 0x0B30 }, { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 },
+ { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 },
+
+ // Tamil
+ { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 },
+ { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F },
+ { 0x0BA3, 0x0BA4 }, { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 },
+ { 0x0BB7, 0x0BB9 },
+
+ // Telugu
+ { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 },
+ { 0x0C2A, 0x0C33 }, { 0x0C35, 0x0C39 }, { 0x0C60, 0x0C61 },
+
+ // Kannada
+ { 0x0C85, 0x0C8C }, { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 },
+ { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 }, { 0x0CE0, 0x0CE1 },
+
+ // Malayam
+ { 0x0D05, 0x0D0C }, { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 },
+ { 0x0D2A, 0x0D39 }, { 0x0D60, 0x0D61 },
+
+ // Thai
+ { 0x0E01, 0x0E30 }, { 0x0E32, 0x0E33 }, { 0x0E40, 0x0E46 },
+ { 0x0E4F, 0x0E5B },
+
+ // Lao
+ { 0x0E81, 0x0E82 }, { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E87 },
+ { 0x0E88, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D },
+ { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 },
+ { 0x0EA5, 0x0EA5 }, { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAA },
+ { 0x0EAB, 0x0EAB }, { 0x0EAD, 0x0EB0 }, { 0x0EB2, 0x0EB2 },
+ { 0x0EB3, 0x0EB3 }, { 0x0EBD, 0x0EBD }, { 0x0EC0, 0x0EC4 },
+ { 0x0EC6, 0x0EC6 },
+
+ // Georgian
+ { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 },
+
+ // Hangul
+ { 0x1100, 0x1159 }, { 0x1161, 0x11A2 }, { 0x11A8, 0x11F9 },
+
+ // Latin (2)
+ { 0x1E00, 0x1E9A }, { 0x1EA0, 0x1EF9 },
+
+ // Greek (2)
+ { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
+ { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 },
+ { 0x1F5B, 0x1F5B }, { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D },
+ { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC }, { 0x1FC2, 0x1FC4 },
+ { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 }, { 0x1FD6, 0x1FDB },
+ { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC },
+
+ // Hiragana
+ { 0x3041, 0x3094 }, { 0x309B, 0x309E },
+
+ // Katakana
+ { 0x30A1, 0x30FE },
+
+ // Bopmofo [sic]
+ { 0x3105, 0x312C },
+
+ // CJK Unified Ideographs
+ { 0x4E00, 0x9FA5 }, { 0xF900, 0xFA2D }, { 0xFB1F, 0xFB36 },
+ { 0xFB38, 0xFB3C }, { 0xFB3E, 0xFB3E }, { 0xFB40, 0xFB41 },
+ { 0xFB42, 0xFB44 }, { 0xFB46, 0xFBB1 }, { 0xFBD3, 0xFD3F },
+ { 0xFD50, 0xFD8F }, { 0xFD92, 0xFDC7 }, { 0xFDF0, 0xFDFB },
+ { 0xFE70, 0xFE72 }, { 0xFE74, 0xFE74 }, { 0xFE76, 0xFEFC },
+ { 0xFF21, 0xFF3A }, { 0xFF41, 0xFF5A }, { 0xFF66, 0xFFBE },
+ { 0xFFC2, 0xFFC7 }, { 0xFFCA, 0xFFCF }, { 0xFFD2, 0xFFD7 },
+ { 0xFFDA, 0xFFDC }
+};
+
+// C99 Annex D
+static const UnicodeCharRange C99AllowedIDChars[] = {
+ // Latin (1)
+ { 0x00AA, 0x00AA },
+
+ // Special characters (1)
+ { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 },
+
+ // Latin (2)
+ { 0x00BA, 0x00BA }, { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 },
+ { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 }, { 0x0250, 0x02A8 },
+
+ // Special characters (2)
+ { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 },
+ { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A },
+
+ // Greek (1)
+ { 0x0386, 0x0386 }, { 0x0388, 0x038A }, { 0x038C, 0x038C },
+ { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, { 0x03D0, 0x03D6 },
+ { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
+ { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 },
+
+ // Cyrillic
+ { 0x0401, 0x040C }, { 0x040E, 0x044F }, { 0x0451, 0x045C },
+ { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 },
+ { 0x04F8, 0x04F9 },
+
+ // Armenian (1)
+ { 0x0531, 0x0556 },
+
+ // Special characters (3)
+ { 0x0559, 0x0559 },
+
+ // Armenian (2)
+ { 0x0561, 0x0587 },
+
+ // Hebrew
+ { 0x05B0, 0x05B9 }, { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF },
+ { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA }, { 0x05F0, 0x05F2 },
+
+ // Arabic (1)
+ { 0x0621, 0x063A }, { 0x0640, 0x0652 },
+
+ // Digits (1)
+ { 0x0660, 0x0669 },
+
+ // Arabic (2)
+ { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE },
+ { 0x06D0, 0x06DC }, { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED },
+
+ // Digits (2)
+ { 0x06F0, 0x06F9 },
+
+ // Devanagari and Special characeter 0x093D.
+ { 0x0901, 0x0903 }, { 0x0905, 0x0939 }, { 0x093D, 0x094D },
+ { 0x0950, 0x0952 }, { 0x0958, 0x0963 },
+
+ // Digits (3)
+ { 0x0966, 0x096F },
+
+ // Bengali (1)
+ { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 },
+ { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 },
+ { 0x09B6, 0x09B9 }, { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 },
+ { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD }, { 0x09DF, 0x09E3 },
+
+ // Digits (4)
+ { 0x09E6, 0x09EF },
+
+ // Bengali (2)
+ { 0x09F0, 0x09F1 },
+
+ // Gurmukhi (1)
+ { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A }, { 0x0A0F, 0x0A10 },
+ { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 },
+ { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 },
+ { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C },
+ { 0x0A5E, 0x0A5E },
+
+ // Digits (5)
+ { 0x0A66, 0x0A6F },
+
+ // Gurmukhi (2)
+ { 0x0A74, 0x0A74 },
+
+ // Gujarti
+ { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D },
+ { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 },
+ { 0x0AB2, 0x0AB3 }, { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 },
+ { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD }, { 0x0AD0, 0x0AD0 },
+ { 0x0AE0, 0x0AE0 },
+
+ // Digits (6)
+ { 0x0AE6, 0x0AEF },
+
+ // Oriya and Special character 0x0B3D
+ { 0x0B01, 0x0B03 }, { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 },
+ { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 }, { 0x0B32, 0x0B33 },
+ { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 },
+ { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 },
+
+ // Digits (7)
+ { 0x0B66, 0x0B6F },
+
+ // Tamil
+ { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 },
+ { 0x0B92, 0x0B95 }, { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C },
+ { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 }, { 0x0BA8, 0x0BAA },
+ { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 },
+ { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD },
+
+ // Digits (8)
+ { 0x0BE7, 0x0BEF },
+
+ // Telugu
+ { 0x0C01, 0x0C03 }, { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 },
+ { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 }, { 0x0C35, 0x0C39 },
+ { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D },
+ { 0x0C60, 0x0C61 },
+
+ // Digits (9)
+ { 0x0C66, 0x0C6F },
+
+ // Kannada
+ { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C }, { 0x0C8E, 0x0C90 },
+ { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 },
+ { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD },
+ { 0x0CDE, 0x0CDE }, { 0x0CE0, 0x0CE1 },
+
+ // Digits (10)
+ { 0x0CE6, 0x0CEF },
+
+ // Malayam
+ { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C }, { 0x0D0E, 0x0D10 },
+ { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 },
+ { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D60 },
+
+ // Digits (11)
+ { 0x0D66, 0x0D6F },
+
+ // Thai...including Digits { 0x0E50, 0x0E59 }
+ { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B },
+
+ // Lao (1)
+ { 0x0E81, 0x0E82 }, { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 },
+ { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D }, { 0x0E94, 0x0E97 },
+ { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 },
+ { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE },
+ { 0x0EB0, 0x0EB9 }, { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 },
+ { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD },
+
+ // Digits (12)
+ { 0x0ED0, 0x0ED9 },
+
+ // Lao (2)
+ { 0x0EDC, 0x0EDD },
+
+ // Tibetan (1)
+ { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 },
+
+ // Digits (13)
+ { 0x0F20, 0x0F33 },
+
+ // Tibetan (2)
+ { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
+ { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 },
+ { 0x0F86, 0x0F8B }, { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 },
+ { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 }, { 0x0FB9, 0x0FB9 },
+
+ // Georgian
+ { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 },
+
+ // Latin (3)
+ { 0x1E00, 0x1E9B }, { 0x1EA0, 0x1EF9 },
+
+ // Greek (2)
+ { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
+ { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 },
+ { 0x1F5B, 0x1F5B }, { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D },
+ { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC },
+
+ // Special characters (4)
+ { 0x1FBE, 0x1FBE },
+
+ // Greek (3)
+ { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 },
+ { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 },
+ { 0x1FF6, 0x1FFC },
+
+ // Special characters (5)
+ { 0x203F, 0x2040 },
+
+ // Latin (4)
+ { 0x207F, 0x207F },
+
+ // Special characters (6)
+ { 0x2102, 0x2102 }, { 0x2107, 0x2107 }, { 0x210A, 0x2113 },
+ { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 },
+ { 0x2133, 0x2138 }, { 0x2160, 0x2182 }, { 0x3005, 0x3007 },
+ { 0x3021, 0x3029 },
+
+ // Hiragana
+ { 0x3041, 0x3093 }, { 0x309B, 0x309C },
+
+ // Katakana
+ { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC },
+
+ // Bopmofo [sic]
+ { 0x3105, 0x312C },
+
+ // CJK Unified Ideographs
+ { 0x4E00, 0x9FA5 },
+
+ // Hangul,
+ { 0xAC00, 0xD7A3 }
+};
+
+// C11 D.2, C++11 [charname.disallowed]
+static const UnicodeCharRange C11DisallowedInitialIDChars[] = {
+ { 0x0300, 0x036F }, { 0x1DC0, 0x1DFF }, { 0x20D0, 0x20FF },
+ { 0xFE20, 0xFE2F }
+};
+
+// C99 6.4.2.1p3: The initial character [of an identifier] shall not be a
+// universal character name designating a digit.
+// C99 Annex D defines these characters as "Digits".
+static const UnicodeCharRange C99DisallowedInitialIDChars[] = {
+ { 0x0660, 0x0669 }, { 0x06F0, 0x06F9 }, { 0x0966, 0x096F },
+ { 0x09E6, 0x09EF }, { 0x0A66, 0x0A6F }, { 0x0AE6, 0x0AEF },
+ { 0x0B66, 0x0B6F }, { 0x0BE7, 0x0BEF }, { 0x0C66, 0x0C6F },
+ { 0x0CE6, 0x0CEF }, { 0x0D66, 0x0D6F }, { 0x0E50, 0x0E59 },
+ { 0x0ED0, 0x0ED9 }, { 0x0F20, 0x0F33 }
+};
+
+// Unicode v6.2, chapter 6.2, table 6-2.
+static const UnicodeCharRange UnicodeWhitespaceChars[] = {
+ { 0x0085, 0x0085 }, { 0x00A0, 0x00A0 }, { 0x1680, 0x1680 },
+ { 0x180E, 0x180E }, { 0x2000, 0x200A }, { 0x2028, 0x2029 },
+ { 0x202F, 0x202F }, { 0x205F, 0x205F }, { 0x3000, 0x3000 }
+};
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index 1f14aa078e4d..2e32dfec35a4 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,9 +8,19 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-PARALLEL_DIRS = Headers Basic Lex Parse AST ASTMatchers Sema CodeGen Analysis \
- StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \
- FrontendTool Tooling Driver
+# 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 ARCMigrate Rewrite \
+ Serialization
-include $(CLANG_LEVEL)/Makefile
+include $(CLANG_LEVEL)/../../Makefile.config
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+PARALLEL_DIRS += ASTMatchers
+endif
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+PARALLEL_DIRS += StaticAnalyzer
+endif
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 55e2aebca870..939998ecb1af 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangParse
ParseExprCXX.cpp
ParseInit.cpp
ParseObjc.cpp
+ ParseOpenMP.cpp
ParsePragma.cpp
ParseStmt.cpp
ParseTemplate.cpp
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 7d68e1f37e40..7cd8a21ac451 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -12,23 +12,68 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/ParseAST.h"
-#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/SemaConsumer.h"
-#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#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>
using namespace clang;
+namespace {
+
+/// If a crash happens while the parser is active, an entry is printed for it.
+class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
+ const Parser &P;
+public:
+ PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
+ virtual void print(raw_ostream &OS) const;
+};
+
+/// If a crash happens while the parser is active, print out a line indicating
+/// what the current token is.
+void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
+ const Token &Tok = P.getCurToken();
+ if (Tok.is(tok::eof)) {
+ OS << "<eof> parser at end of file\n";
+ return;
+ }
+
+ if (Tok.getLocation().isInvalid()) {
+ OS << "<unknown> parser at unknown location\n";
+ return;
+ }
+
+ const Preprocessor &PP = P.getPreprocessor();
+ Tok.getLocation().print(OS, PP.getSourceManager());
+ if (Tok.isAnnotation()) {
+ OS << ": at annotation token\n";
+ } else {
+ // Do the equivalent of PP.getSpelling(Tok) except for the parts that would
+ // allocate memory.
+ bool Invalid = false;
+ const SourceManager &SM = P.getPreprocessor().getSourceManager();
+ unsigned Length = Tok.getLength();
+ const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);
+ if (Invalid) {
+ OS << ": unknown current parser token\n";
+ return;
+ }
+ OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";
+ }
+}
+
+} // namespace
+
//===----------------------------------------------------------------------===//
// Public interface to the file
//===----------------------------------------------------------------------===//
@@ -43,9 +88,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
CodeCompleteConsumer *CompletionConsumer,
bool SkipFunctionBodies) {
- OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
- TUKind,
- CompletionConsumer));
+ OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
@@ -97,7 +140,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
- return;
+ return;
} while (!P.ParseTopLevelDecl(ADecl));
}
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 9c5c0597eee1..bc634b57d9ce 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -11,18 +11,25 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
-#include "clang/AST/DeclTemplate.h"
-#include "RAIIObjectsForParser.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.
-Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
+NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
AttributeList *AccessAttrs,
ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
@@ -38,7 +45,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
- Decl *FnD;
+ NamedDecl *FnD;
D.setFunctionDefinitionKind(DefinitionKind);
if (D.getDeclSpec().isFriendSpecified())
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
@@ -75,7 +82,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_deleted_function :
diag::ext_deleted_function);
@@ -83,7 +90,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_defaulted_function :
diag::ext_defaulted_function);
@@ -117,11 +124,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
if (FnD) {
LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD);
- FunctionDecl *FD = 0;
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD))
- FD = FunTmpl->getTemplatedDecl();
- else
- FD = cast<FunctionDecl>(FnD);
+ FunctionDecl *FD = getFunctionDecl(FnD);
Actions.CheckForFunctionRedefinition(FD);
LateParsedTemplateMap[FD] = LPT;
@@ -176,6 +179,19 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
getCurrentClass().LateParsedDeclarations.pop_back();
}
+ // If this is a friend function, mark that it's late-parsed so that
+ // it's still known to be a definition even before we attach the
+ // parsed body. Sema needs to treat friend function definitions
+ // differently during template instantiation, and it's possible for
+ // the containing class to be instantiated before all its member
+ // function definitions are parsed.
+ //
+ // If you remove this, you can remove the code that clears the flag
+ // after parsing the member.
+ if (D.getDeclSpec().isFriendSpecified()) {
+ getFunctionDecl(FnD)->setLateTemplateParsed(true);
+ }
+
return FnD;
}
@@ -293,8 +309,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// Introduce the parameters into scope and parse their default
// arguments.
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope | Scope::DeclScope);
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
// Introduce the parameter into scope.
Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
@@ -322,7 +338,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
LM.DefaultArgs[I].Param);
ExprResult DefArgResult;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
DefArgResult = ParseBraceInitializer();
} else
@@ -391,7 +407,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
&& "Inline method not starting with '{', ':' or 'try'");
@@ -427,6 +443,9 @@ 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 (Tok.getLocation() != origLoc) {
// Due to parsing error, we either went over the cached tokens or
// there are still cached tokens left. If it's the latter case skip the
@@ -491,7 +510,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
SourceLocation EqualLoc;
@@ -651,7 +670,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
ConsumeBrace();
// In C++03, this has to be the start of the function body, which
// means the initializer is malformed; we'll diagnose it later.
- if (!getLangOpts().CPlusPlus0x)
+ if (!getLangOpts().CPlusPlus11)
return false;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index f73907a7c409..990a9097acf2 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -12,13 +12,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/OpenCL.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
-#include "RAIIObjectsForParser.h"
+#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -36,13 +38,16 @@ using namespace clang;
TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context,
AccessSpecifier AS,
- Decl **OwnedType) {
+ Decl **OwnedType,
+ ParsedAttributes *Attrs) {
DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context);
if (DSC == DSC_normal)
DSC = DSC_type_specifier;
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
+ if (Attrs)
+ DS.addAttributes(Attrs->getList());
ParseSpecifierQualifierList(DS, AS, DSC);
if (OwnedType)
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
@@ -209,6 +214,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation ParmLoc;
bool BuiltinType = false;
+ TypeResult T;
+ SourceRange TypeRange;
+ bool TypeParsed = false;
+
switch (Tok.getKind()) {
case tok::kw_char:
case tok::kw_wchar_t:
@@ -227,12 +236,17 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
case tok::kw_void:
case tok::kw_typeof:
// __attribute__(( vec_type_hint(char) ))
- // FIXME: Don't just discard the builtin type token.
- ConsumeToken();
BuiltinType = true;
+ T = ParseTypeName(&TypeRange);
+ TypeParsed = true;
break;
case tok::identifier:
+ if (AttrName->isStr("vec_type_hint")) {
+ T = ParseTypeName(&TypeRange);
+ TypeParsed = true;
+ break;
+ }
ParmName = Tok.getIdentifierInfo();
ParmLoc = ConsumeToken();
break;
@@ -242,8 +256,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
}
ExprVector ArgExprs;
+ bool isInvalid = false;
+ bool isParmType = false;
- if (!BuiltinType &&
+ if (!BuiltinType && !AttrName->isStr("vec_type_hint") &&
(ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
// Eat the comma.
if (ParmLoc.isValid())
@@ -278,17 +294,32 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
Diag(Tok, diag::err_iboutletcollection_with_protocol);
SkipUntil(tok::r_paren, false, true); // skip until ')'
}
+ } else if (AttrName->isStr("vec_type_hint")) {
+ if (T.get() && !T.isInvalid())
+ isParmType = true;
+ else {
+ if (Tok.is(tok::identifier))
+ ConsumeToken();
+ if (TypeParsed)
+ isInvalid = true;
+ }
}
SourceLocation RParen = Tok.getLocation();
- if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) &&
+ !isInvalid) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- AttributeList *attr =
- Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen),
- ScopeName, ScopeLoc, ParmName, ParmLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
- if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
+ if (isParmType) {
+ Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName,
+ ScopeLoc, ParmName, ParmLoc, T.get(), Syntax);
+ } else {
+ AttributeList *attr = Attrs.addNew(
+ AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName,
+ ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax);
+ if (BuiltinType &&
+ attr->getKind() == AttributeList::AT_IBOutletCollection)
+ Diag(Tok, diag::err_iboutletcollection_builtintype);
+ }
}
}
@@ -457,12 +488,11 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
- Tok.is(tok::kw___ptr32) ||
- Tok.is(tok::kw___unaligned)) {
+ Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_MSTypespec);
+ SourceLocation(), 0, 0, AttributeList::AS_Keyword);
}
}
@@ -472,21 +502,23 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_MSTypespec);
+ SourceLocation(), 0, 0, AttributeList::AS_Keyword);
}
}
void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
// Treat these like attributes
while (Tok.is(tok::kw___kernel)) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"),
- AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_GNU);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
+ SourceLocation(), 0, 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:
@@ -568,7 +600,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// Parse the major version.
unsigned AfterMajor = 0;
unsigned Major = 0;
- while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) {
+ while (AfterMajor < ActualLength && isDigit(ThisTokBegin[AfterMajor])) {
Major = Major * 10 + ThisTokBegin[AfterMajor] - '0';
++AfterMajor;
}
@@ -600,7 +632,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// Parse the minor version.
unsigned AfterMinor = AfterMajor + 1;
unsigned Minor = 0;
- while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) {
+ while (AfterMinor < ActualLength && isDigit(ThisTokBegin[AfterMinor])) {
Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0';
++AfterMinor;
}
@@ -627,7 +659,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// Parse the subminor version.
unsigned AfterSubminor = AfterMinor + 1;
unsigned Subminor = 0;
- while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) {
+ while (AfterSubminor < ActualLength && isDigit(ThisTokBegin[AfterSubminor])) {
Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0';
++AfterSubminor;
}
@@ -735,7 +767,8 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
ConsumeToken();
if (Keyword == Ident_message) {
if (!isTokenStringLiteral()) {
- Diag(Tok, diag::err_expected_string_literal);
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='availability attribute'*/2;
SkipUntil(tok::r_paren);
return;
}
@@ -898,9 +931,11 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
LA.Toks.push_back(Tok);
PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ 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();
}
@@ -969,7 +1004,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
/// \brief Wrapper around a case statement checking if AttrName is
/// one of the thread safety attributes
-bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
+bool Parser::IsThreadSafetyAttribute(StringRef AttrName) {
return llvm::StringSwitch<bool>(AttrName)
.Case("guarded_by", true)
.Case("guarded_var", true)
@@ -1018,6 +1053,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
// 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;
@@ -1137,6 +1173,25 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
llvm_unreachable("All cases handled above.");
}
+/// \brief We have found the opening square brackets of a C++11
+/// attribute-specifier in a location where an attribute is not permitted, but
+/// we know where the attributes ought to be written. Parse them anyway, and
+/// provide a fixit moving them to the right place.
+void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
+ SourceLocation CorrectLocation) {
+ assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
+ Tok.is(tok::kw_alignas));
+
+ // Consume the attributes.
+ SourceLocation Loc = Tok.getLocation();
+ ParseCXX11Attributes(Attrs);
+ CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true);
+
+ Diag(Loc, diag::err_attributes_not_allowed)
+ << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
+ << FixItHint::CreateRemoval(AttrRange);
+}
+
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
<< attrs.Range;
@@ -1145,8 +1200,8 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) {
AttributeList *AttrList = attrs.getList();
while (AttrList) {
- if (AttrList->isCXX0XAttribute()) {
- Diag(AttrList->getLoc(), diag::warn_attribute_no_decl)
+ if (AttrList->isCXX11Attribute()) {
+ Diag(AttrList->getLoc(), diag::err_attribute_not_type_attr)
<< AttrList->getName();
AttrList->setInvalid();
}
@@ -1239,11 +1294,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
Parser::DeclGroupPtrTy
Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs,
+ ParsedAttributesWithRange &Attrs,
bool RequireSemi, ForRangeInit *FRI) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
- DS.takeAttributesFrom(attrs);
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
getDeclSpecContextFromDeclaratorContext(Context));
@@ -1251,6 +1305,7 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
+ ProhibitAttributes(Attrs);
DeclEnd = Tok.getLocation();
if (RequireSemi) ConsumeToken();
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
@@ -1259,6 +1314,7 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
+ DS.takeAttributesFrom(Attrs);
return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
}
@@ -1283,7 +1339,7 @@ bool Parser::MightBeDeclarator(unsigned Context) {
return getLangOpts().CPlusPlus;
case tok::l_square: // Might be an attribute on an unnamed bit-field.
- return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x &&
+ return Context == Declarator::MemberContext && getLangOpts().CPlusPlus11 &&
NextToken().is(tok::l_square);
case tok::colon: // Might be a typo for '::' or an unnamed bit-field.
@@ -1317,7 +1373,7 @@ bool Parser::MightBeDeclarator(unsigned Context) {
(getLangOpts().CPlusPlus && Context == Declarator::FileContext);
case tok::identifier: // Possible virt-specifier.
- return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken());
+ return getLangOpts().CPlusPlus11 && isCXX11VirtSpecifier(NextToken());
default:
return false;
@@ -1720,7 +1776,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
/*DirectInit=*/true, TypeContainsAuto);
}
- } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace) &&
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) &&
(!CurParsedObjCImpl || !D.isFunctionDeclarator())) {
// Parse C++0x braced-init-list.
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
@@ -1841,7 +1897,8 @@ 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");
SourceLocation Loc = Tok.getLocation();
@@ -1927,7 +1984,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal);
else
ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS,
- /*EnteringContext*/ false, DSC_normal);
+ /*EnteringContext*/ false, DSC_normal, Attrs);
return true;
}
}
@@ -2056,7 +2113,7 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start,
} else
ER = ParseConstantExpression();
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis))
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::ellipsis))
EllipsisLoc = ConsumeToken();
return ER;
@@ -2068,15 +2125,15 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start,
/// alignment-specifier:
/// [C11] '_Alignas' '(' type-id ')'
/// [C11] '_Alignas' '(' constant-expression ')'
-/// [C++0x] 'alignas' '(' type-id ...[opt] ')'
-/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')'
+/// [C++11] 'alignas' '(' type-id ...[opt] ')'
+/// [C++11] 'alignas' '(' assignment-expression ...[opt] ')'
void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
- SourceLocation *endLoc) {
+ SourceLocation *EndLoc) {
assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
"Not an alignment-specifier!");
- SourceLocation KWLoc = Tok.getLocation();
- ConsumeToken();
+ IdentifierInfo *KWName = Tok.getIdentifierInfo();
+ SourceLocation KWLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen))
@@ -2090,23 +2147,13 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
}
T.consumeClose();
- if (endLoc)
- *endLoc = T.getCloseLocation();
-
- // FIXME: Handle pack-expansions here.
- if (EllipsisLoc.isValid()) {
- Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported);
- return;
- }
+ if (EndLoc)
+ *EndLoc = T.getCloseLocation();
ExprVector ArgExprs;
ArgExprs.push_back(ArgExpr.release());
- // FIXME: This should not be GNU, but we since the attribute used is
- // based on the spelling, and there is no true spelling for
- // C++11 attributes, this isn't accepted.
- Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
- 0, T.getOpenLocation(), ArgExprs.data(), 1,
- AttributeList::AS_GNU);
+ Attrs.addNew(KWName, KWLoc, 0, KWLoc, 0, T.getOpenLocation(),
+ ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc);
}
/// ParseDeclarationSpecifiers
@@ -2176,7 +2223,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::l_square:
case tok::kw_alignas:
- if (!isCXX11AttributeSpecifier())
+ if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier())
goto DoneWithDeclSpec;
ProhibitAttributes(attrs);
@@ -2270,8 +2317,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// name, then the code is ill-formed; this interpretation is
// reinforced by the NAD status of core issue 635.
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
- if ((DSContext == DSC_top_level ||
- (DSContext == DSC_class && DS.isFriendSpecified())) &&
+ if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
if (isConstructorDeclarator()) {
@@ -2321,8 +2367,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If we're in a context where the identifier could be a class name,
// check whether this is a constructor declaration.
- if ((DSContext == DSC_top_level ||
- (DSContext == DSC_class && DS.isFriendSpecified())) &&
+ if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
&SS)) {
if (isConstructorDeclarator())
@@ -2351,7 +2396,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typename.
if (TypeRep == 0) {
ConsumeToken(); // Eat the scope spec so the identifier is current.
- if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue;
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) {
+ if (!Attrs.empty()) {
+ AttrsLastTime = true;
+ attrs.takeAllFrom(Attrs);
+ }
+ continue;
+ }
goto DoneWithDeclSpec;
}
@@ -2447,7 +2499,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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) {
- if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue;
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext, Attrs)) {
+ if (!Attrs.empty()) {
+ AttrsLastTime = true;
+ attrs.takeAllFrom(Attrs);
+ }
+ continue;
+ }
goto DoneWithDeclSpec;
}
@@ -2512,7 +2571,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// Microsoft single token adornments.
case tok::kw___forceinline: {
- isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecInline(Loc);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = Tok.getLocation();
// FIXME: This does not work correctly if it is set to be a declspec
@@ -2565,7 +2624,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec, DiagID);
break;
case tok::kw_auto:
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID);
@@ -2593,13 +2652,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// function-specifier
case tok::kw_inline:
- isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecInline(Loc);
break;
case tok::kw_virtual:
- isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecVirtual(Loc);
break;
case tok::kw_explicit:
- isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecExplicit(Loc);
+ break;
+ case tok::kw__Noreturn:
+ if (!getLangOpts().C11)
+ Diag(Loc, diag::ext_c11_noreturn);
+ isInvalid = DS.setFunctionSpecNoreturn(Loc);
break;
// alignment-specifier
@@ -2736,6 +2800,38 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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);
+ break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
PrevSpec, DiagID);
@@ -2748,8 +2844,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
+
+ // These are attributes following class specifiers.
+ // To produce better diagnostic, we parse them when
+ // parsing class specifier.
+ ParsedAttributesWithRange Attributes(AttrFactory);
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
- EnteringContext, DSContext);
+ EnteringContext, DSContext, Attributes);
+
+ // If there are attributes following class specifier,
+ // take them over and handle them here.
+ if (!Attributes.empty()) {
+ AttrsLastTime = true;
+ attrs.takeAllFrom(Attributes);
+ }
continue;
}
@@ -2797,8 +2905,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
case tok::kw__Atomic:
- ParseAtomicSpecifier(DS);
- continue;
+ // C11 6.7.2.4/4:
+ // If the _Atomic keyword is immediately followed by a left parenthesis,
+ // it is interpreted as a type specifier (with a type name), not as a
+ // type qualifier.
+ if (NextToken().is(tok::l_paren)) {
+ ParseAtomicSpecifier(DS);
+ continue;
+ }
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
+ getLangOpts());
+ break;
// OpenCL qualifiers:
case tok::kw_private:
@@ -2949,6 +3066,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
unsigned TagType, Decl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc,
"parsing struct/union body");
+ assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen())
@@ -2957,9 +3075,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
- // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
- // C++.
- if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) {
+ // Empty structs are an extension in C (C99 6.7.2.1p7).
+ if (Tok.is(tok::r_brace)) {
Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
}
@@ -2976,6 +3093,13 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
+ // Parse _Static_assert declaration.
+ if (Tok.is(tok::kw__Static_assert)) {
+ SourceLocation DeclEnd;
+ ParseStaticAssertDeclaration(DeclEnd);
+ continue;
+ }
+
if (!Tok.is(tok::at)) {
struct CFieldCallback : FieldCallback {
Parser &P;
@@ -3093,7 +3217,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// If attributes exist after tag, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// If declspecs exist after tag, parse them.
while (Tok.is(tok::kw___declspec))
@@ -3103,7 +3227,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool IsScopedUsingClassTag = false;
// In C++11, recognize 'enum class' and 'enum struct'.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
(Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
IsScopedUsingClassTag = Tok.is(tok::kw_class);
@@ -3115,7 +3239,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// They are allowed afterwards, though.
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
while (Tok.is(tok::kw___declspec))
ParseMicrosoftDeclSpec(attrs);
}
@@ -3135,7 +3259,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool AllowDeclaration = DSC != DSC_trailing;
bool AllowFixedUnderlyingType = AllowDeclaration &&
- (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
+ (getLangOpts().CPlusPlus11 || getLangOpts().MicrosoftExt ||
getLangOpts().ObjC2);
CXXScopeSpec &SS = DS.getTypeSpecScope();
@@ -3145,7 +3269,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
- /*EnteringContext=*/false))
+ /*EnteringContext=*/true))
return;
if (SS.isSet() && Tok.isNot(tok::identifier)) {
@@ -3254,7 +3378,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SourceRange Range;
BaseType = ParseTypeName(&Range);
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
} else if (!getLangOpts().ObjC2) {
if (getLangOpts().CPlusPlus)
@@ -3313,7 +3437,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
MultiTemplateParamsArg TParams;
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
TUK != Sema::TUK_Reference) {
- if (!getLangOpts().CPlusPlus0x || !SS.isSet()) {
+ if (!getLangOpts().CPlusPlus11 || !SS.isSet()) {
// Skip the rest of this declarator, up until the comma or semicolon.
Diag(Tok, diag::err_enum_template);
SkipUntil(tok::comma, true);
@@ -3433,7 +3557,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// If attributes exist after the enumerator, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
SourceLocation EqualLoc;
@@ -3471,12 +3595,12 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
SourceLocation CommaLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
- if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x)
+ if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11)
Diag(CommaLoc, getLangOpts().CPlusPlus ?
diag::ext_enumerator_list_comma_cxx :
diag::ext_enumerator_list_comma_c)
<< FixItHint::CreateRemoval(CommaLoc);
- else if (getLangOpts().CPlusPlus0x)
+ else if (getLangOpts().CPlusPlus11)
Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma)
<< FixItHint::CreateRemoval(CommaLoc);
}
@@ -3567,6 +3691,16 @@ 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:
@@ -3639,6 +3773,16 @@ 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:
@@ -3652,6 +3796,9 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_volatile:
case tok::kw_restrict:
+ // Debugger support.
+ case tok::kw___unknown_anytype:
+
// typedef-name
case tok::annot_typename:
return true;
@@ -3683,7 +3830,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_private:
return getLangOpts().OpenCL;
- // C11 _Atomic()
+ // C11 _Atomic
case tok::kw__Atomic:
return true;
}
@@ -3751,6 +3898,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// Modules
case tok::kw___module_private__:
+ // Debugger support
+ case tok::kw___unknown_anytype:
+
// type-specifiers
case tok::kw_short:
case tok::kw_long:
@@ -3777,6 +3927,16 @@ 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:
@@ -3794,6 +3954,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_inline:
case tok::kw_virtual:
case tok::kw_explicit:
+ case tok::kw__Noreturn:
+
+ // alignment-specifier
+ case tok::kw__Alignas:
// friend keyword.
case tok::kw_friend:
@@ -3811,7 +3975,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::annot_decltype:
case tok::kw_constexpr:
- // C11 _Atomic()
+ // C11 _Atomic
case tok::kw__Atomic:
return true;
@@ -3946,13 +4110,14 @@ bool Parser::isConstructorDeclarator() {
/// [vendor] type-qualifier-list attributes
/// [ only if VendorAttributesAllowed=true ]
/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
-/// [ only if CXX0XAttributesAllowed=true ]
+/// [ only if CXX11AttributesAllowed=true ]
/// Note: vendor can be GNU, MS, etc.
///
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
bool VendorAttributesAllowed,
- bool CXX11AttributesAllowed) {
- if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed &&
+ bool CXX11AttributesAllowed,
+ bool AtomicAllowed) {
+ if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX11Attributes(attrs);
@@ -3984,6 +4149,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
getLangOpts());
break;
+ case tok::kw__Atomic:
+ if (!AtomicAllowed)
+ goto DoneWithTypeQuals;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
+ getLangOpts());
+ break;
// OpenCL qualifiers:
case tok::kw_private:
@@ -4107,7 +4278,11 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
// The scope spec really belongs to the direct-declarator.
- D.getCXXScopeSpec() = SS;
+ if (D.mayHaveIdentifier())
+ D.getCXXScopeSpec() = SS;
+ else
+ AnnotateScopeToken(SS, true);
+
if (DirectDeclParser)
(this->*DirectDeclParser)(D);
return;
@@ -4176,7 +4351,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Complain about rvalue references in C++03, but then go on and build
// the declarator.
if (Kind == tok::ampamp)
- Diag(Loc, getLangOpts().CPlusPlus0x ?
+ Diag(Loc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_rvalue_reference :
diag::ext_rvalue_reference);
@@ -4194,6 +4369,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
Diag(DS.getVolatileSpecLoc(),
diag::err_invalid_reference_qualifier_application) << "volatile";
+ // 'restrict' is permitted as an extension.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(DS.getAtomicSpecLoc(),
+ diag::err_invalid_reference_qualifier_application) << "_Atomic";
}
// Recursively parse the declarator.
@@ -4216,7 +4395,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
}
}
- // Remember that we parsed a reference type. It doesn't have type-quals.
+ // Remember that we parsed a reference type.
D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
Kind == tok::amp),
DS.getAttributes(),
@@ -4308,6 +4487,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
!((D.getContext() == Declarator::PrototypeContext ||
D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) &&
+ !D.hasGroupingParens() &&
!Actions.containsUnexpandedParameterPacks(D))) {
SourceLocation EllipsisLoc = ConsumeToken();
if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) {
@@ -4334,8 +4514,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
else if (D.getCXXScopeSpec().isSet())
AllowConstructorName =
(D.getContext() == Declarator::FileContext ||
- (D.getContext() == Declarator::MemberContext &&
- D.getDeclSpec().isFriendSpecified()));
+ D.getContext() == Declarator::MemberContext);
else
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
@@ -4391,15 +4570,24 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// 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());
+
+ // The grammar for abstract-pack-declarator does not allow grouping parens.
+ // FIXME: Revisit this once core issue 1488 is resolved.
+ if (D.hasEllipsis() && D.hasGroupingParens())
+ Diag(PP.getLocForEndOfToken(D.getEllipsisLoc()),
+ diag::ext_abstract_pack_declarator_parens);
} 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)
- Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
- else
+ 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
+ Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
+ } else
Diag(Tok, diag::err_expected_ident_lparen);
D.SetIdentifier(0, Tok.getLocation());
D.setInvalidType(true);
@@ -4411,14 +4599,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// Don't parse attributes unless we have parsed an unparenthesized name.
if (D.hasName() && !D.getNumTypeObjects())
- MaybeParseCXX0XAttributes(D);
+ MaybeParseCXX11Attributes(D);
while (1) {
if (Tok.is(tok::l_paren)) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ Scope::FunctionPrototypeScope|Scope::DeclScope|
+ (D.isFunctionDeclaratorAFunctionDeclaration()
+ ? Scope::FunctionDeclarationScope : 0));
+
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
// In such a case, check if we actually have a function declarator; if it
// is not, the declarator has been fully parsed.
@@ -4483,13 +4674,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// present even if the attribute list was empty.
RequiresArg = true;
}
+
// Eat any Microsoft extensions.
- if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) ||
- Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64) ||
- Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
- ParseMicrosoftTypeAttributes(attrs);
- }
+ ParseMicrosoftTypeAttributes(attrs);
+
// Eat any Borland extensions.
if (Tok.is(tok::kw___pascal))
ParseBorlandTypeAttributes(attrs);
@@ -4551,7 +4739,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ Scope::FunctionPrototypeScope | Scope::DeclScope |
+ (D.isFunctionDeclaratorAFunctionDeclaration()
+ ? Scope::FunctionDeclarationScope : 0));
ParseFunctionDeclarator(D, attrs, T, false, RequiresArg);
PrototypeScope.Exit();
}
@@ -4646,7 +4836,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// with the virt-specifier-seq and pure-specifier in the same way.
// Parse cv-qualifier-seq[opt].
- ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
+ ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false,
+ /*CXX11AttributesAllowed*/ false,
+ /*AtomicAllowed*/ false);
if (!DS.getSourceRange().getEnd().isInvalid()) {
EndLoc = DS.getSourceRange().getEnd();
ConstQualifierLoc = DS.getConstSpecLoc();
@@ -4655,7 +4847,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// Parse ref-qualifier[opt].
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_ref_qualifier :
diag::ext_ref_qualifier);
@@ -4670,15 +4862,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
// and the end of the function-definition, member-declarator, or
// declarator.
+ // FIXME: currently, "static" case isn't handled correctly.
bool IsCXX11MemberFunction =
- getLangOpts().CPlusPlus0x &&
- (D.getContext() == Declarator::MemberContext ||
- (D.getContext() == Declarator::FileContext &&
- D.getCXXScopeSpec().isValid() &&
- Actions.CurContext->isRecord()));
+ getLangOpts().CPlusPlus11 &&
+ (D.getContext() == Declarator::MemberContext
+ ? !D.getDeclSpec().isFriendSpecified()
+ : D.getContext() == Declarator::FileContext &&
+ D.getCXXScopeSpec().isValid() &&
+ Actions.CurContext->isRecord());
Sema::CXXThisScopeRAII ThisScope(Actions,
dyn_cast<CXXRecordDecl>(Actions.CurContext),
- DS.getTypeQualifiers(),
+ DS.getTypeQualifiers() |
+ (D.getDeclSpec().isConstexprSpecified()
+ ? Qualifiers::Const : 0),
IsCXX11MemberFunction);
// Parse exception-specification[opt].
@@ -4691,11 +4887,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes
// after the exception-specification.
- MaybeParseCXX0XAttributes(FnAttrs);
+ MaybeParseCXX11Attributes(FnAttrs);
// Parse trailing-return-type[opt].
LocalEndLoc = EndLoc;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::arrow)) {
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
if (D.getDeclSpec().getTypeSpecType() == TST_auto)
StartLoc = D.getDeclSpec().getTypeSpecTypeLoc();
@@ -4866,11 +5062,10 @@ void Parser::ParseParameterDeclarationClause(
DeclSpec DS(AttrFactory);
// Parse any C++11 attributes.
- MaybeParseCXX0XAttributes(DS.getAttributes());
+ MaybeParseCXX11Attributes(DS.getAttributes());
// Skip any Microsoft attributes before a param.
- if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
- ParseMicrosoftAttributes(DS.getAttributes());
+ MaybeParseMicrosoftAttributes(DS.getAttributes());
SourceLocation DSStart = Tok.getLocation();
@@ -4955,7 +5150,7 @@ void Parser::ParseParameterDeclarationClause(
Param);
ExprResult DefArgResult;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
DefArgResult = ParseBraceInitializer();
} else
@@ -5017,7 +5212,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
if (Tok.getKind() == tok::r_square) {
T.consumeClose();
ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Remember that we parsed the empty array type.
ExprResult NumElements;
@@ -5034,10 +5229,10 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
T.consumeClose();
ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Remember that we parsed a array type, and remember its features.
- D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false,
ExprRes.release(),
T.getOpenLocation(),
T.getCloseLocation()),
@@ -5104,7 +5299,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
T.consumeClose();
ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
@@ -5184,14 +5379,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
/// _Atomic ( type-name )
///
void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier");
+ assert(Tok.is(tok::kw__Atomic) && NextToken().is(tok::l_paren) &&
+ "Not an atomic specifier");
SourceLocation StartLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) {
- SkipUntil(tok::r_paren);
+ if (T.consumeOpen())
return;
- }
TypeResult Result = ParseTypeName();
if (Result.isInvalid()) {
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f11a9d199572..d7f8e982aa5f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -11,16 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/OperatorKinds.h"
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
-#include "RAIIObjectsForParser.h"
using namespace clang;
/// ParseNamespace - We know that the current token is a namespace keyword. This
@@ -157,7 +158,7 @@ Decl *Parser::ParseNamespace(unsigned Context,
// If we're still good, complain about inline namespaces in non-C++0x now.
if (InlineLoc.isValid())
- Diag(InlineLoc, getLangOpts().CPlusPlus0x ?
+ Diag(InlineLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace);
// Enter a scope for the namespace.
@@ -195,7 +196,7 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
if (index == Ident.size()) {
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
}
@@ -295,7 +296,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
: SourceLocation());
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
if (Tok.isNot(tok::l_brace)) {
@@ -318,7 +319,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
T.consumeOpen();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
}
@@ -439,8 +440,8 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
/// unqualified-id
/// 'using' :: unqualified-id
///
-/// alias-declaration: C++0x [decl.typedef]p2
-/// 'using' identifier = type-id ;
+/// alias-declaration: C++11 [dcl.dcl]p1
+/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
///
Decl *Parser::ParseUsingDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
@@ -450,27 +451,27 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Decl **OwnedType) {
CXXScopeSpec SS;
SourceLocation TypenameLoc;
- bool IsTypeName;
- ParsedAttributesWithRange attrs(AttrFactory);
+ bool IsTypeName = false;
+ ParsedAttributesWithRange Attrs(AttrFactory);
// FIXME: Simply skip the attributes and diagnose, don't bother parsing them.
- MaybeParseCXX0XAttributes(attrs);
- ProhibitAttributes(attrs);
- attrs.clear();
- attrs.Range = SourceRange();
+ MaybeParseCXX11Attributes(Attrs);
+ ProhibitAttributes(Attrs);
+ Attrs.clear();
+ Attrs.Range = SourceRange();
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (Tok.is(tok::kw_typename)) {
- TypenameLoc = Tok.getLocation();
- ConsumeToken();
+ TypenameLoc = ConsumeToken();
IsTypeName = true;
}
- else
- IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ IdentifierInfo *LastII = 0;
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
+ /*MayBePseudoDtor=*/0, /*IsTypename=*/false,
+ /*LastII=*/&LastII);
// Check nested-name specifier.
if (SS.isInvalid()) {
@@ -478,33 +479,45 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+
// Parse the unqualified-id. We allow parsing of both constructor and
// destructor names and allow the action module to diagnose any semantic
// errors.
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/true,
- /*AllowConstructorName=*/true,
- ParsedType(),
- TemplateKWLoc,
- Name)) {
+ //
+ // C++11 [class.qual]p2:
+ // [...] in a using-declaration that is a member-declaration, if the name
+ // specified after the nested-name-specifier is the same as the identifier
+ // or the simple-template-id's template-name in the last component of the
+ // nested-name-specifier, the name is [...] considered to name the
+ // constructor.
+ if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
+ Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
+ SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
+ !SS.getScopeRep()->getAsNamespace() &&
+ !SS.getScopeRep()->getAsNamespaceAlias()) {
+ SourceLocation IdLoc = ConsumeToken();
+ ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII);
+ Name.setConstructorName(Type, IdLoc, IdLoc);
+ } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false,
+ /*AllowDestructorName=*/ true,
+ /*AllowConstructorName=*/ true, ParsedType(),
+ TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
return 0;
}
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(Attrs);
// Maybe this is an alias-declaration.
bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
if (IsAliasDecl) {
- // TODO: Attribute support. C++0x attributes may appear before the equals.
- // Where can GNU attributes appear?
+ // TODO: Can GNU attributes appear here?
ConsumeToken();
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_alias_declaration :
diag::ext_alias_declaration);
@@ -546,25 +559,26 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
- Declarator::AliasDeclContext, AS, OwnedType);
+ Declarator::AliasDeclContext, AS, OwnedType,
+ &Attrs);
} else {
// C++11 attributes are not allowed on a using-declaration, but GNU ones
// are.
- ProhibitAttributes(attrs);
+ ProhibitAttributes(Attrs);
// Parse (optional) attributes (most likely GNU strong-using extension).
- MaybeParseGNUAttributes(attrs);
+ MaybeParseGNUAttributes(Attrs);
}
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- !attrs.empty() ? "attributes list" :
+ !Attrs.empty() ? "attributes list" :
IsAliasDecl ? "alias declaration" : "using declaration",
tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
- // In C++0x, alias-declarations can be templates:
+ // In C++11, alias-declarations can be templates:
// template <...> using id = type;
if (TemplateInfo.Kind && !IsAliasDecl) {
SourceRange R = TemplateInfo.getSourceRange();
@@ -591,13 +605,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
- // FIXME: Propagate attributes.
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
- UsingLoc, Name, TypeAlias);
+ UsingLoc, Name, Attrs.getList(),
+ TypeAlias);
}
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
- Name, attrs.getList(),
+ Name, Attrs.getList(),
IsTypeName, TypenameLoc);
}
@@ -637,7 +651,8 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
return 0;
if (!isTokenStringLiteral()) {
- Diag(Tok, diag::err_expected_string_literal);
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='static_assert'*/1;
SkipMalformedDecl();
return 0;
}
@@ -800,15 +815,18 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
/// class. The result is either a type or null, depending on whether a type
/// name was found.
///
-/// base-type-specifier: [C++ 10.1]
+/// base-type-specifier: [C++11 class.derived]
/// class-or-decltype
-/// class-or-decltype: [C++ 10.1]
+/// class-or-decltype: [C++11 class.derived]
/// nested-name-specifier[opt] class-name
/// decltype-specifier
-/// class-name: [C++ 9.1]
+/// class-name: [C++ class.name]
/// identifier
/// simple-template-id
///
+/// In C++98, instead of base-type-specifier, we have:
+///
+/// ::[opt] nested-name-specifier[opt] class-name
Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
SourceLocation &EndLocation) {
// Ignore attempts to use typename
@@ -956,6 +974,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::semi: // struct foo {...} ;
case tok::star: // struct foo {...} * P;
case tok::amp: // struct foo {...} & R = ...
+ case tok::ampamp: // struct foo {...} && R = ...
case tok::identifier: // struct foo {...} V ;
case tok::r_paren: //(struct foo {...} ) {4}
case tok::annot_cxxscope: // struct foo {...} a:: b;
@@ -963,6 +982,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::annot_template_id: // struct foo {...} a<int> ::b;
case tok::l_paren: // struct foo {...} ( x);
case tok::comma: // __builtin_offsetof(struct foo{...} ,
+ case tok::kw_operator: // struct foo operator ++() {...}
return true;
case tok::colon:
return CouldBeBitfield; // enum E { ... } : 2;
@@ -970,7 +990,12 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::kw_const: // struct foo {...} const x;
case tok::kw_volatile: // struct foo {...} volatile x;
case tok::kw_restrict: // struct foo {...} restrict x;
- case tok::kw_inline: // struct foo {...} inline foo() {};
+ // Function specifiers
+ // Note, no 'explicit'. An explicit function must be either a conversion
+ // operator or a constructor. Either way, it can't have a return type.
+ case tok::kw_inline: // struct foo inline f();
+ case tok::kw_virtual: // struct foo virtual f();
+ case tok::kw_friend: // struct foo friend f();
// Storage-class specifiers
case tok::kw_static: // struct foo {...} static x;
case tok::kw_extern: // struct foo {...} extern x;
@@ -978,6 +1003,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::kw_register: // struct foo {...} register x;
case tok::kw_auto: // struct foo {...} auto x;
case tok::kw_mutable: // struct foo {...} mutable x;
+ case tok::kw_thread_local: // struct foo {...} thread_local x;
case tok::kw_constexpr: // struct foo {...} constexpr x;
// As shown above, type qualifiers and storage class specifiers absolutely
// can occur after class specifiers according to the grammar. However,
@@ -1002,6 +1028,13 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
if (!getLangOpts().CPlusPlus)
return true;
break;
+ // C++11 attributes
+ case tok::l_square: // enum E [[]] x
+ // Note, no tok::kw_alignas here; alignas cannot appertain to a type.
+ return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square);
+ case tok::greater:
+ // template<class T = class X>
+ return getLangOpts().CPlusPlus;
}
return false;
}
@@ -1050,7 +1083,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
- bool EnteringContext, DeclSpecContext DSC) {
+ bool EnteringContext, DeclSpecContext DSC,
+ ParsedAttributesWithRange &Attributes) {
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -1102,7 +1136,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If C++0x attributes exist here, parse them.
// FIXME: Are we consistent with the ordering of parsing of different
// styles of attributes?
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
+
+ // Source location used by FIXIT to insert misplaced
+ // C++11 attributes
+ SourceLocation AttrFixitLoc = Tok.getLocation();
if (TagType == DeclSpec::TST_struct &&
!Tok.is(tok::identifier) &&
@@ -1232,18 +1270,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// - If we have 'struct foo;', then this is either a forward declaration
// or a friend declaration, which have to be treated differently.
// - Otherwise we have something like 'struct foo xyz', a reference.
+ //
+ // We also detect these erroneous cases to provide better diagnostic for
+ // C++11 attributes parsing.
+ // - attributes follow class name:
+ // struct foo [[]] {};
+ // - attributes appear before or after 'final':
+ // struct foo [[]] final [[]] {};
+ //
// However, in type-specifier-seq's, things look like declarations but are
// just references, e.g.
// new struct s;
// or
// &T::operator struct s;
// For these, DSC is DSC_type_specifier.
+
+ // If there are attributes after class name, parse them.
+ MaybeParseCXX11Attributes(Attributes);
+
Sema::TagUseKind TUK;
if (DSC == DSC_trailing)
TUK = Sema::TUK_Reference;
else if (Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- (isCXX0XFinalKeyword() &&
+ (isCXX11FinalKeyword() &&
(NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) {
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
@@ -1259,6 +1309,37 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Okay, this is a class definition.
TUK = Sema::TUK_Definition;
}
+ } else if (isCXX11FinalKeyword() && (NextToken().is(tok::l_square) ||
+ NextToken().is(tok::kw_alignas))) {
+ // We can't tell if this is a definition or reference
+ // until we skipped the 'final' and C++11 attribute specifiers.
+ TentativeParsingAction PA(*this);
+
+ // Skip the 'final' keyword.
+ ConsumeToken();
+
+ // Skip C++11 attribute specifiers.
+ while (true) {
+ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ break;
+ } else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) {
+ ConsumeToken();
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ break;
+ } else {
+ break;
+ }
+ }
+
+ if (Tok.is(tok::l_brace) || Tok.is(tok::colon))
+ TUK = Sema::TUK_Definition;
+ else
+ TUK = Sema::TUK_Reference;
+
+ PA.Revert();
} else if (DSC != DSC_type_specifier &&
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) {
@@ -1273,6 +1354,28 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else
TUK = Sema::TUK_Reference;
+ // Forbid misplaced attributes. In cases of a reference, we pass attributes
+ // to caller to handle.
+ if (TUK != Sema::TUK_Reference) {
+ // If this is not a reference, then the only possible
+ // valid place for C++11 attributes to appear here
+ // is between class-key and class-name. If there are
+ // any attributes after class-name, we try a fixit to move
+ // them to the right place.
+ SourceRange AttrRange = Attributes.Range;
+ if (AttrRange.isValid()) {
+ Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
+ << AttrRange
+ << FixItHint::CreateInsertionFromRange(AttrFixitLoc,
+ CharSourceRange(AttrRange, true))
+ << FixItHint::CreateRemoval(AttrRange);
+
+ // Recover by adding misplaced attributes to the attribute list
+ // of the class so they can be applied on the class later.
+ attrs.takeAllFrom(Attributes);
+ }
+ }
+
// If this is an elaborated type specifier, and we delayed
// diagnostics before, just merge them into the current pool.
if (shouldDelayDiagsInTag) {
@@ -1414,11 +1517,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
} else {
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
- TUK == Sema::TUK_Definition) {
- // FIXME: Diagnose this particular error.
- }
-
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
ProhibitAttributes(attrs);
@@ -1453,9 +1551,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX0XFinalKeyword());
+ isCXX11FinalKeyword());
if (getLangOpts().CPlusPlus)
- ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
+ ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
+ TagOrTempResult.get());
else
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
}
@@ -1490,13 +1589,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// is permitted.
if (TUK == Sema::TUK_Definition &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- DeclSpec::getSpecifierName(TagType));
- // 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.
- PP.EnterToken(Tok);
- Tok.setKind(tok::semi);
+ if (Tok.isNot(tok::semi)) {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
+ DeclSpec::getSpecifierName(TagType));
+ // 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.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::semi);
+ }
}
}
@@ -1544,26 +1645,33 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
/// 'public bar' and 'virtual private baz' are each base-specifiers.
///
/// base-specifier: [C++ class.derived]
-/// ::[opt] nested-name-specifier[opt] class-name
-/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
-/// base-type-specifier
-/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
-/// base-type-specifier
+/// attribute-specifier-seq[opt] base-type-specifier
+/// attribute-specifier-seq[opt] 'virtual' access-specifier[opt]
+/// base-type-specifier
+/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
+/// base-type-specifier
Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
+ ParsedAttributesWithRange Attributes(AttrFactory);
+ MaybeParseCXX11Attributes(Attributes);
+
// Parse the 'virtual' keyword.
if (Tok.is(tok::kw_virtual)) {
ConsumeToken();
IsVirtual = true;
}
+ CheckMisplacedCXX11Attribute(Attributes, StartLoc);
+
// Parse an (optional) access specifier.
AccessSpecifier Access = getAccessSpecifierIfPresent();
if (Access != AS_none)
ConsumeToken();
+ CheckMisplacedCXX11Attribute(Attributes, StartLoc);
+
// Parse the 'virtual' keyword (again!), in case it came after the
// access specifier.
if (Tok.is(tok::kw_virtual)) {
@@ -1577,6 +1685,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
IsVirtual = true;
}
+ CheckMisplacedCXX11Attribute(Attributes, StartLoc);
+
// Parse the class-name.
SourceLocation EndLocation;
SourceLocation BaseLoc;
@@ -1596,8 +1706,9 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
// Notify semantic analysis that we have parsed a complete
// base-specifier.
- return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
- BaseType.get(), BaseLoc, EllipsisLoc);
+ return Actions.ActOnBaseSpecifier(ClassDecl, Range, Attributes, IsVirtual,
+ Access, BaseType.get(), BaseLoc,
+ EllipsisLoc);
}
/// getAccessSpecifierIfPresent - Determine whether the next token is
@@ -1653,13 +1764,13 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
}
}
-/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x
+/// isCXX11VirtSpecifier - Determine whether the given token is a C++11
/// virt-specifier.
///
/// virt-specifier:
/// override
/// final
-VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
+VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
if (!getLangOpts().CPlusPlus)
return VirtSpecifiers::VS_None;
@@ -1682,15 +1793,15 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
return VirtSpecifiers::VS_None;
}
-/// ParseOptionalCXX0XVirtSpecifierSeq - Parse a virt-specifier-seq.
+/// ParseOptionalCXX11VirtSpecifierSeq - Parse a virt-specifier-seq.
///
/// virt-specifier-seq:
/// virt-specifier
/// virt-specifier-seq virt-specifier
-void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
+void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
bool IsInterface) {
while (true) {
- VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier();
+ VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
return;
@@ -1706,7 +1817,7 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
Diag(Tok.getLocation(), diag::err_override_control_interface)
<< VirtSpecifiers::getSpecifierName(Specifier);
} else {
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_override_control_keyword :
diag::ext_override_control_keyword)
<< VirtSpecifiers::getSpecifierName(Specifier);
@@ -1715,9 +1826,9 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
}
}
-/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x
+/// isCXX11FinalKeyword - Determine whether the next token is a C++11
/// contextual 'final' keyword.
-bool Parser::isCXX0XFinalKeyword() const {
+bool Parser::isCXX11FinalKeyword() const {
if (!getLangOpts().CPlusPlus)
return false;
@@ -1861,8 +1972,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ColonProtectionRAIIObject X(*this);
ParsedAttributesWithRange attrs(AttrFactory);
- // Optional C++0x attribute-specifier
- MaybeParseCXX0XAttributes(attrs);
+ ParsedAttributesWithRange FnAttrs(AttrFactory);
+ // Optional C++11 attribute-specifier
+ MaybeParseCXX11Attributes(attrs);
+ // We need to keep these attributes for future diagnostic
+ // before they are taken over by declaration specifier.
+ FnAttrs.addAll(attrs.getList());
+ FnAttrs.Range = attrs.Range;
+
MaybeParseMicrosoftAttributes(attrs);
if (Tok.is(tok::kw_using)) {
@@ -1901,6 +2018,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::semi)) {
ConsumeToken();
+
+ if (DS.isFriendSpecified())
+ ProhibitAttributes(FnAttrs);
+
Decl *TheDecl =
Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
DS.complete(TheDecl);
@@ -1931,7 +2052,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
@@ -1955,7 +2076,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// In C++11, a non-function declarator followed by an open brace is a
// braced-init-list for an in-class member initialization, not an
// erroneous function definition.
- if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) {
+ if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus11) {
DefinitionKind = FDK_Definition;
} else if (DeclaratorInfo.isFunctionDeclarator()) {
if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
@@ -1969,12 +2090,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
}
+ // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
+ // to a friend declaration, that declaration shall be a definition.
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ DefinitionKind != FDK_Definition && DS.isFriendSpecified()) {
+ // Diagnose attributes that appear before decl specifier:
+ // [[]] friend int foo();
+ ProhibitAttributes(FnAttrs);
+ }
+
if (DefinitionKind) {
if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params);
ConsumeBrace();
SkipUntil(tok::r_brace, /*StopAtSemi*/false);
-
+
// Consume the optional ';'
if (Tok.is(tok::semi))
ConsumeToken();
@@ -1984,16 +2114,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
Diag(DeclaratorInfo.getIdentifierLoc(),
diag::err_function_declared_typedef);
- // This recovery skips the entire function body. It would be nice
- // to simply call ParseCXXInlineMethodDef() below, however Sema
- // assumes the declarator represents a function, not a typedef.
- ConsumeBrace();
- SkipUntil(tok::r_brace, /*StopAtSemi*/false);
- // Consume the optional ';'
- if (Tok.is(tok::semi))
- ConsumeToken();
- return;
+ // Recover by treating the 'typedef' as spurious.
+ DS.ClearStorageClassSpecs();
}
Decl *FunDecl =
@@ -2052,7 +2175,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// FIXME: When g++ adds support for this, we'll need to check whether it
// goes before or after the GNU attributes and __asm__.
- ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
InClassInitStyle HasInClassInit = ICIS_NoInit;
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
@@ -2063,8 +2186,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
HasInitializer = true;
if (!DeclaratorInfo.isDeclarationOfFunction() &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_static &&
- DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef)
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
}
@@ -2074,8 +2195,23 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
- Decl *ThisDecl = 0;
+ NamedDecl *ThisDecl = 0;
if (DS.isFriendSpecified()) {
+ // 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 [[]] ();
+ SmallVector<SourceRange, 4> Ranges;
+ DeclaratorInfo.getCXX11AttributeRanges(Ranges);
+ if (!Ranges.empty()) {
+ for (SmallVector<SourceRange, 4>::iterator I = Ranges.begin(),
+ E = Ranges.end(); I != E; ++I) {
+ Diag((*I).getBegin(), diag::err_attributes_not_allowed)
+ << *I;
+ }
+ }
+
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
@@ -2100,9 +2236,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
LateParsedAttrs.clear();
// Handle the initializer.
- if (HasInClassInit != ICIS_NoInit) {
+ if (HasInClassInit != ICIS_NoInit &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
+ DeclSpec::SCS_static) {
// The initializer was deferred; parse it and cache the tokens.
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nonstatic_member_init :
diag::ext_nonstatic_member_init);
@@ -2264,6 +2402,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
/// access-specifier ':' member-specification[opt]
///
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
+ SourceLocation AttrFixitLoc,
+ ParsedAttributesWithRange &Attrs,
unsigned TagType, Decl *TagDecl) {
assert((TagType == DeclSpec::TST_struct ||
TagType == DeclSpec::TST_interface ||
@@ -2320,17 +2460,23 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Parse the optional 'final' keyword.
if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
- assert(isCXX0XFinalKeyword() && "not a class definition");
+ assert(isCXX11FinalKeyword() && "not a class definition");
FinalLoc = ConsumeToken();
if (TagType == DeclSpec::TST_interface) {
Diag(FinalLoc, diag::err_override_control_interface)
<< "final";
} else {
- Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
+ Diag(FinalLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_override_control_keyword :
diag::ext_override_control_keyword) << "final";
}
+
+ // Parse any C++11 attributes after 'final' keyword.
+ // These attributes are not allowed to appear here,
+ // and the only possible place for them to appertain
+ // to the class would be between class-key and class-name.
+ CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
}
if (Tok.is(tok::colon)) {
@@ -2395,6 +2541,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_openmp)) {
+ ParseOpenMPDeclarativeDirective();
+ continue;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2551,8 +2702,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
}
} while (true);
- Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
- MemInitializers.data(), MemInitializers.size(),
+ Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, MemInitializers,
AnyErrors);
}
@@ -2606,7 +2756,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// Parse the '('.
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
ExprResult InitList = ParseBraceInitializer();
@@ -2645,7 +2795,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
EllipsisLoc);
}
- Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace
+ Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace
: diag::err_expected_lparen);
return true;
}
@@ -2892,9 +3042,9 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
case tok::exclaimequal: // 'not_eq'
// Alternative tokens do not have identifier info, but their spelling
// starts with an alphabetical character.
- llvm::SmallString<8> SpellingBuf;
+ SmallString<8> SpellingBuf;
StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf);
- if (std::isalpha(Spelling[0])) {
+ if (isLetter(Spelling[0])) {
Loc = ConsumeToken();
return &PP.getIdentifierTable().get(Spelling);
}
@@ -2908,7 +3058,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
case AttributeList::AT_FallThrough:
- case AttributeList::AT_NoReturn: {
+ case AttributeList::AT_CXX11NoReturn: {
return true;
}
@@ -2971,6 +3121,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
ConsumeBracket();
ConsumeBracket();
+ llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs;
+
while (Tok.isNot(tok::r_square)) {
// attribute not present
if (Tok.is(tok::comma)) {
@@ -3004,6 +3156,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
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]);
+
// Parse attribute arguments
if (Tok.is(tok::l_paren)) {
if (ScopeName && ScopeName->getName() == "gnu") {
@@ -3050,6 +3207,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
/// attribute-specifier-seq[opt] attribute-specifier
void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc) {
+ assert(getLangOpts().CPlusPlus11);
+
SourceLocation StartLoc = Tok.getLocation(), Loc;
if (!endLoc)
endLoc = &Loc;
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index c7be0d3ff2b9..956ba36d3c88 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -22,77 +22,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
-#include "clang/Basic/PrettyStackTrace.h"
-#include "RAIIObjectsForParser.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
-/// \brief Return the precedence of the specified binary operator token.
-static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
- bool GreaterThanIsOperator,
- bool CPlusPlus0x) {
- switch (Kind) {
- case tok::greater:
- // C++ [temp.names]p3:
- // [...] When parsing a template-argument-list, the first
- // non-nested > is taken as the ending delimiter rather than a
- // greater-than operator. [...]
- if (GreaterThanIsOperator)
- return prec::Relational;
- return prec::Unknown;
-
- case tok::greatergreater:
- // C++0x [temp.names]p3:
- //
- // [...] Similarly, the first non-nested >> is treated as two
- // consecutive but distinct > tokens, the first of which is
- // taken as the end of the template-argument-list and completes
- // the template-id. [...]
- if (GreaterThanIsOperator || !CPlusPlus0x)
- return prec::Shift;
- return prec::Unknown;
-
- default: return prec::Unknown;
- case tok::comma: return prec::Comma;
- case tok::equal:
- case tok::starequal:
- case tok::slashequal:
- case tok::percentequal:
- case tok::plusequal:
- case tok::minusequal:
- case tok::lesslessequal:
- case tok::greatergreaterequal:
- case tok::ampequal:
- case tok::caretequal:
- case tok::pipeequal: return prec::Assignment;
- case tok::question: return prec::Conditional;
- case tok::pipepipe: return prec::LogicalOr;
- case tok::ampamp: return prec::LogicalAnd;
- case tok::pipe: return prec::InclusiveOr;
- case tok::caret: return prec::ExclusiveOr;
- case tok::amp: return prec::And;
- case tok::exclaimequal:
- case tok::equalequal: return prec::Equality;
- case tok::lessequal:
- case tok::less:
- case tok::greaterequal: return prec::Relational;
- case tok::lessless: return prec::Shift;
- case tok::plus:
- case tok::minus: return prec::Additive;
- case tok::percent:
- case tok::slash:
- case tok::star: return prec::Multiplicative;
- case tok::periodstar:
- case tok::arrowstar: return prec::PointerToMember;
- }
-}
-
-
/// \brief Simple precedence-based parser for binary/ternary operators.
///
/// Note: we diverge from the C99 grammar when parsing the assignment-expression
@@ -282,7 +221,7 @@ ExprResult
Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
GreaterThanIsOperator,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
SourceLocation ColonLoc;
while (1) {
@@ -383,7 +322,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// they only appear on the RHS of assignments later.
ExprResult RHS;
bool RHSIsInitList = false;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
RHS = ParseBraceInitializer();
RHSIsInitList = true;
} else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional)
@@ -398,7 +337,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// operator immediately to the right of the RHS.
prec::Level ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
// Assignment and conditional expressions are right-associative.
bool isRightAssoc = ThisPrec == prec::Conditional ||
@@ -426,7 +365,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
LHS = ExprError();
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
}
assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
@@ -1036,7 +975,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::annot_typename:
if (isStartOfObjCClassMessageMissingOpenBracket()) {
ParsedType Type = getTypeAnnotation(Tok);
-
+
// Fake up a Declarator to use with ActOnTypeName.
DeclSpec DS(AttrFactory);
DS.SetRangeStart(Tok.getLocation());
@@ -1046,7 +985,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
unsigned DiagID;
DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, Type);
-
+
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
if (Ty.isInvalid())
@@ -1058,7 +997,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
}
// Fall through
-
+
case tok::annot_decltype:
case tok::kw_char:
case tok::kw_wchar_t:
@@ -1078,7 +1017,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
- case tok::kw___vector: {
+ 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: {
if (!getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
@@ -1097,7 +1044,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren) &&
- (!getLangOpts().CPlusPlus0x || Tok.isNot(tok::l_brace)))
+ (!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace)))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
@@ -1241,10 +1188,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_union:
case tok::kw___is_final:
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:
@@ -1282,7 +1232,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ExprError();
}
case tok::l_square:
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
if (getLangOpts().ObjC1) {
// C++11 lambda expressions and Objective-C message sends both start with a
// square bracket. There are three possibilities here:
@@ -1381,7 +1331,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
T.consumeOpen();
Loc = T.getOpenLocation();
ExprResult Idx;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Idx = ParseBraceInitializer();
} else
@@ -1459,7 +1409,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCall(getCurScope(), LHS.get(),
- llvm::ArrayRef<Expr *>());
+ ArrayRef<Expr *>());
cutOffParsing();
return ExprError();
}
@@ -1663,11 +1613,11 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
/// unary-expression: [C99 6.5.3]
/// 'sizeof' unary-expression
/// 'sizeof' '(' type-name ')'
-/// [C++0x] 'sizeof' '...' '(' identifier ')'
+/// [C++11] 'sizeof' '...' '(' identifier ')'
/// [GNU] '__alignof' unary-expression
/// [GNU] '__alignof' '(' type-name ')'
/// [C11] '_Alignof' '(' type-name ')'
-/// [C++0x] 'alignof' '(' type-id ')'
+/// [C++11] 'alignof' '(' type-id ')'
/// \endverbatim
ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) ||
@@ -1677,7 +1627,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
Token OpTok = Tok;
ConsumeToken();
- // [C++0x] 'sizeof' '...' '(' identifier ')'
+ // [C++11] 'sizeof' '...' '(' identifier ')'
if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) {
SourceLocation EllipsisLoc = ConsumeToken();
SourceLocation LParenLoc, RParenLoc;
@@ -1748,6 +1698,9 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
CastTy.getAsOpaquePtr(),
CastRange);
+ if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof))
+ Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo();
+
// If we get here, the operand to the sizeof/alignof was an expresion.
if (!Operand.isInvalid())
Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
@@ -2008,12 +1961,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Tok.is(tok::kw___bridge_retained) ||
Tok.is(tok::kw___bridge_retain)));
if (BridgeCast && !getLangOpts().ObjCAutoRefCount) {
- StringRef BridgeCastName = Tok.getName();
- SourceLocation BridgeKeywordLoc = ConsumeToken();
- if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
- Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc)
- << BridgeCastName
- << FixItHint::CreateReplacement(BridgeKeywordLoc, "");
+ if (Tok.isNot(tok::kw___bridge)) {
+ StringRef BridgeCastName = Tok.getName();
+ SourceLocation BridgeKeywordLoc = ConsumeToken();
+ if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
+ Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc)
+ << BridgeCastName
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "");
+ }
+ else
+ ConsumeToken(); // consume __bridge
BridgeCast = false;
}
@@ -2360,10 +2317,10 @@ ExprResult Parser::ParseGenericSelectionExpression() {
/// [C++0x] braced-init-list
/// \endverbatim
bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
- SmallVectorImpl<SourceLocation> &CommaLocs,
- void (Sema::*Completer)(Scope *S,
- Expr *Data,
- llvm::ArrayRef<Expr *> Args),
+ SmallVectorImpl<SourceLocation> &CommaLocs,
+ void (Sema::*Completer)(Scope *S,
+ Expr *Data,
+ ArrayRef<Expr *> Args),
Expr *Data) {
while (1) {
if (Tok.is(tok::code_completion)) {
@@ -2376,7 +2333,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
}
ExprResult Expr;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Expr = ParseBraceInitializer();
} else
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 2f615e150aad..17c4adf7d7ef 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -11,14 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/LiteralSupport.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -99,7 +99,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
/// \brief Emits an error for a left parentheses after a double colon.
///
/// When a '(' is found after a '::', emit an error. Attempt to fix the token
-/// stream by removing the '(', and the matching ')' if it found.
+/// stream by removing the '(', and the matching ')' if found.
void Parser::CheckForLParenAfterColonColon() {
if (!Tok.is(tok::l_paren))
return;
@@ -168,19 +168,26 @@ void Parser::CheckForLParenAfterColonColon() {
/// if we do end up determining that we are parsing a destructor name,
/// the last component of the nested-name-specifier is not parsed as
/// part of the scope specifier.
-
-/// member access expression, e.g., the \p T:: in \p p->T::m.
+///
+/// \param IsTypename If \c true, this nested-name-specifier is known to be
+/// part of a type name. This is used to improve error recovery.
+///
+/// \param LastII When non-NULL, points to an IdentifierInfo* that will be
+/// filled in with the leading identifier in the last component of the
+/// nested-name-specifier, if any.
///
/// \returns true if there was an error parsing a scope specifier
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
bool *MayBePseudoDestructor,
- bool IsTypename) {
+ bool IsTypename,
+ IdentifierInfo **LastII) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
if (Tok.is(tok::annot_cxxscope)) {
+ assert(!LastII && "want last identifier but have already annotated scope");
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
@@ -188,6 +195,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (LastII)
+ *LastII = 0;
+
bool HasScopeSpecifier = false;
if (Tok.is(tok::coloncolon)) {
@@ -334,6 +344,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (LastII)
+ *LastII = TemplateId->Name;
+
// Consume the template-id token.
ConsumeToken();
@@ -405,6 +418,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (LastII)
+ *LastII = &II;
+
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
SourceLocation IdLoc = ConsumeToken();
@@ -602,7 +618,7 @@ ExprResult Parser::ParseLambdaExpression() {
// Parse lambda-introducer.
LambdaIntroducer Intro;
- llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square);
@@ -620,7 +636,7 @@ ExprResult Parser::ParseLambdaExpression() {
///
/// If we are not looking at a lambda expression, returns ExprError().
ExprResult Parser::TryParseLambdaExpression() {
- assert(getLangOpts().CPlusPlus0x
+ assert(getLangOpts().CPlusPlus11
&& Tok.is(tok::l_square)
&& "Not at the start of a possible lambda expression.");
@@ -658,8 +674,8 @@ ExprResult Parser::TryParseLambdaExpression() {
/// ParseLambdaExpression - Parse a lambda introducer.
///
/// Returns a DiagnosticID if it hit something unexpected.
-llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){
- typedef llvm::Optional<unsigned> DiagResult;
+Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
+ typedef Optional<unsigned> DiagResult;
assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
BalancedDelimiterTracker T(*this, tok::l_square);
@@ -769,7 +785,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){
bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
TentativeParsingAction PA(*this);
- llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
if (DiagID) {
PA.Revert();
@@ -797,6 +813,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
Scope::DeclScope);
SourceLocation DeclEndLoc;
@@ -806,7 +823,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse parameter-declaration-clause.
ParsedAttributes Attr(AttrFactory);
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
if (Tok.isNot(tok::r_paren))
@@ -826,8 +843,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse exception-specification[opt].
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
- llvm::SmallVector<ParsedType, 2> DynamicExceptions;
- llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ SmallVector<ParsedType, 2> DynamicExceptions;
+ SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
ESpecType = tryParseExceptionSpecification(ESpecRange,
DynamicExceptions,
@@ -838,7 +855,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclEndLoc = ESpecRange.getEnd();
// Parse attribute-specifier[opt].
- MaybeParseCXX0XAttributes(Attr, &DeclEndLoc);
+ MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
SourceLocation FunLocalRangeEnd = DeclEndLoc;
@@ -1288,7 +1305,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
assert((Tok.is(tok::l_paren) ||
- (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)))
+ (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)))
&& "Expected '(' or '{'!");
if (Tok.is(tok::l_brace)) {
@@ -1362,7 +1379,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
}
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
if (!isCXXConditionDeclaration()) {
ProhibitAttributes(attrs);
@@ -1382,6 +1399,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// type-specifier-seq
DeclSpec DS(AttrFactory);
+ DS.takeAttributesFrom(attrs);
ParseSpecifierQualifierList(DS);
// declarator
@@ -1416,7 +1434,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
ConsumeToken();
ExprResult InitExpr = ExprError();
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
InitExpr = ParseBraceInitializer();
@@ -1851,7 +1869,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
SymbolLocations[SymbolIdx++] = ConsumeToken();
// Check for array new/delete.
if (Tok.is(tok::l_square) &&
- (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) {
+ (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))) {
// Consume the '[' and ']'.
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
@@ -1928,7 +1946,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// operator string-literal identifier
// operator user-defined-string-literal
- if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) {
+ if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
SourceLocation DiagLoc;
@@ -1936,8 +1954,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// We're past translation phase 6, so perform string literal concatenation
// before checking for "".
- llvm::SmallVector<Token, 4> Toks;
- llvm::SmallVector<SourceLocation, 4> TokLocs;
+ SmallVector<Token, 4> Toks;
+ SmallVector<SourceLocation, 4> TokLocs;
while (isTokenStringLiteral()) {
if (!Tok.is(tok::string_literal) && !DiagId) {
// C++11 [over.literal]p1:
@@ -1986,7 +2004,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
if (DiagId) {
// This isn't a valid literal-operator-id, but we think we know
// what the user meant. Tell them what they should have written.
- llvm::SmallString<32> Str;
+ SmallString<32> Str;
Str += "\"\" ";
Str += II->getName();
Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement(
@@ -2361,7 +2379,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
ConstructorRParen,
ConstructorArgs);
- } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) {
+ } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
Initializer = ParseBraceInitializer();
@@ -2405,7 +2423,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
// Attributes here appertain to the array type. C++11 [expr.new]p5.
ParsedAttributes Attrs(AttrFactory);
- MaybeParseCXX0XAttributes(Attrs);
+ MaybeParseCXX11Attributes(Attrs);
D.AddTypeInfo(DeclaratorChunk::getArray(0,
/*static=*/false, /*star=*/false,
@@ -2493,11 +2511,15 @@ 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;
@@ -2659,7 +2681,7 @@ ExprResult Parser::ParseTypeTrait() {
if (Parens.expectAndConsume(diag::err_expected_lparen))
return ExprError();
- llvm::SmallVector<ParsedType, 2> Args;
+ SmallVector<ParsedType, 2> Args;
do {
// Parse the next type.
TypeResult Ty = ParseTypeName();
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index e47fd9bd24a6..3b967174bc5a 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallString.h"
@@ -33,7 +33,7 @@ bool Parser::MayBeDesignationStart() {
return true;
case tok::l_square: { // designator: array-designator
- if (!PP.getLangOpts().CPlusPlus0x)
+ if (!PP.getLangOpts().CPlusPlus11)
return true;
// C++11 lambda expressions and C99 designators can be ambiguous all the
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index d321baf836bf..ad95dd5821ce 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
@@ -21,6 +22,18 @@
#include "llvm/ADT/StringExtras.h"
using namespace clang;
+/// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
+void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
+ ParsedAttributes attrs(AttrFactory);
+ if (Tok.is(tok::kw___attribute)) {
+ if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
+ Diag(Tok, diag::err_objc_postfix_attribute_hint)
+ << (Kind == tok::objc_protocol);
+ else
+ Diag(Tok, diag::err_objc_postfix_attribute);
+ ParseGNUAttributes(attrs);
+ }
+}
/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
/// external-declaration: [C99 6.9]
@@ -65,7 +78,7 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
case tok::objc_dynamic:
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
break;
- case tok::objc___experimental_modules_import:
+ case tok::objc_import:
if (getLangOpts().Modules)
return ParseModuleImport(AtLoc);
@@ -92,6 +105,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
while (1) {
+ MaybeSkipAttributes(tok::objc_class);
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
@@ -178,6 +192,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
return 0;
}
+ MaybeSkipAttributes(tok::objc_interface);
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing class or category name.
return 0;
@@ -690,7 +706,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
case tok::caret:
case tok::caretequal: {
std::string ThisTok(PP.getSpelling(Tok));
- if (isalpha(ThisTok[0])) {
+ if (isLetter(ThisTok[0])) {
IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok.data());
Tok.setKind(tok::identifier);
SelectorLoc = ConsumeToken();
@@ -1028,8 +1044,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SmallVector<IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope | Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
while (1) {
@@ -1200,12 +1216,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
// Consume the '>'.
- if (Tok.isNot(tok::greater)) {
- Diag(Tok, diag::err_expected_greater);
+ if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
return true;
- }
-
- EndLoc = ConsumeToken();
// Convert the list of protocols identifiers into a list of protocol decls.
Actions.FindProtocolDeclaration(WarnOnDeclarations,
@@ -1231,6 +1243,22 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
return Result;
}
+void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
+ BalancedDelimiterTracker &T,
+ SmallVectorImpl<Decl *> &AllIvarDecls,
+ bool RBraceMissing) {
+ if (!RBraceMissing)
+ T.consumeClose();
+
+ Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
+ Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
+ Actions.ActOnObjCContainerFinishDefinition();
+ // Call ActOnFields() even if we don't have any decls. This is useful
+ // for code rewriting tools that need to be aware of the empty list.
+ Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl,
+ AllIvarDecls,
+ T.getOpenLocation(), T.getCloseLocation(), 0);
+}
/// objc-class-instance-variables:
/// '{' objc-instance-variable-decl-list[opt] '}'
@@ -1263,7 +1291,6 @@ 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)) {
// Each iteration of this loop reads one objc-instance-variable-decl.
@@ -1291,6 +1318,17 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
visibility = Tok.getObjCKeywordID();
ConsumeToken();
continue;
+
+ case tok::objc_end:
+ Diag(Tok, diag::err_objc_unexpected_atend);
+ Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
+ Tok.setKind(tok::at);
+ Tok.setLength(1);
+ PP.EnterToken(Tok);
+ HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
+ T, AllIvarDecls, true);
+ return;
+
default:
Diag(Tok, diag::err_objc_illegal_visibility_spec);
continue;
@@ -1340,16 +1378,8 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
SkipUntil(tok::r_brace, true, true);
}
}
- T.consumeClose();
-
- Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
- Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
- Actions.ActOnObjCContainerFinishDefinition();
- // Call ActOnFields() even if we don't have any decls. This is useful
- // for code rewriting tools that need to be aware of the empty list.
- Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl,
- AllIvarDecls,
- T.getOpenLocation(), T.getCloseLocation(), 0);
+ HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
+ T, AllIvarDecls, false);
return;
}
@@ -1382,6 +1412,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
return DeclGroupPtrTy();
}
+ MaybeSkipAttributes(tok::objc_protocol);
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing protocol name.
return DeclGroupPtrTy();
@@ -1473,6 +1505,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
return DeclGroupPtrTy();
}
+ MaybeSkipAttributes(tok::objc_implementation);
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing class or category name.
return DeclGroupPtrTy();
@@ -1540,7 +1574,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
DeclGroupRef DG = DGP.get();
@@ -2040,7 +2074,7 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
// Otherwise, eat the semicolon.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.take()));
+ return Actions.ActOnExprStmt(Res);
}
ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
@@ -2423,7 +2457,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Parse objc-selector
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
-
+
SmallVector<IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
ExprVector KeyExprs;
@@ -2547,7 +2581,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SkipUntil(tok::r_square);
return ExprError();
}
-
+
SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
unsigned nKeys = KeyIdents.size();
@@ -2593,8 +2627,8 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
AtStrings.push_back(Lit.release());
}
- return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
- AtStrings.size()));
+ return Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
+ AtStrings.size());
}
/// ParseObjCBooleanLiteral -
@@ -2617,7 +2651,7 @@ ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
return Lit;
}
ConsumeToken(); // Consume the literal token.
- return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+ return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
}
/// ParseObjCNumericLiteral -
@@ -2631,7 +2665,7 @@ ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
return Lit;
}
ConsumeToken(); // Consume the literal token.
- return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+ return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
}
/// ParseObjCBoxedExpr -
@@ -2655,8 +2689,8 @@ Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
// a boxed expression from a literal.
SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.take());
- return Owned(Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
- ValueExpr.take()));
+ return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
+ ValueExpr.take());
}
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
@@ -2689,7 +2723,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
}
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
MultiExprArg Args(ElementExprs);
- return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args));
+ return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
}
ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
@@ -2733,7 +2767,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// We have a valid expression. Collect it in a vector so we can
// build the argument list.
ObjCDictionaryElement Element = {
- KeyExpr.get(), ValueExpr.get(), EllipsisLoc, llvm::Optional<unsigned>()
+ KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
};
Elements.push_back(Element);
@@ -2745,9 +2779,8 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
SourceLocation EndLoc = ConsumeBrace();
// Create the ObjCDictionaryLiteral.
- return Owned(Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
- Elements.data(),
- Elements.size()));
+ return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
+ Elements.data(), Elements.size());
}
/// objc-encode-expression:
@@ -2771,9 +2804,8 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
if (Ty.isInvalid())
return ExprError();
- return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc,
- T.getOpenLocation(), Ty.get(),
- T.getCloseLocation()));
+ return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
+ Ty.get(), T.getCloseLocation());
}
/// objc-protocol-expression
@@ -2796,10 +2828,9 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
T.consumeClose();
- return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
- T.getOpenLocation(),
- ProtoIdLoc,
- T.getCloseLocation()));
+ return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
+ T.getOpenLocation(), ProtoIdLoc,
+ T.getCloseLocation());
}
/// objc-selector-expression
@@ -2860,9 +2891,9 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
}
T.consumeClose();
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
- return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
- T.getOpenLocation(),
- T.getCloseLocation()));
+ return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
+ T.getOpenLocation(),
+ T.getCloseLocation());
}
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
@@ -2884,7 +2915,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
Tok.is(tok::colon)) &&
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
new file mode 100644
index 000000000000..507a6b1bcd87
--- /dev/null
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -0,0 +1,118 @@
+//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements parsing of all OpenMP directives and clauses.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// OpenMP declarative directives.
+//===----------------------------------------------------------------------===//
+
+/// \brief Parses OpenMP declarative directive
+/// threadprivate-directive
+/// annot_pragma_openmp threadprivate simple-variable-list
+///
+Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+ assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+
+ SourceLocation Loc = ConsumeToken();
+ SmallVector<DeclarationNameInfo, 5> Identifiers;
+ OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ switch(Kind) {
+ case OMPD_threadprivate:
+ ConsumeToken();
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
+ // The last seen token is annot_pragma_openmp_end - need to check for
+ // extra tokens.
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_threadprivate);
+ SkipUntil(tok::annot_pragma_openmp_end, false, true);
+ }
+ ConsumeToken();
+ return Actions.ActOnOpenMPThreadprivateDirective(Loc,
+ getCurScope(),
+ Identifiers);
+ }
+ break;
+ case OMPD_unknown:
+ Diag(Tok, diag::err_omp_unknown_directive);
+ break;
+ default:
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << getOpenMPDirectiveName(Kind);
+ break;
+ }
+ SkipUntil(tok::annot_pragma_openmp_end, false);
+ return DeclGroupPtrTy();
+}
+
+/// \brief Parses list of simple variables for '#pragma omp threadprivate'
+/// directive
+/// simple-variable-list:
+/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
+///
+bool Parser::ParseOpenMPSimpleVarList(
+ OpenMPDirectiveKind Kind,
+ SmallVectorImpl<DeclarationNameInfo> &IdList) {
+ // Parse '('.
+ bool IsCorrect = true;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPDirectiveName(Kind))) {
+ SkipUntil(tok::annot_pragma_openmp_end, false, true);
+ return false;
+ }
+
+ // Read tokens while ')' or annot_pragma_openmp_end is not found.
+ do {
+ CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+ // Read var name.
+ Token PrevTok = Tok;
+
+ if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+ TemplateKWLoc, Name)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ false, true);
+ }
+ else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ false, true);
+ Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus
+ << SourceRange(PrevTok.getLocation(), PrevTokLocation);
+ } else {
+ IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
+ }
+ // Consume ','.
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ }
+ } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+
+ if (IsCorrect || Tok.is(tok::r_paren)) {
+ IsCorrect = !T.consumeClose() && IsCorrect;
+ }
+
+ return !IsCorrect && IdList.empty();
+}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index a7605f0cf4e0..dc6b3ed4fa98 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "ParsePragma.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
-#include "clang/Lex/Preprocessor.h"
using namespace clang;
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -718,3 +718,47 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
/*OwnsTokens=*/false);
}
+/// \brief Handle '#pragma omp ...' when OpenMP is disabled.
+///
+void
+PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstTok) {
+ if (PP.getDiagnostics().getDiagnosticLevel(diag::warn_pragma_omp_ignored,
+ FirstTok.getLocation()) !=
+ DiagnosticsEngine::Ignored) {
+ PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
+ PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored,
+ diag::MAP_IGNORE,
+ SourceLocation());
+ }
+ PP.DiscardUntilEndOfDirective();
+}
+
+/// \brief Handle '#pragma omp ...' when OpenMP is enabled.
+///
+void
+PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstTok) {
+ SmallVector<Token, 16> Pragma;
+ Token Tok;
+ Tok.startToken();
+ Tok.setKind(tok::annot_pragma_openmp);
+ Tok.setLocation(FirstTok.getLocation());
+
+ while (Tok.isNot(tok::eod)) {
+ Pragma.push_back(Tok);
+ PP.Lex(Tok);
+ }
+ SourceLocation EodLoc = Tok.getLocation();
+ Tok.startToken();
+ Tok.setKind(tok::annot_pragma_openmp_end);
+ Tok.setLocation(EodLoc);
+ Pragma.push_back(Tok);
+
+ Token *Toks = new Token[Pragma.size()];
+ std::copy(Pragma.begin(), Pragma.end(), Toks);
+ PP.EnterTokenStream(Toks, Pragma.size(),
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index b9a2a251fcd4..841a60be7ba1 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -98,7 +98,20 @@ public:
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);
+};
} // end namespace clang
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 588311585020..355f3694bb6c 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -14,13 +14,13 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/PrettyStackTrace.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -84,7 +84,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
ParenBraceBracketBalancer BalancerRAIIObj(*this);
ParsedAttributesWithRange Attrs(AttrFactory);
- MaybeParseCXX0XAttributes(Attrs, 0, /*MightBeObjCMessageSend*/ true);
+ MaybeParseCXX11Attributes(Attrs, 0, /*MightBeObjCMessageSend*/ true);
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts,
OnlyStatement, TrailingElseLoc, Attrs);
@@ -288,6 +288,11 @@ Retry:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
return StmtEmpty();
+
+ case tok::annot_pragma_openmp:
+ SourceLocation DeclStart = Tok.getLocation();
+ DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective();
+ return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation());
}
// If we reached this code, the statement must end in a semicolon.
@@ -319,7 +324,7 @@ StmtResult Parser::ParseExprStatement() {
SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
if (Tok.is(tok::semi))
ConsumeToken();
- return StmtError();
+ return Actions.ActOnExprStmtError();
}
if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
@@ -335,7 +340,7 @@ StmtResult Parser::ParseExprStatement() {
// Otherwise, eat the semicolon.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+ return Actions.ActOnExprStmt(Expr);
}
StmtResult Parser::ParseSEHTryBlock() {
@@ -830,7 +835,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ConsumeToken();
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
+ MaybeParseCXX11Attributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
@@ -856,7 +861,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// Eat the semicolon at the end of stmt and convert the expr into a
// statement.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get()));
+ R = Actions.ActOnExprStmt(Res);
}
}
@@ -867,15 +872,10 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
SourceLocation CloseLoc = Tok.getLocation();
// We broke out of the while loop because we found a '}' or EOF.
- if (Tok.isNot(tok::r_brace)) {
- Diag(Tok, diag::err_expected_rbrace);
- Diag(T.getOpenLocation(), diag::note_matching) << "{";
+ if (!T.consumeClose())
// Recover by creating a compound statement with what we parsed so far,
// instead of dropping everything and returning StmtError();
- } else {
- if (!T.consumeClose())
- CloseLoc = T.getCloseLocation();
- }
+ CloseLoc = T.getCloseLocation();
return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
Stmts, isStmtExpr);
@@ -1047,11 +1047,6 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
IfScope.Exit();
- // If the condition was invalid, discard the if statement. We could recover
- // better by replacing it with a valid expr, but don't do that yet.
- if (CondExp.isInvalid() && !CondVar)
- return StmtError();
-
// If the then or else stmt is invalid and the other is valid (and present),
// make turn the invalid one into a null stmt to avoid dropping the other
// part. If both are invalid, return error.
@@ -1290,7 +1285,7 @@ StmtResult Parser::ParseDoStatement() {
// FIXME: Do not just parse the attribute contents and throw them away
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
ExprResult Cond = ParseExpression();
@@ -1383,7 +1378,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
@@ -1395,9 +1390,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
-
// In C++0x, "for (T NS:a" might not be a typo for ::
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
@@ -1411,7 +1403,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
- Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus0x ?
+ Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
ForRange = true;
@@ -1442,7 +1434,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (ForEach)
FirstPart = Actions.ActOnForEachLValueExpr(Value.get());
else
- FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get()));
+ FirstPart = Actions.ActOnExprStmt(Value);
}
if (Tok.is(tok::semi)) {
@@ -1456,7 +1448,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
return StmtError();
}
Collection = ParseExpression();
- } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::colon) && FirstPart.get()) {
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::colon) && FirstPart.get()) {
// User tried to write the reasonable, but ill-formed, for-range-statement
// for (expr : expr) { ... }
Diag(Tok, diag::err_for_range_expected_decl)
@@ -1510,7 +1502,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// Parse the third part of the for specifier.
if (Tok.isNot(tok::r_paren)) { // for (...;...;)
ExprResult Third = ParseExpression();
- ThirdPart = Actions.MakeFullExpr(Third.take());
+ // 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());
}
}
// Match the ')'.
@@ -1652,7 +1646,7 @@ StmtResult Parser::ParseReturnStatement() {
if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
R = ParseInitializer();
if (R.isUsable())
- Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus0x ?
+ Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_generalized_initializer_lists :
diag::ext_generalized_initializer_lists)
<< R.get()->getSourceRange();
@@ -1682,9 +1676,6 @@ StmtResult Parser::ParseReturnStatement() {
/// ms-asm-line '\n' ms-asm-instruction-block
///
StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
- // MS-style inline assembly is not fully supported, so emit a warning.
- Diag(AsmLoc, diag::warn_unsupported_msasm);
-
SourceManager &SrcMgr = PP.getSourceManager();
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
@@ -1777,21 +1768,6 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
return StmtError();
}
- // If MS-style inline assembly is disabled, then build an empty asm.
- if (!getLangOpts().EmitMicrosoftInlineAsm) {
- Token t;
- t.setKind(tok::string_literal);
- t.setLiteralData("\"/*FIXME: not done*/\"");
- t.clearFlag(Token::NeedsCleaning);
- t.setLength(21);
- ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
- ExprVector Constraints;
- ExprVector Exprs;
- ExprVector Clobbers;
- return Actions.ActOnGCCAsmStmt(AsmLoc, true, true, 0, 0, 0, Constraints,
- Exprs, AsmString.take(), Clobbers, EndLoc);
- }
-
// FIXME: We should be passing source locations for better diagnostics.
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc,
llvm::makeArrayRef(AsmToks), EndLoc);
@@ -1820,7 +1796,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
SourceLocation AsmLoc = ConsumeToken();
- if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) &&
+ if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
!isTypeQualifier()) {
msAsm = true;
return ParseMicrosoftAsmStatement(AsmLoc);
@@ -1834,6 +1810,9 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
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;
@@ -2003,9 +1982,10 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
- if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ if (SkipFunctionBodies && (!Decl || Actions.canSkipFunctionBody(Decl)) &&
+ trySkippingFunctionBody()) {
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, 0);
+ return Actions.ActOnSkippedFunctionBody(Decl);
}
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
@@ -2045,9 +2025,10 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
else
Actions.ActOnDefaultCtorInitializers(Decl);
- if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ if (SkipFunctionBodies && Actions.canSkipFunctionBody(Decl) &&
+ trySkippingFunctionBody()) {
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, 0);
+ return Actions.ActOnSkippedFunctionBody(Decl);
}
SourceLocation LBraceLoc = Tok.getLocation();
@@ -2123,8 +2104,8 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope |
- (FnTry ? Scope::FnTryScope : Scope::TryScope)));
+ Scope::DeclScope | Scope::TryScope |
+ (FnTry ? Scope::FnTryCatchScope : 0)));
if (TryBlock.isInvalid())
return TryBlock;
@@ -2154,7 +2135,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
else {
StmtVector Handlers;
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
if (Tok.isNot(tok::kw_catch))
@@ -2175,14 +2156,13 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
///
-/// handler:
-/// 'catch' '(' exception-declaration ')' compound-statement
+/// handler:
+/// 'catch' '(' exception-declaration ')' compound-statement
///
-/// exception-declaration:
-/// type-specifier-seq declarator
-/// type-specifier-seq abstract-declarator
-/// type-specifier-seq
-/// '...'
+/// exception-declaration:
+/// attribute-specifier-seq[opt] type-specifier-seq declarator
+/// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
+/// '...'
///
StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
@@ -2197,15 +2177,21 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
// The name in a catch exception-declaration is local to the handler and
// shall not be redeclared in the outermost block of the handler.
ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope |
- (FnCatch ? Scope::FnCatchScope : Scope::CatchScope));
+ (FnCatch ? Scope::FnTryCatchScope : 0));
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
Decl *ExceptionDecl = 0;
if (Tok.isNot(tok::ellipsis)) {
+ ParsedAttributesWithRange Attributes(AttrFactory);
+ MaybeParseCXX11Attributes(Attributes);
+
DeclSpec DS(AttrFactory);
+ DS.takeAttributesFrom(Attributes);
+
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
+
Declarator ExDecl(DS, Declarator::CXXCatchContext);
ParseDeclarator(ExDecl);
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 2e0411e8a81c..f14666922b95 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
-#include "RAIIObjectsForParser.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTConsumer.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -172,16 +172,6 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
/// \brief Parse a single declaration that declares a template,
/// template specialization, or explicit instantiation of a template.
///
-/// \param TemplateParams if non-NULL, the template parameter lists
-/// that preceded this declaration. In this case, the declaration is a
-/// template declaration, out-of-line definition of a template, or an
-/// explicit template specialization. When NULL, the declaration is an
-/// explicit template instantiation.
-///
-/// \param TemplateLoc when TemplateParams is NULL, the location of
-/// the 'template' keyword that indicates that we have an explicit
-/// template instantiation.
-///
/// \param DeclEnd will receive the source location of the last token
/// within this declaration.
///
@@ -208,7 +198,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
}
ParsedAttributesWithRange prefixAttrs(AttrFactory);
- MaybeParseCXX0XAttributes(prefixAttrs);
+ MaybeParseCXX11Attributes(prefixAttrs);
if (Tok.is(tok::kw_using))
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
@@ -218,22 +208,27 @@ Parser::ParseSingleDeclarationAfterTemplate(
// the template parameters.
ParsingDeclSpec DS(*this, &DiagsFromTParams);
- // Move the attributes from the prefix into the DS.
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- ProhibitAttributes(prefixAttrs);
- else
- DS.takeAttributesFrom(prefixAttrs);
-
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
+ ProhibitAttributes(prefixAttrs);
DeclEnd = ConsumeToken();
- Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+ Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
+ getCurScope(), AS, DS,
+ TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams
+ : MultiTemplateParamsArg(),
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation);
DS.complete(Decl);
return Decl;
}
+ // Move the attributes from the prefix into the DS.
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ ProhibitAttributes(prefixAttrs);
+ else
+ DS.takeAttributesFrom(prefixAttrs);
+
// Parse the declarator.
ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context);
ParseDeclarator(DeclaratorInfo);
@@ -250,27 +245,6 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (DeclaratorInfo.isFunctionDeclarator())
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
- // If we have a declaration or declarator list, handle it.
- if (isDeclarationAfterDeclarator()) {
- // Parse this declaration.
- Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
- TemplateInfo);
-
- if (Tok.is(tok::comma)) {
- Diag(Tok, diag::err_multiple_template_declarators)
- << (int)TemplateInfo.Kind;
- SkipUntil(tok::semi, true, false);
- return ThisDecl;
- }
-
- // Eat the semi colon after the declaration.
- ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
- if (LateParsedAttrs.size() > 0)
- ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
- DeclaratorInfo.complete(ThisDecl);
- return ThisDecl;
- }
-
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -285,12 +259,23 @@ Parser::ParseSingleDeclarationAfterTemplate(
&LateParsedAttrs);
}
- if (DeclaratorInfo.isFunctionDeclarator())
- Diag(Tok, diag::err_expected_fn_body);
- else
- Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
- SkipUntil(tok::semi);
- return 0;
+ // Parse this declaration.
+ Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
+ TemplateInfo);
+
+ if (Tok.is(tok::comma)) {
+ Diag(Tok, diag::err_multiple_template_declarators)
+ << (int)TemplateInfo.Kind;
+ SkipUntil(tok::semi, true, false);
+ return ThisDecl;
+ }
+
+ // Eat the semi colon after the declaration.
+ ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
+ if (LateParsedAttrs.size() > 0)
+ ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
+ DeclaratorInfo.complete(ThisDecl);
+ return ThisDecl;
}
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
@@ -357,7 +342,7 @@ Parser::ParseTemplateParameterList(unsigned Depth,
SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
}
- // Did we find a comma or the end of the template parmeter list?
+ // Did we find a comma or the end of the template parameter list?
if (Tok.is(tok::comma)) {
ConsumeToken();
} else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
@@ -491,7 +476,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
@@ -578,7 +563,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
@@ -675,52 +660,17 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
DefaultArg.take());
}
-/// \brief Parses a template-id that after the template name has
-/// already been parsed.
-///
-/// This routine takes care of parsing the enclosed template argument
-/// list ('<' template-parameter-list [opt] '>') and placing the
-/// results into a form that can be transferred to semantic analysis.
+/// \brief Parses a '>' at the end of a template list.
///
-/// \param Template the template declaration produced by isTemplateName
-///
-/// \param TemplateNameLoc the source location of the template name
+/// If this function encounters '>>', '>>>', '>=', or '>>=', it tries
+/// to determine if these tokens were supposed to be a '>' followed by
+/// '>', '>>', '>=', or '>='. It emits an appropriate diagnostic if necessary.
///
-/// \param SS if non-NULL, the nested-name-specifier preceding the
-/// template name.
+/// \param RAngleLoc the location of the consumed '>'.
///
-/// \param ConsumeLastToken if true, then we will consume the last
-/// token that forms the template-id. Otherwise, we will leave the
-/// last token in the stream (e.g., so that it can be replaced with an
-/// annotation token).
-bool
-Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
- const CXXScopeSpec &SS,
- bool ConsumeLastToken,
- SourceLocation &LAngleLoc,
- TemplateArgList &TemplateArgs,
- SourceLocation &RAngleLoc) {
- assert(Tok.is(tok::less) && "Must have already parsed the template-name");
-
- // Consume the '<'.
- LAngleLoc = ConsumeToken();
-
- // Parse the optional template-argument-list.
- bool Invalid = false;
- {
- GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
- Invalid = ParseTemplateArgumentList(TemplateArgs);
-
- if (Invalid) {
- // Try to find the closing '>'.
- SkipUntil(tok::greater, true, !ConsumeLastToken);
-
- return true;
- }
- }
-
+/// \param ConsumeLastToken if true, the '>' is not consumed.
+bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
+ bool ConsumeLastToken) {
// What will be left once we've consumed the '>'.
tok::TokenKind RemainingToken;
const char *ReplacementStr = "> >";
@@ -788,7 +738,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater))
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater))
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
else if (Tok.is(tok::greaterequal))
DiagId = diag::err_right_angle_bracket_equal_needs_space;
@@ -819,10 +769,59 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
Tok.setLength(1);
Tok.setLocation(RAngleLoc);
}
-
return false;
}
+
+/// \brief Parses a template-id that after the template name has
+/// already been parsed.
+///
+/// This routine takes care of parsing the enclosed template argument
+/// list ('<' template-parameter-list [opt] '>') and placing the
+/// results into a form that can be transferred to semantic analysis.
+///
+/// \param Template the template declaration produced by isTemplateName
+///
+/// \param TemplateNameLoc the source location of the template name
+///
+/// \param SS if non-NULL, the nested-name-specifier preceding the
+/// template name.
+///
+/// \param ConsumeLastToken if true, then we will consume the last
+/// token that forms the template-id. Otherwise, we will leave the
+/// last token in the stream (e.g., so that it can be replaced with an
+/// annotation token).
+bool
+Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec &SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ SourceLocation &RAngleLoc) {
+ assert(Tok.is(tok::less) && "Must have already parsed the template-name");
+
+ // Consume the '<'.
+ LAngleLoc = ConsumeToken();
+
+ // Parse the optional template-argument-list.
+ bool Invalid = false;
+ {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+ if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
+ Invalid = ParseTemplateArgumentList(TemplateArgs);
+
+ if (Invalid) {
+ // Try to find the closing '>'.
+ SkipUntil(tok::greater, true, !ConsumeLastToken);
+
+ return true;
+ }
+ }
+
+ return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken);
+}
+
/// \brief Replace the tokens that form a simple-template-id with an
/// annotation token containing the complete template-id.
///
@@ -839,7 +838,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
/// \param Template the declaration of the template named by the first
/// token (an identifier), as returned from \c Action::isTemplateName().
///
-/// \param TemplateNameKind the kind of template that \p Template
+/// \param TNK the kind of template that \p Template
/// refers to, as returned from \c Action::isTemplateName().
///
/// \param SS if non-NULL, the nested-name-specifier that precedes
@@ -1201,7 +1200,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
/// explicit-instantiation:
/// 'extern' [opt] 'template' declaration
///
-/// Note that the 'extern' is a GNU extension and C++0x feature.
+/// Note that the 'extern' is a GNU extension and C++11 feature.
Decl *Parser::ParseExplicitInstantiation(unsigned Context,
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
@@ -1306,7 +1305,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
&& "Inline method not starting with '{', ':' or 'try'");
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 40c4eee1994b..5e0ef2b83f67 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -184,6 +184,9 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
return TPResult::Ambiguous();
}
+/// Tentatively parse an init-declarator-list in order to disambiguate it from
+/// an expression.
+///
/// init-declarator-list:
/// init-declarator
/// init-declarator-list ',' init-declarator
@@ -192,14 +195,21 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
/// declarator initializer[opt]
/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
///
-/// initializer:
-/// '=' initializer-clause
-/// '(' expression-list ')'
+/// initializer:
+/// brace-or-equal-initializer
+/// '(' expression-list ')'
+///
+/// brace-or-equal-initializer:
+/// '=' initializer-clause
+/// [C++11] braced-init-list
+///
+/// initializer-clause:
+/// assignment-expression
+/// braced-init-list
///
-/// initializer-clause:
-/// assignment-expression
-/// '{' initializer-list ','[opt] '}'
-/// '{' '}'
+/// braced-init-list:
+/// '{' initializer-list ','[opt] '}'
+/// '{' '}'
///
Parser::TPResult Parser::TryParseInitDeclaratorList() {
while (1) {
@@ -218,6 +228,10 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
ConsumeParen();
if (!SkipUntil(tok::r_paren))
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();
} 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.
@@ -295,7 +309,7 @@ bool Parser::isCXXConditionDeclaration() {
if (Tok.is(tok::equal) ||
Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
TPR = TPResult::True();
- else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))
+ else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))
TPR = TPResult::True();
else
TPR = TPResult::False();
@@ -379,7 +393,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// ',', this is a type-id. Otherwise, it's an expression.
} else if (Context == TypeIdAsTemplateArgument &&
(Tok.is(tok::greater) || Tok.is(tok::comma) ||
- (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
+ (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) {
TPR = TPResult::True();
isAmbiguous = true;
@@ -837,6 +851,15 @@ 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();
default:
@@ -976,6 +999,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// to types and identifiers, in order to try to recover from errors.
CorrectionCandidateCallback TypoCorrection;
TypoCorrection.WantRemainingKeywords = false;
+ TypoCorrection.WantTypeSpecifiers = Next.isNot(tok::arrow);
switch (TryAnnotateName(false /* no nested name specifier */,
&TypoCorrection)) {
case ANK_Error:
@@ -1056,6 +1080,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// Modules
case tok::kw___module_private__:
+
+ // Debugger support
+ case tok::kw___unknown_anytype:
// type-specifier:
// simple-type-specifier
@@ -1212,7 +1239,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (isFollowedByParen)
return TPResult::Ambiguous();
- if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ if (getLangOpts().CPlusPlus11 && isFollowedByBrace)
return BracedCastResult;
return TPResult::True();
@@ -1244,7 +1271,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// enum E : int { a = 4 }; // enum
// enum E : int { 4 }; // bit-field
// };
- if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace))
+ if (getLangOpts().CPlusPlus11 && NextToken().is(tok::l_brace))
return BracedCastResult;
if (isStartOfObjCClassMessageMissingOpenBracket())
@@ -1271,7 +1298,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (isFollowedByParen)
return TPResult::Ambiguous();
- if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ if (getLangOpts().CPlusPlus11 && isFollowedByBrace)
return BracedCastResult;
return TPResult::True();
@@ -1386,7 +1413,7 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
if (Next.is(tok::amp) || Next.is(tok::ampamp) ||
Next.is(tok::kw_const) || Next.is(tok::kw_volatile) ||
Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) ||
- Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) ||
+ Next.is(tok::l_square) || isCXX11VirtSpecifier(Next) ||
Next.is(tok::l_brace) || Next.is(tok::kw_try) ||
Next.is(tok::equal) || Next.is(tok::arrow))
// The next token cannot appear after a constructor-style initializer,
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index f4cdd619cef4..1ebba3e67a82 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -12,15 +12,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "ParsePragma.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
#include "llvm/Support/raw_ostream.h"
-#include "RAIIObjectsForParser.h"
-#include "ParsePragma.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTConsumer.h"
using namespace clang;
@@ -96,6 +96,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
}
+ if (getLangOpts().OpenMP)
+ OpenMPHandler.reset(new PragmaOpenMPHandler());
+ else
+ OpenMPHandler.reset(new PragmaNoOpenMPHandler());
+ PP.AddPragmaHandler(OpenMPHandler.get());
CommentSemaHandler.reset(new ActionCommentHandler(actions));
PP.addCommentHandler(CommentSemaHandler.get());
@@ -103,29 +108,6 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.setCodeCompletionHandler(*this);
}
-/// If a crash happens while the parser is active, print out a line indicating
-/// what the current token is.
-void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
- const Token &Tok = P.getCurToken();
- if (Tok.is(tok::eof)) {
- OS << "<eof> parser at end of file\n";
- return;
- }
-
- if (Tok.getLocation().isInvalid()) {
- OS << "<unknown> parser at unknown location\n";
- return;
- }
-
- const Preprocessor &PP = P.getPreprocessor();
- Tok.getLocation().print(OS, PP.getSourceManager());
- if (Tok.isAnnotation())
- OS << ": at annotation token \n";
- else
- OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n";
-}
-
-
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
return Diags.Report(Loc, DiagID);
}
@@ -241,7 +223,7 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
// C++11 allows extra semicolons at namespace scope, but not in any of the
// other contexts.
if (Kind == OutsideFunction && getLangOpts().CPlusPlus) {
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
Diag(StartLoc, diag::warn_cxx98_compat_top_level_semi)
<< FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
else
@@ -451,6 +433,8 @@ Parser::~Parser() {
OpenCLExtensionHandler.reset();
PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
}
+ PP.RemovePragmaHandler(OpenMPHandler.get());
+ OpenMPHandler.reset();
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
FPContractHandler.reset();
@@ -577,34 +561,18 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
}
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
Result = ParseExternalDeclaration(attrs);
return false;
}
-/// ParseTranslationUnit:
-/// translation-unit: [C99 6.9]
-/// external-declaration
-/// translation-unit external-declaration
-void Parser::ParseTranslationUnit() {
- Initialize();
-
- DeclGroupPtrTy Res;
- while (!ParseTopLevelDecl(Res))
- /*parse them all*/;
-
- ExitScope();
- assert(getCurScope() == 0 && "Scope imbalance!");
-}
-
/// ParseExternalDeclaration:
///
/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
/// function-definition
/// declaration
-/// [C++0x] empty-declaration
/// [GNU] asm-definition
/// [GNU] __extension__ external-declaration
/// [OBJC] objc-class-definition
@@ -616,8 +584,10 @@ void Parser::ParseTranslationUnit() {
/// [C++] linkage-specification
/// [GNU] asm-definition:
/// simple-asm-expr ';'
+/// [C++11] empty-declaration
+/// [C++11] attribute-declaration
///
-/// [C++0x] empty-declaration:
+/// [C++11] empty-declaration:
/// ';'
///
/// [C++0x/GNU] 'extern' 'template' declaration
@@ -661,10 +631,16 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
+ case tok::annot_pragma_openmp:
+ ParseOpenMPDeclarativeDirective();
+ return DeclGroupPtrTy();
case tok::semi:
+ // Either a C++11 empty-declaration or attribute-declaration.
+ SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
+ attrs.getList(),
+ Tok.getLocation());
ConsumeExtraSemi(OutsideFunction);
- // TODO: Invoke action for top-level semicolon.
- return DeclGroupPtrTy();
+ break;
case tok::r_brace:
Diag(Tok, diag::err_extraneous_closing_brace);
ConsumeBrace();
@@ -764,7 +740,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// Extern templates
SourceLocation ExternLoc = ConsumeToken();
SourceLocation TemplateLoc = ConsumeToken();
- Diag(ExternLoc, getLangOpts().CPlusPlus0x ?
+ Diag(ExternLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_extern_template :
diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
@@ -783,11 +759,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
- if (DS) {
- return ParseDeclarationOrFunctionDefinition(attrs, DS);
- } else {
- return ParseDeclarationOrFunctionDefinition(attrs);
- }
+ return ParseDeclarationOrFunctionDefinition(attrs, DS);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -986,7 +958,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (Tok.isNot(tok::equal)) {
AttributeList *DtorAttrs = D.getAttributes();
while (DtorAttrs) {
- if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName())) {
+ if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName()) &&
+ !DtorAttrs->isCXX11Attribute()) {
Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition)
<< DtorAttrs->getName()->getName();
}
@@ -1076,7 +1049,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_deleted_function :
diag::ext_deleted_function);
@@ -1084,7 +1057,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
Actions.SetDeclDeleted(Res, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_defaulted_function :
diag::ext_defaulted_function);
@@ -1138,7 +1111,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope | Scope::DeclScope);
// Read all the argument declarations.
while (isDeclarationSpecifier()) {
@@ -1263,7 +1237,8 @@ Parser::ExprResult Parser::ParseAsmStringLiteral() {
return ExprError();
}
default:
- Diag(Tok, diag::err_expected_string_literal);
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << "'asm'";
return ExprError();
}
@@ -1857,7 +1832,7 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
// Parse the declarations.
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
if (Result && !getCurScope()->getParent())
@@ -1867,11 +1842,11 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
}
Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
- assert(Tok.isObjCAtKeyword(tok::objc___experimental_modules_import) &&
+ assert(Tok.isObjCAtKeyword(tok::objc_import) &&
"Improper start to module import");
SourceLocation ImportLoc = ConsumeToken();
- llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
// Parse the module path.
do {
@@ -1909,7 +1884,9 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
}
bool BalancedDelimiterTracker::diagnoseOverflow() {
- P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
+ 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;
}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 060fd206cd71..213950a6db92 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -407,7 +407,7 @@ namespace clang {
if (!P.Tok.is(Kind))
return true;
- if (getDepth() < MaxDepth) {
+ if (getDepth() < P.getLangOpts().BracketDepth) {
LOpen = (P.*Consumer)();
return false;
}
diff --git a/lib/Rewrite/Core/DeltaTree.cpp b/lib/Rewrite/Core/DeltaTree.cpp
index 46922772c5a2..7a7f15b7d336 100644
--- a/lib/Rewrite/Core/DeltaTree.cpp
+++ b/lib/Rewrite/Core/DeltaTree.cpp
@@ -13,8 +13,8 @@
#include "clang/Rewrite/Core/DeltaTree.h"
#include "clang/Basic/LLVM.h"
-#include <cstring>
#include <cstdio>
+#include <cstring>
using namespace clang;
/// The DeltaTree class is a multiway search tree (BTree) structure with some
diff --git a/lib/Rewrite/Core/HTMLRewrite.cpp b/lib/Rewrite/Core/HTMLRewrite.cpp
index 0e8e4fec9f4a..2d279f1ee4a1 100644
--- a/lib/Rewrite/Core/HTMLRewrite.cpp
+++ b/lib/Rewrite/Core/HTMLRewrite.cpp
@@ -12,14 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
-#include "clang/Lex/TokenConcatenation.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
+#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"
diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp
index 4df967f39bc0..c1c6595d1622 100644
--- a/lib/Rewrite/Core/Rewriter.cpp
+++ b/lib/Rewrite/Core/Rewriter.cpp
@@ -13,14 +13,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Stmt.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
raw_ostream &RewriteBuffer::write(raw_ostream &os) const {
@@ -416,6 +418,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
return false;
}
+namespace {
// A wrapper for a file stream that atomically overwrites the target.
//
// Creates a file output stream for a temporary file in the constructor,
@@ -461,7 +464,7 @@ public:
}
bool ok() { return FileStream; }
- llvm::raw_ostream &getStream() { return *FileStream; }
+ raw_ostream &getStream() { return *FileStream; }
private:
DiagnosticsEngine &Diagnostics;
@@ -470,6 +473,7 @@ private:
OwningPtr<llvm::raw_fd_ostream> FileStream;
bool &AllWritten;
};
+} // end anonymous namespace
bool Rewriter::overwriteChangedFiles() {
bool AllWritten = true;
diff --git a/lib/Rewrite/Core/TokenRewriter.cpp b/lib/Rewrite/Core/TokenRewriter.cpp
index 940ece2f9e03..494defdedaa9 100644
--- a/lib/Rewrite/Core/TokenRewriter.cpp
+++ b/lib/Rewrite/Core/TokenRewriter.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Core/TokenRewriter.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/ScratchBuffer.h"
-#include "clang/Basic/SourceManager.h"
using namespace clang;
TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM,
diff --git a/lib/Rewrite/Frontend/CMakeLists.txt b/lib/Rewrite/Frontend/CMakeLists.txt
index 9017e479ab77..903a3ef8d50d 100644
--- a/lib/Rewrite/Frontend/CMakeLists.txt
+++ b/lib/Rewrite/Frontend/CMakeLists.txt
@@ -25,4 +25,5 @@ target_link_libraries(clangRewriteFrontend
clangAST
clangParse
clangFrontend
+ clangRewriteCore
)
diff --git a/lib/Rewrite/Frontend/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp
index 43a1ab1ac100..a3bbdcf6ebda 100644
--- a/lib/Rewrite/Frontend/FixItRewriter.cpp
+++ b/lib/Rewrite/Frontend/FixItRewriter.cpp
@@ -14,15 +14,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/FixItRewriter.h"
-#include "clang/Edit/Commit.h"
-#include "clang/Edit/EditsReceiver.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Path.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
diff --git a/lib/Rewrite/Frontend/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp
index 7d29b6d4219d..9935aeb63e58 100644
--- a/lib/Rewrite/Frontend/FrontendActions.cpp
+++ b/lib/Rewrite/Frontend/FrontendActions.cpp
@@ -9,20 +9,20 @@
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Parse/Parser.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
#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/raw_ostream.h"
-#include "llvm/Support/Path.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -158,7 +158,9 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
if (CI.getLangOpts().ObjCRuntime.isNonFragile())
return CreateModernObjCRewriter(InFile, OS,
CI.getDiagnostics(), CI.getLangOpts(),
- CI.getDiagnosticOpts().NoRewriteMacros);
+ CI.getDiagnosticOpts().NoRewriteMacros,
+ (CI.getCodeGenOpts().getDebugInfo() !=
+ CodeGenOptions::NoDebugInfo));
return CreateObjCRewriter(InFile, OS,
CI.getDiagnostics(), CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros);
diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp
index 9d1bec957d6d..d95fb073b1e3 100644
--- a/lib/Rewrite/Frontend/InclusionRewriter.cpp
+++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/Rewriters.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -39,7 +39,7 @@ class InclusionRewriter : public PPCallbacks {
bool ShowLineMarkers; ///< Show #line markers.
bool UseLineDirective; ///< Use of line directives or line markers.
typedef std::map<unsigned, FileChange> FileChangeMap;
- FileChangeMap FileChanges; /// Tracks which files were included where.
+ FileChangeMap FileChanges; ///< Tracks which files were included where.
/// Used transitively for building up the FileChanges mapping over the
/// various \c PPCallbacks callbacks.
FileChangeMap::iterator LastInsertedFileChange;
diff --git a/lib/Rewrite/Frontend/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp
index f399dd5d7ce9..3c1d2e11903d 100644
--- a/lib/Rewrite/Frontend/RewriteMacros.cpp
+++ b/lib/Rewrite/Frontend/RewriteMacros.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/Rewriters.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Path.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>
using namespace clang;
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index 4b56b3720a3f..0e59b113c965 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -12,20 +12,23 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/ASTConsumers.h"
-#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#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 "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/DenseSet.h"
using namespace clang;
using llvm::utostr;
@@ -115,7 +118,7 @@ namespace {
SmallVector<ObjCInterfaceDecl*, 8> DefinedNonLazyClasses;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
- llvm::SmallVector<ObjCCategoryDecl*, 8> DefinedNonLazyCategories;
+ SmallVector<ObjCCategoryDecl *, 8> DefinedNonLazyCategories;
SmallVector<Stmt *, 32> Stmts;
SmallVector<int, 8> ObjCBcLabelNo;
@@ -131,6 +134,7 @@ namespace {
SmallVector<DeclRefExpr *, 32> BlockDeclRefs;
+
// Block related declarations.
SmallVector<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
@@ -144,6 +148,14 @@ namespace {
llvm::DenseMap<ObjCInterfaceDecl *,
llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
+ // ivar bitfield grouping containers
+ llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups;
+ llvm::DenseMap<const ObjCIvarDecl* , unsigned> IvarGroupNumber;
+ // This container maps an <class, group number for ivar> tuple to the type
+ // of the struct where the bitfield belongs.
+ llvm::DenseMap<std::pair<const ObjCInterfaceDecl*, unsigned>, QualType> GroupRecordType;
+ SmallVector<FunctionDecl*, 32> FunctionDefinitionsSeen;
+
// This maps an original source AST to it's rewritten form. This allows
// us to avoid rewriting the same node twice (which is very uncommon).
// This is needed to support some of the exotic property rewriting.
@@ -152,6 +164,7 @@ namespace {
// Needed for header files being rewritten
bool IsHeader;
bool SilenceRewriteMacroWarning;
+ bool GenerateLineInfo;
bool objc_impl_method;
bool DisableReplaceStmt;
@@ -193,6 +206,18 @@ namespace {
}
}
+ if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I)) {
+ // Under modern abi, we cannot translate body of the function
+ // yet until all class extensions and its implementation is seen.
+ // This is because they may introduce new bitfields which must go
+ // into their grouping struct.
+ if (FDecl->isThisDeclarationADefinition() &&
+ // Not c functions defined inside an objc container.
+ !FDecl->isTopLevelDeclInObjCContainer()) {
+ FunctionDefinitionsSeen.push_back(FDecl);
+ break;
+ }
+ }
HandleTopLevelSingleDecl(*I);
}
return true;
@@ -201,7 +226,7 @@ namespace {
void HandleDeclInMainFile(Decl *D);
RewriteModernObjC(std::string inFile, raw_ostream *OS,
DiagnosticsEngine &D, const LangOptions &LOpts,
- bool silenceMacroWarn);
+ bool silenceMacroWarn, bool LineInfo);
~RewriteModernObjC() {}
@@ -282,7 +307,7 @@ namespace {
void ConvertSourceLocationToLineDirective(SourceLocation Loc,
std::string &LineString);
void RewriteForwardClassDecl(DeclGroupRef D);
- void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardClassDecl(const SmallVector<Decl *, 8> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
@@ -300,7 +325,7 @@ namespace {
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(DeclGroupRef D);
- void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -338,6 +363,20 @@ namespace {
void RewriteImplicitCastObjCExpr(CastExpr *IE);
void RewriteLinkageSpec(LinkageSpecDecl *LSD);
+ // Computes ivar bitfield group no.
+ unsigned ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV);
+ // Names field decl. for ivar bitfield group.
+ void ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV, std::string &Result);
+ // Names struct type for ivar bitfield group.
+ void ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV, std::string &Result);
+ // Names symbol for ivar bitfield group field offset.
+ void ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV, std::string &Result);
+ // Given an ivar bitfield, it builds (or finds) its group record type.
+ QualType GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV);
+ QualType SynthesizeBitfieldGroupStructType(
+ ObjCIvarDecl *IV,
+ SmallVectorImpl<ObjCIvarDecl *> &IVars);
+
// Block rewriting.
void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
@@ -533,14 +572,13 @@ namespace {
}
QualType getSimpleFunctionType(QualType result,
- const QualType *args,
- unsigned numArgs,
+ ArrayRef<QualType> args,
bool variadic = false) {
if (result == Context->getObjCInstanceType())
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
- return Context->getFunctionType(result, args, numArgs, fpi);
+ return Context->getFunctionType(result, args, fpi);
}
// Helper function: create a CStyleCastExpr with trivial type source info.
@@ -596,9 +634,10 @@ static bool IsHeaderFile(const std::string &Filename) {
RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS,
DiagnosticsEngine &D, const LangOptions &LOpts,
- bool silenceMacroWarn)
+ bool silenceMacroWarn,
+ bool LineInfo)
: Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
- SilenceRewriteMacroWarning(silenceMacroWarn) {
+ SilenceRewriteMacroWarning(silenceMacroWarn), GenerateLineInfo(LineInfo) {
IsHeader = IsHeaderFile(inFile);
RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
"rewriting sub-expression within a macro (may not be correct)");
@@ -617,8 +656,10 @@ ASTConsumer *clang::CreateModernObjCRewriter(const std::string& InFile,
raw_ostream* OS,
DiagnosticsEngine &Diags,
const LangOptions &LOpts,
- bool SilenceRewriteMacroWarning) {
- return new RewriteModernObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+ bool SilenceRewriteMacroWarning,
+ bool LineInfo) {
+ return new RewriteModernObjC(InFile, OS, Diags, LOpts,
+ SilenceRewriteMacroWarning, LineInfo);
}
void RewriteModernObjC::InitializeCommon(ASTContext &context) {
@@ -798,11 +839,16 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
// Build name of symbol holding ivar offset.
std::string IvarOffsetName;
- WriteInternalIvarName(ClassDecl, D, IvarOffsetName);
+ if (D->isBitField())
+ ObjCIvarBitfieldGroupOffset(D, IvarOffsetName);
+ else
+ WriteInternalIvarName(ClassDecl, D, IvarOffsetName);
std::string S = "(*(";
QualType IvarT = D->getType();
+ if (D->isBitField())
+ IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
@@ -850,6 +896,10 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
S += "((char *)self + ";
S += IvarOffsetName;
S += "))";
+ if (D->isBitField()) {
+ S += ".";
+ S += D->getNameAsString();
+ }
ReferencedIvars[const_cast<ObjCInterfaceDecl *>(ClassDecl)].insert(D);
return S;
}
@@ -889,9 +939,8 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// Generate the 'getter' function.
ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCIvarDecl *OID = PID->getPropertyIvarDecl();
+ assert(IMD && OID && "Synthesized ivars must be attached to @implementation");
- if (!OID)
- return;
unsigned Attributes = PD->getPropertyAttributes();
if (mustSynthesizeSetterGetterMethod(IMD, PD, true /*getter*/)) {
bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
@@ -993,7 +1042,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl,
std::string &typedefString) {
- typedefString += "#ifndef _REWRITER_typedef_";
+ typedefString += "\n#ifndef _REWRITER_typedef_";
typedefString += ForwardDecl->getNameAsString();
typedefString += "\n";
typedefString += "#define _REWRITER_typedef_";
@@ -1026,7 +1075,7 @@ void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) {
// as a comment.
typedefString += "// @class ";
typedefString += ForwardDecl->getNameAsString();
- typedefString += ";\n";
+ typedefString += ";";
}
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
@@ -1035,14 +1084,14 @@ void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) {
}
void RewriteModernObjC::RewriteForwardClassDecl(
- const llvm::SmallVector<Decl*, 8> &D) {
+ const SmallVector<Decl *, 8> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
if (i == 0) {
typedefString += "// @class ";
typedefString += ForwardDecl->getNameAsString();
- typedefString += ";\n";
+ typedefString += ";";
}
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
@@ -1100,7 +1149,7 @@ void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
// Lastly, comment out the @end.
ReplaceText(CatDecl->getAtEndRange().getBegin(),
- strlen("@end"), "/* @end */");
+ strlen("@end"), "/* @end */\n");
}
void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -1125,7 +1174,7 @@ void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
- ReplaceText(LocEnd, strlen("@end"), "/* @end */");
+ ReplaceText(LocEnd, strlen("@end"), "/* @end */\n");
// Must comment out @optional/@required
const char *startBuf = SM->getCharacterData(LocStart);
@@ -1153,7 +1202,7 @@ void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
}
void
-RewriteModernObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+RewriteModernObjC::RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG) {
SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
@@ -1393,7 +1442,7 @@ void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
// Lastly, comment out the @end.
ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),
- "/* @end */");
+ "/* @end */\n");
}
}
@@ -1608,7 +1657,7 @@ Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) {
void RewriteModernObjC::ConvertSourceLocationToLineDirective(
SourceLocation Loc,
std::string &LineString) {
- if (Loc.isFileID()) {
+ if (Loc.isFileID() && GenerateLineInfo) {
LineString += "\n#line ";
PresumedLoc PLoc = SM->getPresumedLoc(Loc);
LineString += utostr(PLoc.getLine());
@@ -2042,7 +2091,9 @@ Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
assert((*wBuf == 'w') && "@throw: can't find 'w'");
ReplaceText(startLoc, wBuf-startBuf+1, buf);
- const char *semiBuf = strchr(startBuf, ';');
+ SourceLocation endLoc = S->getLocEnd();
+ const char *endBuf = SM->getCharacterData(endLoc);
+ const char *semiBuf = strchr(endBuf, ';');
assert((*semiBuf == ';') && "@throw: can't find ';'");
SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);
if (S->getThrowExpr())
@@ -2208,6 +2259,10 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
Loc = FD->getLocation();
Type = FD->getType();
}
+ else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(Dcl)) {
+ Loc = TD->getLocation();
+ Type = TD->getUnderlyingType();
+ }
else
return;
@@ -2305,13 +2360,12 @@ void RewriteModernObjC::SynthSelGetUidFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
- getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ getSimpleFunctionType(Context->getObjCSelType(), ArgTys);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- SelGetUidIdent, getFuncType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ SelGetUidIdent, getFuncType, 0,
+ SC_Extern);
}
void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2404,13 +2458,12 @@ void RewriteModernObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ 0, SC_Extern);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2424,14 +2477,12 @@ void RewriteModernObjC::SynthMsgSendFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void);
@@ -2440,14 +2491,12 @@ void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() {
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(Context->VoidTy);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], 1,
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2461,14 +2510,12 @@ void RewriteModernObjC::SynthMsgSendStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2479,14 +2526,13 @@ void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() {
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(Context->VoidTy);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], 1,
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ msgSendIdent,
+ msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
@@ -2500,14 +2546,12 @@ void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthGetClassFunctionDecl - Class objc_getClass(const char *name);
@@ -2516,13 +2560,12 @@ void RewriteModernObjC::SynthGetClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
+ SC_Extern);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2532,15 +2575,13 @@ void RewriteModernObjC::SynthGetSuperClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
getSuperClassIdent,
getClassType, 0,
- SC_Extern,
- SC_None,
- false);
+ SC_Extern);
}
// SynthGetMetaClassFunctionDecl - Class objc_getMetaClass(const char *name);
@@ -2549,13 +2590,12 @@ void RewriteModernObjC::SynthGetMetaClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType,
+ 0, SC_Extern);
}
Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
@@ -2568,7 +2608,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
for (i=0; i < tmpName.length(); i++) {
char c = tmpName.at(i);
// replace any non alphanumeric characters with '_'.
- if (!isalpha(c) && (c < '0' || c > '9'))
+ if (!isAlphanumeric(c))
tmpName[i] = '_';
}
S += tmpName;
@@ -2588,7 +2628,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
- strType, 0, SC_Static, SC_None);
+ strType, 0, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2697,8 +2737,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- BoxingMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, BoxingMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -2731,7 +2770,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Build the expression: __NSContainer_literal(int, ...).arr
QualType IntQT = Context->IntTy;
QualType NSArrayFType =
- getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ getSimpleFunctionType(Context->VoidTy, IntQT, true);
std::string NSArrayFName("__NSContainer_literal");
FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName);
DeclRefExpr *NSArrayDRE =
@@ -2835,8 +2874,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- ArrayMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, ArrayMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -2869,7 +2907,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Build the expression: __NSContainer_literal(int, ...).arr
QualType IntQT = Context->IntTy;
QualType NSDictFType =
- getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ getSimpleFunctionType(Context->VoidTy, IntQT, true);
std::string NSDictFName("__NSContainer_literal");
FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName);
DeclRefExpr *NSDictDRE =
@@ -3009,8 +3047,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- DictMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, DictMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3102,7 +3139,7 @@ static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R,
if (!LSD->getRBraceLoc().isValid())
return LSD->getExternLoc();
}
- if (FD->getStorageClassAsWritten() != SC_None)
+ if (FD->getStorageClass() != SC_None)
R.RewriteBlockLiteralFunctionDecl(FD);
return FD->getTypeSpecStartLoc();
}
@@ -3111,7 +3148,7 @@ void RewriteModernObjC::RewriteLineDirective(const Decl *D) {
SourceLocation Location = D->getLocation();
- if (Location.isFileID()) {
+ if (Location.isFileID() && GenerateLineInfo) {
std::string LineString("\n#line ");
PresumedLoc PLoc = SM->getPresumedLoc(Location);
LineString += utostr(PLoc.getLine());
@@ -3152,8 +3189,9 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
SmallVectorImpl<Expr*> &MsgExprs,
ObjCMethodDecl *Method) {
// Now do the "normal" pointer to function cast.
- QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- Method ? Method->isVariadic() : false);
+ QualType castType = getSimpleFunctionType(returnType, ArgTypes,
+ Method ? Method->isVariadic()
+ : false);
castType = Context->getPointerType(castType);
// build type for containing the objc_msgSend_stret object.
@@ -3211,8 +3249,8 @@ 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,
- SC_None, false, false);
+ SourceLocation(), ID, castType, 0,
+ SC_Extern, false, false);
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue,
SourceLocation());
CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs,
@@ -3592,10 +3630,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
CK_BitCast, DRE);
// Now do the "normal" pointer to function cast.
+ // If we don't have a method decl, force a variadic cast.
+ const ObjCMethodDecl *MD = Exp->getMethodDecl();
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- // If we don't have a method decl, force a variadic cast.
- Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true);
+ getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3685,7 +3723,7 @@ Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, getProtocolType(), 0,
- SC_Extern, SC_None);
+ SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -3840,16 +3878,16 @@ void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl,
Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context));
}
else if (EleboratedType && Type->isArrayType()) {
- CanQualType CType = Context->getCanonicalType(Type);
- while (isa<ArrayType>(CType)) {
- if (const ConstantArrayType *CAT = Context->getAsConstantArrayType(CType)) {
+ const ArrayType *AT = Context->getAsArrayType(Type);
+ do {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
Result += "[";
llvm::APInt Dim = CAT->getSize();
Result += utostr(Dim.getZExtValue());
Result += "]";
}
- CType = CType->getAs<ArrayType>()->getElementType();
- }
+ AT = Context->getAsArrayType(AT->getElementType());
+ } while (AT);
}
Result += ";\n";
@@ -3890,6 +3928,126 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec
}
+unsigned RewriteModernObjC::ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ if (ObjCInterefaceHasBitfieldGroups.count(CDecl)) {
+ return IvarGroupNumber[IV];
+ }
+ unsigned GroupNo = 0;
+ SmallVector<const ObjCIvarDecl *, 8> IVars;
+ for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar())
+ IVars.push_back(IVD);
+
+ for (unsigned i = 0, e = IVars.size(); i < e; i++)
+ if (IVars[i]->isBitField()) {
+ IvarGroupNumber[IVars[i++]] = ++GroupNo;
+ while (i < e && IVars[i]->isBitField())
+ IvarGroupNumber[IVars[i++]] = GroupNo;
+ if (i < e)
+ --i;
+ }
+
+ ObjCInterefaceHasBitfieldGroups.insert(CDecl);
+ return IvarGroupNumber[IV];
+}
+
+QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType(
+ ObjCIvarDecl *IV,
+ SmallVectorImpl<ObjCIvarDecl *> &IVars) {
+ std::string StructTagName;
+ ObjCIvarBitfieldGroupType(IV, StructTagName);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get(StructTagName));
+ for (unsigned i=0, e = IVars.size(); i < e; i++) {
+ ObjCIvarDecl *Ivar = IVars[i];
+ RD->addDecl(FieldDecl::Create(*Context, RD, SourceLocation(), SourceLocation(),
+ &Context->Idents.get(Ivar->getName()),
+ Ivar->getType(),
+ 0, /*Expr *BW */Ivar->getBitWidth(), false,
+ ICIS_NoInit));
+ }
+ RD->completeDefinition();
+ return Context->getTagDeclType(RD);
+}
+
+QualType RewriteModernObjC::GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
+ std::pair<const ObjCInterfaceDecl*, unsigned> tuple = std::make_pair(CDecl, GroupNo);
+ if (GroupRecordType.count(tuple))
+ return GroupRecordType[tuple];
+
+ SmallVector<ObjCIvarDecl *, 8> IVars;
+ for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
+ if (IVD->isBitField())
+ IVars.push_back(const_cast<ObjCIvarDecl *>(IVD));
+ else {
+ if (!IVars.empty()) {
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]);
+ // Generate the struct type for this group of bitfield ivars.
+ GroupRecordType[std::make_pair(CDecl, GroupNo)] =
+ SynthesizeBitfieldGroupStructType(IVars[0], IVars);
+ IVars.clear();
+ }
+ }
+ }
+ if (!IVars.empty()) {
+ // Do the last one.
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]);
+ GroupRecordType[std::make_pair(CDecl, GroupNo)] =
+ SynthesizeBitfieldGroupStructType(IVars[0], IVars);
+ }
+ QualType RetQT = GroupRecordType[tuple];
+ assert(!RetQT.isNull() && "GetGroupRecordTypeForObjCIvarBitfield struct type is NULL");
+
+ return RetQT;
+}
+
+/// ObjCIvarBitfieldGroupDecl - Names field decl. for ivar bitfield group.
+/// Name would be: classname__GRBF_n where n is the group number for this ivar.
+void RewriteModernObjC::ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV,
+ std::string &Result) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ Result += CDecl->getName();
+ Result += "__GRBF_";
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
+ Result += utostr(GroupNo);
+ return;
+}
+
+/// ObjCIvarBitfieldGroupType - Names struct type for ivar bitfield group.
+/// Name of the struct would be: classname__T_n where n is the group number for
+/// this ivar.
+void RewriteModernObjC::ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV,
+ std::string &Result) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ Result += CDecl->getName();
+ Result += "__T_";
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
+ Result += utostr(GroupNo);
+ return;
+}
+
+/// ObjCIvarBitfieldGroupOffset - Names symbol for ivar bitfield group field offset.
+/// Name would be: OBJC_IVAR_$_classname__GRBF_n where n is the group number for
+/// this ivar.
+void RewriteModernObjC::ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV,
+ std::string &Result) {
+ Result += "OBJC_IVAR_$_";
+ ObjCIvarBitfieldGroupDecl(IV, Result);
+}
+
+#define SKIP_BITFIELDS(IX, ENDIX, VEC) { \
+ while ((IX < ENDIX) && VEC[IX]->isBitField()) \
+ ++IX; \
+ if (IX < ENDIX) \
+ --IX; \
+}
+
/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
/// an objective-c class with ivars.
void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
@@ -3923,7 +4081,19 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// struct/unions in objective-c classes.
for (unsigned i = 0, e = IVars.size(); i < e; i++)
RewriteLocallyDefinedNamedAggregates(IVars[i], Result);
-
+
+ // Insert named structs which are syntheized to group ivar bitfields
+ // to outer scope as well.
+ for (unsigned i = 0, e = IVars.size(); i < e; i++)
+ if (IVars[i]->isBitField()) {
+ ObjCIvarDecl *IV = IVars[i];
+ QualType QT = GetGroupRecordTypeForObjCIvarBitfield(IV);
+ RewriteObjCFieldDeclType(QT, Result);
+ Result += ";";
+ // skip over ivar bitfields in this group.
+ SKIP_BITFIELDS(i , e, IVars);
+ }
+
Result += "\nstruct ";
Result += CDecl->getNameAsString();
Result += "_IMPL {\n";
@@ -3934,8 +4104,18 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Result += "_IVARS;\n";
}
- for (unsigned i = 0, e = IVars.size(); i < e; i++)
- RewriteObjCFieldDecl(IVars[i], Result);
+ for (unsigned i = 0, e = IVars.size(); i < e; i++) {
+ if (IVars[i]->isBitField()) {
+ ObjCIvarDecl *IV = IVars[i];
+ Result += "\tstruct ";
+ ObjCIvarBitfieldGroupType(IV, Result); Result += " ";
+ ObjCIvarBitfieldGroupDecl(IV, Result); Result += ";\n";
+ // skip over ivar bitfields in this group.
+ SKIP_BITFIELDS(i , e, IVars);
+ }
+ else
+ RewriteObjCFieldDecl(IVars[i], Result);
+ }
Result += "};\n";
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
@@ -3954,9 +4134,18 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
if (Ivars.empty())
return;
+
+ llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
for (llvm::SmallPtrSet<ObjCIvarDecl *, 8>::iterator i = Ivars.begin(),
e = Ivars.end(); i != e; i++) {
ObjCIvarDecl *IvarDecl = (*i);
+ const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
+ unsigned GroupNo = 0;
+ if (IvarDecl->isBitField()) {
+ GroupNo = ObjCIvarBitfieldGroupNo(IvarDecl);
+ if (GroupSymbolOutput.count(std::make_pair(IDecl, GroupNo)))
+ continue;
+ }
Result += "\n";
if (LangOpts.MicrosoftExt)
Result += "__declspec(allocate(\".objc_ivar$B\")) ";
@@ -3967,7 +4156,12 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
Result += "__declspec(dllimport) ";
Result += "unsigned long ";
- WriteInternalIvarName(CDecl, IvarDecl, Result);
+ if (IvarDecl->isBitField()) {
+ ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
+ GroupSymbolOutput.insert(std::make_pair(IDecl, GroupNo));
+ }
+ else
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += ";";
}
}
@@ -4545,7 +4739,7 @@ QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT)
}
QualType FuncType;
if (modified)
- FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ FuncType = getSimpleFunctionType(Res, ArgTypes);
else FuncType = QualType(FT, 0);
return FuncType;
}
@@ -4612,8 +4806,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+ QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
@@ -5053,7 +5246,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
// Add void *__Block_byref_id_object_copy;
// void *__Block_byref_id_object_dispose; if needed.
QualType Ty = ND->getType();
- bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND);
if (HasCopyAndDispose) {
ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
@@ -5089,7 +5282,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
flag |= BLOCK_FIELD_IS_OBJECT;
std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
if (!HF.empty())
- InsertText(FunLocStart, HF);
+ Preamble += HF;
}
// struct __Block_byref_ND ND =
@@ -5210,7 +5403,7 @@ FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) {
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, FType, 0, SC_Extern,
- SC_None, false, false);
+ false, false);
}
Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
@@ -5311,7 +5504,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData.c_str()),
Context->VoidPtrTy, 0,
- SC_Static, SC_None);
+ SC_Static);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
Context->VoidPtrTy,
@@ -5464,6 +5657,8 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
} else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
return RewriteObjCIvarRefExpr(IvarRefExpr);
}
+ else if (isa<OpaqueValueExpr>(S))
+ S = cast<OpaqueValueExpr>(S)->getSourceExpr();
SourceRange OrigStmtRange = S->getSourceRange();
@@ -5805,6 +6000,8 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ else
+ RewriteObjCQualifiedInterfaceTypes(TD);
}
break;
}
@@ -5844,6 +6041,14 @@ 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
+ // their extensions and implementations are seen. This is because, we
+ // cannot build grouping structs for bitfields untill they are all seen.
+ FunctionDecl *FDecl = FunctionDefinitionsSeen[i];
+ HandleTopLevelSingleDecl(FDecl);
+ }
+
// Here's a great place to add any extra declarations that may be needed.
// Write out meta data for each @protocol(<expr>).
for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
@@ -5865,7 +6070,7 @@ void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) {
// private ivars.
RewriteInterfaceDecl(CDecl);
}
-
+
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
if (const RewriteBuffer *RewriteBuf =
@@ -6060,19 +6265,16 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
/// ivar offset.
void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
- if (ivar->isBitField()) {
- // FIXME: The hack below doesn't work for bitfields. For now, we simply
- // place all bitfields at offset 0.
- Result += "0";
- } else {
- Result += "__OFFSETOFIVAR__(struct ";
- Result += ivar->getContainingInterface()->getNameAsString();
- if (LangOpts.MicrosoftExt)
- Result += "_IMPL";
- Result += ", ";
+ Result += "__OFFSETOFIVAR__(struct ";
+ Result += ivar->getContainingInterface()->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ", ";
+ if (ivar->isBitField())
+ ObjCIvarBitfieldGroupDecl(ivar, Result);
+ else
Result += ivar->getNameAsString();
- Result += ")";
- }
+ Result += ")";
}
/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI.
@@ -6749,21 +6951,41 @@ static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj,
Result += "extern \"C\" unsigned long int ";
else
Result += "extern \"C\" __declspec(dllexport) unsigned long int ";
- WriteInternalIvarName(CDecl, IvarDecl, Result);
+ if (Ivars[i]->isBitField())
+ RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
+ else
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))";
Result += " = ";
RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result);
Result += ";\n";
+ if (Ivars[i]->isBitField()) {
+ // skip over rest of the ivar bitfields.
+ SKIP_BITFIELDS(i , e, Ivars);
+ }
}
}
static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
ASTContext *Context, std::string &Result,
- ArrayRef<ObjCIvarDecl *> Ivars,
+ ArrayRef<ObjCIvarDecl *> OriginalIvars,
StringRef VarName,
ObjCInterfaceDecl *CDecl) {
- if (Ivars.size() > 0) {
- Write_IvarOffsetVar(RewriteObj, Context, Result, Ivars, CDecl);
+ if (OriginalIvars.size() > 0) {
+ Write_IvarOffsetVar(RewriteObj, Context, Result, OriginalIvars, CDecl);
+ SmallVector<ObjCIvarDecl *, 8> Ivars;
+ // strip off all but the first ivar bitfield from each group of ivars.
+ // Such ivars in the ivar list table will be replaced by their grouping struct
+ // 'ivar'.
+ for (unsigned i = 0, e = OriginalIvars.size(); i < e; i++) {
+ if (OriginalIvars[i]->isBitField()) {
+ Ivars.push_back(OriginalIvars[i]);
+ // skip over rest of the ivar bitfields.
+ SKIP_BITFIELDS(i , e, OriginalIvars);
+ }
+ else
+ Ivars.push_back(OriginalIvars[i]);
+ }
Result += "\nstatic ";
Write__ivar_list_t_TypeDecl(Result, Ivars.size());
@@ -6779,22 +7001,35 @@ static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
else
Result += "\t {";
Result += "(unsigned long int *)&";
- WriteInternalIvarName(CDecl, IvarDecl, Result);
+ if (Ivars[i]->isBitField())
+ RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
+ else
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += ", ";
- Result += "\""; Result += IvarDecl->getName(); Result += "\", ";
+ Result += "\"";
+ if (Ivars[i]->isBitField())
+ RewriteObj.ObjCIvarBitfieldGroupDecl(Ivars[i], Result);
+ else
+ Result += IvarDecl->getName();
+ Result += "\", ";
+
+ QualType IVQT = IvarDecl->getType();
+ if (IvarDecl->isBitField())
+ IVQT = RewriteObj.GetGroupRecordTypeForObjCIvarBitfield(IvarDecl);
+
std::string IvarTypeString, QuoteIvarTypeString;
- Context->getObjCEncodingForType(IvarDecl->getType(), IvarTypeString,
+ Context->getObjCEncodingForType(IVQT, IvarTypeString,
IvarDecl);
RewriteObj.QuoteDoublequotes(IvarTypeString, QuoteIvarTypeString);
Result += "\""; Result += QuoteIvarTypeString; Result += "\", ";
// FIXME. this alignment represents the host alignment and need be changed to
// represent the target alignment.
- unsigned Align = Context->getTypeAlign(IvarDecl->getType())/8;
+ unsigned Align = Context->getTypeAlign(IVQT)/8;
Align = llvm::Log2_32(Align);
Result += llvm::utostr(Align); Result += ", ";
- CharUnits Size = Context->getTypeSizeInChars(IvarDecl->getType());
+ CharUnits Size = Context->getTypeSizeInChars(IVQT);
Result += llvm::utostr(Size.getQuantity());
if (i == e-1)
Result += "}}\n";
@@ -7306,11 +7541,8 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
WriteModernMetadataDeclarations(Context, Result);
ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
// Find category declaration for this implementation.
- ObjCCategoryDecl *CDecl=0;
- for (CDecl = ClassDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->getIdentifier() == IDecl->getIdentifier())
- break;
+ ObjCCategoryDecl *CDecl
+ = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier());
std::string FullCategoryName = ClassDecl->getNameAsString();
FullCategoryName += "_$_";
@@ -7522,7 +7754,10 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
// Build name of symbol holding ivar offset.
std::string IvarOffsetName;
- WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
+ if (D->isBitField())
+ ObjCIvarBitfieldGroupOffset(D, IvarOffsetName);
+ else
+ WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
ReferencedIvars[clsDeclared].insert(D);
@@ -7533,7 +7768,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BaseExpr);
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(IvarOffsetName),
- Context->UnsignedLongTy, 0, SC_Extern, SC_None);
+ Context->UnsignedLongTy, 0, SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false,
Context->UnsignedLongTy, VK_LValue,
SourceLocation());
@@ -7546,6 +7781,8 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
SourceLocation(),
addExpr);
QualType IvarT = D->getType();
+ if (D->isBitField())
+ IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
@@ -7598,8 +7835,23 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
PE = new (Context) ParenExpr(OldRange.getBegin(),
OldRange.getEnd(),
Exp);
+
+ if (D->isBitField()) {
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get(D->getNameAsString()),
+ D->getType(), 0,
+ /*BitWidth=*/D->getBitWidth(),
+ /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(),
+ FD->getType(), VK_LValue,
+ OK_Ordinary);
+ Replacement = ME;
- Replacement = PE;
+ }
+ else
+ Replacement = PE;
}
ReplaceStmtWithRange(IV, Replacement, OldRange);
diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index a6dcc6b8d804..2f5cd0f6c6c6 100644
--- a/lib/Rewrite/Frontend/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -12,20 +12,22 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/ASTConsumers.h"
-#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
#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 "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/DenseSet.h"
using namespace clang;
using llvm::utostr;
@@ -265,7 +267,7 @@ namespace {
void RewriteRecordBody(RecordDecl *RD);
void RewriteInclude();
void RewriteForwardClassDecl(DeclGroupRef D);
- void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardClassDecl(const SmallVector<Decl *, 8> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
@@ -283,7 +285,7 @@ namespace {
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(DeclGroupRef D);
- void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -483,14 +485,13 @@ namespace {
}
QualType getSimpleFunctionType(QualType result,
- const QualType *args,
- unsigned numArgs,
+ ArrayRef<QualType> args,
bool variadic = false) {
if (result == Context->getObjCInstanceType())
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
- return Context->getFunctionType(result, args, numArgs, fpi);
+ return Context->getFunctionType(result, args, fpi);
}
// Helper function: create a CStyleCastExpr with trivial type source info.
@@ -925,8 +926,7 @@ void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
}
-void RewriteObjC::RewriteForwardClassDecl(
- const llvm::SmallVector<Decl*, 8> &D) {
+void RewriteObjC::RewriteForwardClassDecl(const SmallVector<Decl *, 8> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
@@ -1038,7 +1038,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
}
void
-RewriteObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+RewriteObjC::RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG) {
SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
@@ -2262,13 +2262,12 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
- getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ getSimpleFunctionType(Context->getObjCSelType(), ArgTys);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- SelGetUidIdent, getFuncType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ SelGetUidIdent, getFuncType, 0,
+ SC_Extern);
}
void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2359,13 +2358,12 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ 0, SC_Extern);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2379,14 +2377,12 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
@@ -2403,14 +2399,12 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2424,14 +2418,12 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2450,14 +2442,13 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ msgSendIdent,
+ msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
@@ -2471,14 +2462,12 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
@@ -2487,13 +2476,12 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
+ SC_Extern);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2503,15 +2491,13 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
getSuperClassIdent,
getClassType, 0,
- SC_Extern,
- SC_None,
- false);
+ SC_Extern);
}
// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name);
@@ -2520,13 +2506,12 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType,
+ 0, SC_Extern);
}
Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
@@ -2539,7 +2524,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
for (i=0; i < tmpName.length(); i++) {
char c = tmpName.at(i);
// replace any non alphanumeric characters with '_'.
- if (!isalpha(c) && (c < '0' || c > '9'))
+ if (!isAlphanumeric(c))
tmpName[i] = '_';
}
S += tmpName;
@@ -2559,7 +2544,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
- strType, 0, SC_Static, SC_None);
+ strType, 0, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2651,8 +2636,9 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
Context->getPointerType(Context->VoidTy),
CK_BitCast, STDRE);
// Now do the "normal" pointer to function cast.
- QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- Method ? Method->isVariadic() : false);
+ QualType castType = getSimpleFunctionType(returnType, ArgTypes,
+ Method ? Method->isVariadic()
+ : false);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3033,10 +3019,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
CK_BitCast, DRE);
// Now do the "normal" pointer to function cast.
+ // If we don't have a method decl, force a variadic cast.
+ const ObjCMethodDecl *MD = Exp->getMethodDecl();
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- // If we don't have a method decl, force a variadic cast.
- Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true);
+ getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3126,7 +3112,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, getProtocolType(), 0,
- SC_Extern, SC_None);
+ SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -3815,7 +3801,7 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
// FIXME. Does this work if block takes no argument but has a return type
// which is of block type?
if (HasBlockType)
- FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ FuncType = getSimpleFunctionType(Res, ArgTypes);
else FuncType = QualType(FT, 0);
return FuncType;
}
@@ -3882,8 +3868,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+ QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
@@ -4309,7 +4294,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
// Add void *__Block_byref_id_object_copy;
// void *__Block_byref_id_object_dispose; if needed.
QualType Ty = ND->getType();
- bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND);
if (HasCopyAndDispose) {
ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
@@ -4463,7 +4448,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, FType, 0, SC_Extern,
- SC_None, false, false);
+ false, false);
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
@@ -4547,7 +4532,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData.c_str()),
Context->VoidPtrTy, 0,
- SC_Static, SC_None);
+ SC_Static);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
Context->VoidPtrTy,
@@ -5754,11 +5739,8 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID
std::string &Result) {
ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
// Find category declaration for this implementation.
- ObjCCategoryDecl *CDecl;
- for (CDecl = ClassDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->getIdentifier() == IDecl->getIdentifier())
- break;
+ ObjCCategoryDecl *CDecl
+ = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier());
std::string FullCategoryName = ClassDecl->getNameAsString();
FullCategoryName += '_';
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 801a1b1e0264..00d3c47525d3 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -14,42 +14,43 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/AnalysisBasedWarnings.h"
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/StmtCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/Analyses/ReachableCode.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
-#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
+#include <deque>
#include <iterator>
#include <vector>
-#include <deque>
using namespace clang;
@@ -157,7 +158,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
for ( ; ri != re ; ++ri)
- if (isa<CFGStmt>(*ri))
+ if (ri->getAs<CFGStmt>())
break;
// No more CFGElements in the block?
@@ -171,7 +172,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
continue;
}
- CFGStmt CS = cast<CFGStmt>(*ri);
+ CFGStmt CS = ri->castAs<CFGStmt>();
const Stmt *S = CS.getStmt();
if (isa<ReturnStmt>(S)) {
HasLiveReturn = true;
@@ -329,8 +330,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
ReturnsVoid = FD->getResultType()->isVoidType();
- HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+ HasNoReturn = FD->isNoReturn();
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
ReturnsVoid = MD->getResultType()->isVoidType();
@@ -505,7 +505,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
StringRef Str;
SourceRange Range;
- // FixIts to suppress the diagnosic by removing the dead condition.
+ // FixIts to suppress the diagnostic by removing the dead condition.
// For all binary terminators, branch 0 is taken if the condition is true,
// and branch 1 is taken if the condition is false.
int RemoveDiagKind = -1;
@@ -703,7 +703,38 @@ namespace {
return FallthroughStmts;
}
+ void fillReachableBlocks(CFG *Cfg) {
+ assert(ReachableBlocks.empty() && "ReachableBlocks already filled");
+ std::deque<const CFGBlock *> BlockQueue;
+
+ ReachableBlocks.insert(&Cfg->getEntry());
+ BlockQueue.push_back(&Cfg->getEntry());
+ // Mark all case blocks reachable to avoid problems with switching on
+ // 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;
+ const Stmt *L = B->getLabel();
+ if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B))
+ BlockQueue.push_back(B);
+ }
+
+ while (!BlockQueue.empty()) {
+ const CFGBlock *P = BlockQueue.front();
+ BlockQueue.pop_front();
+ for (CFGBlock::const_succ_iterator I = P->succ_begin(),
+ E = P->succ_end();
+ I != E; ++I) {
+ if (*I && ReachableBlocks.insert(*I))
+ BlockQueue.push_back(*I);
+ }
+ }
+ }
+
bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) {
+ assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
+
int UnannotatedCnt = 0;
AnnotatedCnt = 0;
@@ -723,16 +754,21 @@ namespace {
if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())
continue; // Previous case label has no statements, good.
- if (P->pred_begin() == P->pred_end()) { // The block is unreachable.
- // This only catches trivially unreachable blocks.
- for (CFGBlock::const_iterator ElIt = P->begin(), ElEnd = P->end();
- ElIt != ElEnd; ++ElIt) {
- if (const CFGStmt *CS = ElIt->getAs<CFGStmt>()){
+ const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel());
+ if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())
+ continue; // Case label is preceded with a normal label, good.
+
+ if (!ReachableBlocks.count(P)) {
+ for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(),
+ ElemEnd = P->rend();
+ ElemIt != ElemEnd; ++ElemIt) {
+ if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) {
if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
S.Diag(AS->getLocStart(),
diag::warn_fallthrough_attr_unreachable);
markFallthroughVisited(AS);
++AnnotatedCnt;
+ break;
}
// Don't care about other unreachable statements.
}
@@ -781,6 +817,10 @@ namespace {
return true;
}
+ // We don't want to traverse local type declarations. We analyze their
+ // methods separately.
+ bool TraverseDecl(Decl *D) { return true; }
+
private:
static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
@@ -797,7 +837,7 @@ namespace {
for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(),
ElemEnd = B.rend();
ElemIt != ElemEnd; ++ElemIt) {
- if (const CFGStmt *CS = ElemIt->getAs<CFGStmt>())
+ if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>())
return CS->getStmt();
}
// Workaround to detect a statement thrown out by CFGBuilder:
@@ -813,6 +853,7 @@ namespace {
bool FoundSwitchStatements;
AttrStmts FallthroughStmts;
Sema &S;
+ llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
};
}
@@ -827,7 +868,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
//
// NOTE: This an intermediate solution. There are on-going discussions on
// how to properly support this warning outside of C++11 with an annotation.
- if (!AC.getASTContext().getLangOpts().CPlusPlus0x)
+ if (!AC.getASTContext().getLangOpts().CPlusPlus11)
return;
FallthroughMapper FM(S);
@@ -844,16 +885,18 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
if (!Cfg)
return;
- int AnnotatedCnt;
+ FM.fillReachableBlocks(Cfg);
for (CFG::reverse_iterator I = Cfg->rbegin(), E = Cfg->rend(); I != E; ++I) {
- const CFGBlock &B = **I;
- const Stmt *Label = B.getLabel();
+ const CFGBlock *B = *I;
+ const Stmt *Label = B->getLabel();
if (!Label || !isa<SwitchCase>(Label))
continue;
- if (!FM.checkFallThroughIntoBlock(B, AnnotatedCnt))
+ int AnnotatedCnt;
+
+ if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
continue;
S.Diag(Label->getLocStart(),
@@ -864,9 +907,14 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
SourceLocation L = Label->getLocStart();
if (L.isMacroID())
continue;
- if (S.getLangOpts().CPlusPlus0x) {
- const Stmt *Term = B.getTerminator();
- if (!(B.empty() && Term && isa<BreakStmt>(Term))) {
+ if (S.getLangOpts().CPlusPlus11) {
+ const Stmt *Term = B->getTerminator();
+ // Skip empty cases.
+ while (B->empty() && !Term && B->succ_size() == 1) {
+ B = *B->succ_begin();
+ Term = B->getTerminator();
+ }
+ if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
TokenValue Tokens[] = {
tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
@@ -1106,7 +1154,11 @@ struct SLocSort {
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
typedef SmallVector<UninitUse, 2> UsesVec;
- typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap;
+ typedef std::pair<UsesVec*, bool> MappedType;
+ // Prefer using MapVector to DenseMap, so that iteration order will be
+ // the same as insertion order. This is needed to obtain a deterministic
+ // order of diagnostics when calling flushDiagnostics().
+ typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
UsesMap *uses;
public:
@@ -1115,11 +1167,11 @@ public:
flushDiagnostics();
}
- std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) {
+ MappedType &getUses(const VarDecl *vd) {
if (!uses)
uses = new UsesMap();
- UsesMap::mapped_type &V = (*uses)[vd];
+ MappedType &V = (*uses)[vd];
UsesVec *&vec = V.first;
if (!vec)
vec = new UsesVec();
@@ -1138,12 +1190,10 @@ public:
void flushDiagnostics() {
if (!uses)
return;
-
- // FIXME: This iteration order, and thus the resulting diagnostic order,
- // is nondeterministic.
+
for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) {
const VarDecl *vd = i->first;
- const UsesMap::mapped_type &V = i->second;
+ const MappedType &V = i->second;
UsesVec *vec = V.first;
bool hasSelfInit = V.second;
@@ -1198,7 +1248,7 @@ private:
//===----------------------------------------------------------------------===//
namespace clang {
namespace thread_safety {
-typedef llvm::SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
+typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
typedef std::list<DelayedDiag> DiagList;
@@ -1423,7 +1473,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (cast<DeclContext>(D)->isDependentContext())
return;
- if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) {
+ if (Diags.hasUncompilableErrorOccurred() || Diags.hasFatalErrorOccurred()) {
// Flush out any possibly unreachable diagnostics.
flushDiagnostics(S, fscope);
return;
@@ -1544,6 +1594,10 @@ 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)
+ Reporter.setIssueBetaWarnings(true);
+
thread_safety::runThreadSafetyAnalysis(AC, Reporter);
Reporter.emitDiagnostics();
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 7c79879d976c..e227d4e840b3 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -15,8 +15,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
size_t AttributeList::allocated_size() const {
@@ -125,3 +125,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
return ::getAttrKind(Buf);
}
+
+unsigned AttributeList::getAttributeSpellingListIndex() const {
+ // Both variables will be used in tablegen generated
+ // attribute spell list index matching code.
+ StringRef Name = AttrName->getName();
+ StringRef Scope = ScopeName ? ScopeName->getName() : "";
+
+#include "clang/Sema/AttrSpellingListIndex.inc"
+
+}
+
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 7cfe3ae8462c..e92f76713422 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -38,6 +38,7 @@ add_clang_library(clangSema
SemaLambda.cpp
SemaLookup.cpp
SemaObjCProperty.cpp
+ SemaOpenMP.cpp
SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp
@@ -58,6 +59,7 @@ add_dependencies(clangSema
ClangAttrList
ClangAttrParsedAttrList
ClangAttrParsedAttrKinds
+ ClangAttrSpellingListIndex
ClangAttrTemplateInstantiate
ClangCommentNodes
ClangDeclNodes
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 0a236018bdfd..19be1cb42fe7 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Sema.h"
+#include "clang-c/Index.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang-c/Index.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -267,8 +267,8 @@ const char *CodeCompletionAllocator::CopyString(Twine String) {
return CopyString(String.toStringRef(Data));
}
-StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
- NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {
+ const NamedDecl *ND = dyn_cast<NamedDecl>(DC);
if (!ND)
return StringRef();
@@ -283,9 +283,9 @@ StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
return StringRef();
// Find the interesting names.
- llvm::SmallVector<DeclContext *, 2> Contexts;
+ SmallVector<const DeclContext *, 2> Contexts;
while (DC && !DC->isFunctionOrMethod()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
if (ND->getIdentifier())
Contexts.push_back(DC);
}
@@ -294,7 +294,7 @@ StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
}
{
- llvm::SmallString<128> S;
+ SmallString<128> S;
llvm::raw_svector_ostream OS(S);
bool First = true;
for (unsigned I = Contexts.size(); I != 0; --I) {
@@ -304,12 +304,12 @@ StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
OS << "::";
}
- DeclContext *CurDC = Contexts[I-1];
- if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
+ const DeclContext *CurDC = Contexts[I-1];
+ if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
CurDC = CatImpl->getCategoryDecl();
- if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
- ObjCInterfaceDecl *Interface = Cat->getClassInterface();
+ if (const ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
+ const ObjCInterfaceDecl *Interface = Cat->getClassInterface();
if (!Interface) {
// Assign an empty StringRef but with non-null data to distinguish
// between empty because we didn't process the DeclContext yet.
@@ -377,7 +377,7 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
Chunks.push_back(Chunk(CK, Text));
}
-void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
+void CodeCompletionBuilder::addParentContext(const DeclContext *DC) {
if (DC->isTranslationUnit()) {
return;
}
@@ -385,7 +385,7 @@ void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (DC->isFunctionOrMethod())
return;
- NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+ const NamedDecl *ND = dyn_cast<NamedDecl>(DC);
if (!ND)
return;
@@ -396,33 +396,6 @@ void CodeCompletionBuilder::addBriefComment(StringRef Comment) {
BriefComment = Allocator.CopyString(Comment);
}
-unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) {
- if (!ND)
- return CCP_Unlikely;
-
- // Context-based decisions.
- DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
- // _cmd is relatively rare
- if (ImplicitParamDecl *ImplicitParam = dyn_cast<ImplicitParamDecl>(ND))
- if (ImplicitParam->getIdentifier() &&
- ImplicitParam->getIdentifier()->isStr("_cmd"))
- return CCP_ObjC_cmd;
-
- return CCP_LocalDeclaration;
- }
- if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
- return CCP_MemberDeclaration;
-
- // Content-based decisions.
- if (isa<EnumConstantDecl>(ND))
- return CCP_Constant;
- if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
- return CCP_Type;
-
- return CCP_Declaration;
-}
-
//===----------------------------------------------------------------------===//
// Code completion overload candidate implementation
//===----------------------------------------------------------------------===//
@@ -526,7 +499,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
}
/// \brief Retrieve the effective availability of the given declaration.
-static AvailabilityResult getDeclAvailability(Decl *D) {
+static AvailabilityResult getDeclAvailability(const Decl *D) {
AvailabilityResult AR = D->getAvailability();
if (isa<EnumConstantDecl>(D))
AR = std::max(AR, cast<Decl>(D->getDeclContext())->getAvailability());
@@ -559,7 +532,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
break;
}
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration))
if (Function->isDeleted())
Availability = CXAvailability_NotAvailable;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index b3066eb08013..e1d55dbddccf 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -11,18 +11,18 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/LocInfoType.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Sema/Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
+#include "clang/Sema/LocInfoType.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstring>
@@ -169,6 +169,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
TypeResult TrailingReturnType) {
+ assert(!(TypeQuals & DeclSpec::TQ_atomic) &&
+ "function cannot have _Atomic qualifier");
+
DeclaratorChunk I;
I.Kind = Function;
I.Loc = LocalRangeBegin;
@@ -280,6 +283,14 @@ 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:
@@ -323,7 +334,8 @@ unsigned DeclSpec::getParsedSpecifiers() const {
if (hasTypeSpecifier())
Res |= PQ_TypeSpecifier;
- if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified)
+ if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified ||
+ FS_noreturn_specified)
Res |= PQ_FunctionSpecifier;
return Res;
}
@@ -414,6 +426,14 @@ 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!");
@@ -425,6 +445,7 @@ const char *DeclSpec::getSpecifierName(TQ T) {
case DeclSpec::TQ_const: return "const";
case DeclSpec::TQ_restrict: return "restrict";
case DeclSpec::TQ_volatile: return "volatile";
+ case DeclSpec::TQ_atomic: return "_Atomic";
}
llvm_unreachable("Unknown typespec!");
}
@@ -693,38 +714,44 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
TypeQualifiers |= T;
switch (T) {
- default: llvm_unreachable("Unknown type qualifier!");
- case TQ_const: TQ_constLoc = Loc; break;
- case TQ_restrict: TQ_restrictLoc = Loc; break;
- case TQ_volatile: TQ_volatileLoc = Loc; break;
+ case TQ_unspecified: break;
+ case TQ_const: TQ_constLoc = Loc; return false;
+ case TQ_restrict: TQ_restrictLoc = Loc; return false;
+ case TQ_volatile: TQ_volatileLoc = Loc; return false;
+ case TQ_atomic: TQ_atomicLoc = Loc; return false;
}
- return false;
+
+ llvm_unreachable("Unknown type qualifier!");
}
-bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
+bool DeclSpec::setFunctionSpecInline(SourceLocation Loc) {
// 'inline inline' is ok.
FS_inline_specified = true;
FS_inlineLoc = Loc;
return false;
}
-bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
+bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc) {
// 'virtual virtual' is ok.
FS_virtual_specified = true;
FS_virtualLoc = Loc;
return false;
}
-bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
+bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc) {
// 'explicit explicit' is ok.
FS_explicit_specified = true;
FS_explicitLoc = Loc;
return false;
}
+bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc) {
+ // '_Noreturn _Noreturn' is ok.
+ FS_noreturn_specified = true;
+ FS_noreturnLoc = Loc;
+ return false;
+}
+
bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
if (Friend_specified) {
@@ -763,9 +790,10 @@ void DeclSpec::setProtocolQualifiers(Decl * const *Protos,
SourceLocation *ProtoLocs,
SourceLocation LAngleLoc) {
if (NP == 0) return;
- ProtocolQualifiers = new Decl*[NP];
+ Decl **ProtoQuals = new Decl*[NP];
+ memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP);
+ ProtocolQualifiers = ProtoQuals;
ProtocolLocs = new SourceLocation[NP];
- memcpy((void*)ProtocolQualifiers, Protos, sizeof(Decl*)*NP);
memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP);
NumProtocolQualifiers = NP;
ProtocolLAngleLoc = LAngleLoc;
@@ -787,15 +815,6 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
}
}
-void DeclSpec::SaveStorageSpecifierAsWritten() {
- if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern)
- // If 'extern' is part of a linkage specification,
- // then it is not a storage class "as written".
- StorageClassSpecAsWritten = SCS_unspecified;
- else
- StorageClassSpecAsWritten = StorageClassSpec;
-}
-
/// Finish - This does final analysis of the declspec, rejecting things like
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
@@ -803,7 +822,6 @@ void DeclSpec::SaveStorageSpecifierAsWritten() {
void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
- SaveStorageSpecifierAsWritten();
// Check the type specifier components first.
@@ -913,15 +931,15 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt &&
TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) {
TypeSpecType = TST_auto;
- StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified;
+ StorageClassSpec = SCS_unspecified;
TSTLoc = TSTNameLoc = StorageClassSpecLoc;
StorageClassSpecLoc = SourceLocation();
}
// Diagnose if we've recovered from an ill-formed 'auto' storage class
// specifier in a pre-C++0x dialect of C++.
- if (!PP.getLangOpts().CPlusPlus0x && TypeSpecType == TST_auto)
+ if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto)
Diag(D, TSTLoc, diag::ext_auto_type_specifier);
- if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus0x &&
+ if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 &&
StorageClassSpec == SCS_auto)
Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class)
<< FixItHint::CreateRemoval(StorageClassSpecLoc);
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 7d5530442f48..d44c1fb926f5 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -13,12 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/IdentifierResolver.h"
-#include "clang/Sema/Scope.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Scope.h"
using namespace clang;
@@ -108,8 +107,7 @@ IdentifierResolver::~IdentifierResolver() {
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
-bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
- ASTContext &Context, Scope *S,
+bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
bool ExplicitInstantiationOrSpecialization) const {
Ctx = Ctx->getRedeclContext();
@@ -304,6 +302,14 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
// If the declarations are redeclarations of each other, keep the newest one.
if (Existing->getCanonicalDecl() == New->getCanonicalDecl()) {
+ // If either of these is the most recent declaration, use it.
+ Decl *MostRecent = Existing->getMostRecentDecl();
+ if (Existing == MostRecent)
+ return DMK_Ignore;
+
+ if (New == MostRecent)
+ return DMK_Replace;
+
// 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(),
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index e2ec1ccebdcf..5f92cfffc6b0 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -16,8 +16,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "llvm/ADT/BitVector.h"
using namespace clang;
@@ -511,8 +511,14 @@ void JumpScopeChecker::VerifyJumps() {
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
- CheckJump(SS, SC, SC->getLocStart(),
- diag::err_switch_into_protected_scope, 0,
+ SourceLocation Loc;
+ if (CaseStmt *CS = dyn_cast<CaseStmt>(SC))
+ Loc = CS->getLocStart();
+ else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC))
+ Loc = DS->getLocStart();
+ else
+ Loc = SC->getLocStart();
+ CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0,
diag::warn_cxx98_compat_switch_into_protected_scope);
}
}
@@ -668,7 +674,7 @@ static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) {
/// Return true if a particular note should be downgraded to a compatibility
/// warning in C++11 mode.
static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
- return S.getLangOpts().CPlusPlus0x &&
+ return S.getLangOpts().CPlusPlus11 &&
InDiagNote == diag::note_protected_by_variable_non_pod;
}
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index f930fb348a25..d85624ba6f64 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -11,7 +11,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/MultiplexExternalSemaSource.h"
-
#include "clang/AST/DeclContextInternals.h"
#include "clang/Sema/Lookup.h"
@@ -82,19 +81,12 @@ CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
return 0;
}
-DeclContextLookupResult MultiplexExternalSemaSource::
+bool MultiplexExternalSemaSource::
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
- StoredDeclsList DeclsFound;
- DeclContextLookupResult lookup;
- for(size_t i = 0; i < Sources.size(); ++i) {
- lookup = Sources[i]->FindExternalVisibleDeclsByName(DC, Name);
- while(lookup.first != lookup.second) {
- if (!DeclsFound.HandleRedeclaration(*lookup.first))
- DeclsFound.AddSubsequentDecl(*lookup.first);
- lookup.first++;
- }
- }
- return DeclsFound.getLookupResult();
+ bool AnyDeclsFound = false;
+ for (size_t i = 0; i < Sources.size(); ++i)
+ AnyDeclsFound |= Sources[i]->FindExternalVisibleDeclsByName(DC, Name);
+ return AnyDeclsFound;
}
void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
@@ -201,6 +193,12 @@ void MultiplexExternalSemaSource::ReadKnownNamespaces(
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadKnownNamespaces(Namespaces);
}
+
+void MultiplexExternalSemaSource::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUndefinedButUsed(Undefined);
+}
bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R, Scope *S){
for(size_t i = 0; i < Sources.size(); ++i)
@@ -239,10 +237,10 @@ void MultiplexExternalSemaSource::ReadDynamicClasses(
Sources[i]->ReadDynamicClasses(Decls);
}
-void MultiplexExternalSemaSource::ReadLocallyScopedExternalDecls(
+void MultiplexExternalSemaSource::ReadLocallyScopedExternCDecls(
SmallVectorImpl<NamedDecl*> &Decls) {
for(size_t i = 0; i < Sources.size(); ++i)
- Sources[i]->ReadLocallyScopedExternalDecls(Decls);
+ Sources[i]->ReadLocallyScopedExternCDecls(Decls);
}
void MultiplexExternalSemaSource::ReadReferencedSelectors(
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 13a33b785b43..6bab9e80cbf7 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,21 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DelayedDiagnostic.h"
#include "TargetAttributesSema.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/APFloat.h"
-#include "llvm/Support/CrashRecoveryContext.h"
-#include "clang/Sema/CXXFieldCollector.h"
-#include "clang/Sema/TemplateDeduction.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/MultiplexExternalSemaSource.h"
-#include "clang/Sema/ObjCMethodList.h"
-#include "clang/Sema/PrettyDeclStackTrace.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/SemaConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -36,11 +22,25 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/CXXFieldCollector.h"
+#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+#include "clang/Sema/ObjCMethodList.h"
+#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/TemplateDeduction.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
using namespace sema;
@@ -49,13 +49,14 @@ PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
PrintingPolicy Policy = Context.getPrintingPolicy();
Policy.Bool = Context.getLangOpts().Bool;
if (!Policy.Bool) {
- if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
- Policy.Bool = BoolMacro->isObjectLike() &&
+ if (const MacroInfo *
+ BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
+ Policy.Bool = BoolMacro->isObjectLike() &&
BoolMacro->getNumTokens() == 1 &&
BoolMacro->getReplacementToken(0).is(tok::kw__Bool);
}
}
-
+
return Policy;
}
@@ -69,7 +70,7 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
- : TheTargetAttributesSema(0), ExternalSource(0),
+ : TheTargetAttributesSema(0), ExternalSource(0),
isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
@@ -83,16 +84,16 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
NSStringDecl(0), StringWithUTF8StringMethod(0),
NSArrayDecl(0), ArrayWithObjectsMethod(0),
NSDictionaryDecl(0), DictionaryWithObjectsMethod(0),
- GlobalNewDeleteDeclared(false),
+ GlobalNewDeleteDeclared(false),
TUKind(TUKind),
NumSFINAEErrors(0), InFunctionDeclarator(0),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
CurrentInstantiationScope(0), TyposCorrected(0),
- AnalysisWarnings(*this)
+ AnalysisWarnings(*this), Ident_super(0)
{
TUScope = 0;
-
+
LoadedExternalKnownNamespaces = false;
for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)
NSNumberLiteralMethods[I] = 0;
@@ -104,7 +105,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
- PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
&Context);
ExprEvalContexts.push_back(
@@ -117,18 +118,18 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
void Sema::Initialize() {
// Tell the AST consumer about this Sema object.
Consumer.Initialize(Context);
-
+
// FIXME: Isn't this redundant with the initialization above?
if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer))
SC->InitializeSema(*this);
-
+
// Tell the external Sema source about this Sema object.
if (ExternalSemaSource *ExternalSema
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->InitializeSema(*this);
// Initialize predefined 128-bit integer types, if needed.
- if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
+ if (PP.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");
@@ -139,7 +140,7 @@ void Sema::Initialize() {
if (IdResolver.begin(UInt128) == IdResolver.end())
PushOnScopeChains(Context.getUInt128Decl(), TUScope);
}
-
+
// Initialize predefined Objective-C types:
if (PP.getLangOpts().ObjC1) {
@@ -154,7 +155,7 @@ void Sema::Initialize() {
DeclarationName Id = &Context.Idents.get("id");
if (IdResolver.begin(Id) == IdResolver.end())
PushOnScopeChains(Context.getObjCIdDecl(), TUScope);
-
+
// Create the built-in typedef for 'Class'.
DeclarationName Class = &Context.Idents.get("Class");
if (IdResolver.begin(Class) == IdResolver.end())
@@ -181,7 +182,7 @@ Sema::~Sema() {
delete FunctionScopes[I];
if (FunctionScopes.size() == 1)
delete FunctionScopes[0];
-
+
// Tell the SemaConsumer to forget about us; we're going out of scope.
if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer))
SC->ForgetSema();
@@ -209,7 +210,7 @@ bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
// If we're in template instantiation, it's an error.
if (!ActiveTemplateInstantiations.empty())
return false;
-
+
// If that function's not in a system header, it's an error.
if (!Context.getSourceManager().isInSystemHeader(loc))
return false;
@@ -288,13 +289,13 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
- if (Kind == CK_DerivedToBase &&
+ if (Kind == CK_DerivedToBase &&
BasePathInvolvesVirtualBase(*BasePath)) {
QualType T = E->getType();
if (const PointerType *Pointer = T->getAs<PointerType>())
T = Pointer->getPointeeType();
if (const RecordType *RecordTy = T->getAs<RecordType>())
- MarkVTableUsed(E->getLocStart(),
+ MarkVTableUsed(E->getLocStart(),
cast<CXXRecordDecl>(RecordTy->getDecl()));
}
@@ -328,7 +329,10 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector.
static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
- if (D->isUsed())
+ if (D->getMostRecentDecl()->isUsed())
+ return true;
+
+ if (D->hasExternalLinkage())
return true;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -348,7 +352,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
- const VarDecl *DeclToCheck = VD->getDefinition();
+ const VarDecl *DeclToCheck = VD->getDefinition();
if (DeclToCheck)
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
@@ -363,68 +367,91 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
}
namespace {
- struct UndefinedInternal {
- NamedDecl *decl;
- FullSourceLoc useLoc;
-
- UndefinedInternal(NamedDecl *decl, FullSourceLoc useLoc)
- : decl(decl), useLoc(useLoc) {}
+ 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());
+ }
};
-
- bool operator<(const UndefinedInternal &l, const UndefinedInternal &r) {
- return l.useLoc.isBeforeInTranslationUnitThan(r.useLoc);
- }
}
-/// checkUndefinedInternals - Check for undefined objects with internal linkage.
-static void checkUndefinedInternals(Sema &S) {
- if (S.UndefinedInternals.empty()) return;
-
- // Collect all the still-undefined entities with internal linkage.
- SmallVector<UndefinedInternal, 16> undefined;
- for (llvm::DenseMap<NamedDecl*,SourceLocation>::iterator
- i = S.UndefinedInternals.begin(), e = S.UndefinedInternals.end();
- i != e; ++i) {
- NamedDecl *decl = i->first;
+/// Obtains a sorted list of functions that are undefined but ODR-used.
+void Sema::getUndefinedButUsed(
+ SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) {
+ for (llvm::DenseMap<NamedDecl *, SourceLocation>::iterator
+ I = UndefinedButUsed.begin(), E = UndefinedButUsed.end();
+ I != E; ++I) {
+ NamedDecl *ND = I->first;
// Ignore attributes that have become invalid.
- if (decl->isInvalidDecl()) continue;
+ if (ND->isInvalidDecl()) continue;
// __attribute__((weakref)) is basically a definition.
- if (decl->hasAttr<WeakRefAttr>()) continue;
+ if (ND->hasAttr<WeakRefAttr>()) continue;
- if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) {
- if (fn->isPure() || fn->hasBody())
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ if (FD->isDefined())
+ continue;
+ if (FD->hasExternalLinkage() &&
+ !FD->getMostRecentDecl()->isInlined())
continue;
} else {
- if (cast<VarDecl>(decl)->hasDefinition() != VarDecl::DeclarationOnly)
+ if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly)
+ continue;
+ if (ND->hasExternalLinkage())
continue;
}
- // We build a FullSourceLoc so that we can sort with array_pod_sort.
- FullSourceLoc loc(i->second, S.Context.getSourceManager());
- undefined.push_back(UndefinedInternal(decl, loc));
+ Undefined.push_back(std::make_pair(ND, I->second));
}
- if (undefined.empty()) return;
+ // Sort (in order of use site) so that we're not dependent on the iteration
+ // order through an llvm::DenseMap.
+ std::sort(Undefined.begin(), Undefined.end(),
+ SortUndefinedButUsed(Context.getSourceManager()));
+}
+
+/// checkUndefinedButUsed - Check for undefined objects with internal linkage
+/// or that are inline.
+static void checkUndefinedButUsed(Sema &S) {
+ if (S.UndefinedButUsed.empty()) return;
+
+ // Collect all the still-undefined entities with internal linkage.
+ SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
+ S.getUndefinedButUsed(Undefined);
+ if (Undefined.empty()) return;
- // Sort (in order of use site) so that we're not (as) dependent on
- // the iteration order through an llvm::DenseMap.
- llvm::array_pod_sort(undefined.begin(), undefined.end());
+ for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
+ I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
+ NamedDecl *ND = I->first;
- for (SmallVectorImpl<UndefinedInternal>::iterator
- i = undefined.begin(), e = undefined.end(); i != e; ++i) {
- NamedDecl *decl = i->decl;
- S.Diag(decl->getLocation(), diag::warn_undefined_internal)
- << isa<VarDecl>(decl) << decl;
- S.Diag(i->useLoc, diag::note_used_here);
+ if (ND->getLinkage() != ExternalLinkage) {
+ S.Diag(ND->getLocation(), diag::warn_undefined_internal)
+ << isa<VarDecl>(ND) << ND;
+ } else {
+ assert(cast<FunctionDecl>(ND)->getMostRecentDecl()->isInlined() &&
+ "used object requires definition but isn't inline or internal?");
+ S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND;
+ }
+ if (I->second.isValid())
+ S.Diag(I->second, diag::note_used_here);
}
}
void Sema::LoadExternalWeakUndeclaredIdentifiers() {
if (!ExternalSource)
return;
-
+
SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs;
ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs);
for (unsigned I = 0, N = WeakIDs.size(); I != N; ++I) {
@@ -432,7 +459,7 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() {
= WeakUndeclaredIdentifiers.find(WeakIDs[I].first);
if (Pos != WeakUndeclaredIdentifiers.end())
continue;
-
+
WeakUndeclaredIdentifiers.insert(WeakIDs[I]);
}
}
@@ -537,7 +564,7 @@ void Sema::ActOnEndOfTranslationUnit() {
I != E; ++I) {
assert(!(*I)->isDependentType() &&
"Should not see dependent types here!");
- if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) {
+ if (const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(*I)) {
const FunctionDecl *Definition = 0;
if (KeyFunction->hasBody(Definition))
MarkVTableUsed(Definition->getLocation(), *I, true);
@@ -561,9 +588,9 @@ void Sema::ActOnEndOfTranslationUnit() {
// or we need to perform template instantiations earlier.
PerformPendingInstantiations();
}
-
+
// Remove file scoped decls that turned out to be used.
- UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0,
+ UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0,
true),
UnusedFileScopedDecls.end(),
std::bind1st(std::ptr_fun(ShouldRemoveFromUnused),
@@ -589,24 +616,31 @@ void Sema::ActOnEndOfTranslationUnit() {
<< I->first;
}
+ if (LangOpts.CPlusPlus11 &&
+ Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
+ SourceLocation())
+ != DiagnosticsEngine::Ignored)
+ CheckDelegatingCtorCycles();
+
if (TUKind == TU_Module) {
// If we are building a module, resolve all of the exported declarations
// now.
if (Module *CurrentModule = PP.getCurrentModule()) {
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
-
- llvm::SmallVector<Module *, 2> Stack;
+
+ SmallVector<Module *, 2> Stack;
Stack.push_back(CurrentModule);
while (!Stack.empty()) {
Module *Mod = Stack.back();
Stack.pop_back();
-
- // Resolve the exported declarations.
+
+ // Resolve the exported declarations and conflicts.
// FIXME: Actually complain, once we figure out how to teach the
- // diagnostic client to deal with complains in the module map at this
+ // diagnostic client to deal with complaints in the module map at this
// point.
ModMap.resolveExports(Mod, /*Complain=*/false);
-
+ ModMap.resolveConflicts(Mod, /*Complain=*/false);
+
// Queue the submodules, so their exports will also be resolved.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
@@ -615,12 +649,12 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
}
-
+
// Modules don't need any of the checking below.
TUScope = 0;
return;
}
-
+
// C99 6.9.2p2:
// A declaration of an identifier for an object that has file
// scope without an initializer, and without a storage-class
@@ -633,10 +667,10 @@ void Sema::ActOnEndOfTranslationUnit() {
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
llvm::SmallSet<VarDecl *, 32> Seen;
- for (TentativeDefinitionsType::iterator
+ for (TentativeDefinitionsType::iterator
T = TentativeDefinitions.begin(ExternalSource),
TEnd = TentativeDefinitions.end();
- T != TEnd; ++T)
+ T != TEnd; ++T)
{
VarDecl *VD = (*T)->getActingDefinition();
@@ -673,12 +707,6 @@ void Sema::ActOnEndOfTranslationUnit() {
}
- if (LangOpts.CPlusPlus0x &&
- Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
- SourceLocation())
- != DiagnosticsEngine::Ignored)
- CheckDelegatingCtorCycles();
-
// If there were errors, disable 'unused' warnings since they will mostly be
// noise.
if (!Diags.hasErrorOccurred()) {
@@ -688,7 +716,7 @@ void Sema::ActOnEndOfTranslationUnit() {
E = UnusedFileScopedDecls.end(); I != E; ++I) {
if (ShouldRemoveFromUnused(this, *I))
continue;
-
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionDecl *DiagD;
if (!FD->hasBody(DiagD))
@@ -700,7 +728,7 @@ void Sema::ActOnEndOfTranslationUnit() {
Diag(DiagD->getLocation(), diag::warn_unneeded_member_function)
<< DiagD->getDeclName();
else {
- if (FD->getStorageClassAsWritten() == SC_Static &&
+ if (FD->getStorageClass() == SC_Static &&
!FD->isInlineSpecified() &&
!SourceMgr.isFromMainFile(
SourceMgr.getExpansionLoc(FD->getLocation())))
@@ -730,7 +758,9 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
- checkUndefinedInternals(*this);
+ if (ExternalSource)
+ ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
+ checkUndefinedButUsed(*this);
}
if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
@@ -809,13 +839,13 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// eliminnated. If it truly cannot be (for example, there is some reentrancy
// issue I am not seeing yet), then there should at least be a clarifying
// comment somewhere.
- if (llvm::Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
+ if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
switch (DiagnosticIDs::getDiagnosticSFINAEResponse(
Diags.getCurrentDiagID())) {
case DiagnosticIDs::SFINAE_Report:
// We'll report the diagnostic below.
break;
-
+
case DiagnosticIDs::SFINAE_SubstitutionFailure:
// Count this failure so that we know that template argument deduction
// has failed.
@@ -832,13 +862,13 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
Diags.setLastDiagnosticIgnored();
Diags.Clear();
return;
-
+
case DiagnosticIDs::SFINAE_AccessControl: {
// Per C++ Core Issue 1170, access control is part of SFINAE.
// Additionally, the AccessCheckingSFINAE flag can be used to temporarily
// make access control a part of SFINAE for the purposes of checking
// type traits.
- if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus0x)
+ if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus11)
break;
SourceLocation Loc = Diags.getCurrentDiagLoc();
@@ -882,10 +912,10 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
return;
}
}
-
+
// Set up the context's printing policy based on our current state.
Context.setPrintingPolicy(getPrintingPolicy());
-
+
// Emit the diagnostic.
if (!Diags.EmitCurrentDiagnostic())
return;
@@ -944,10 +974,10 @@ bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) {
/// \returns The scope corresponding to the given declaraion context, or NULL
/// if no such scope is open.
Scope *Sema::getScopeForContext(DeclContext *Ctx) {
-
+
if (!Ctx)
return 0;
-
+
Ctx = Ctx->getPrimaryContext();
for (Scope *S = getCurScope(); S; S = S->getParent()) {
// Ignore scopes that cannot have declarations. This is important for
@@ -957,7 +987,7 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) {
if (Ctx == Entity->getPrimaryContext())
return S;
}
-
+
return 0;
}
@@ -970,7 +1000,7 @@ void Sema::PushFunctionScope() {
FunctionScopes.push_back(FunctionScopes.back());
return;
}
-
+
FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
}
@@ -979,7 +1009,7 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
-void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
+void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
CXXMethodDecl *CallOperator) {
FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda,
CallOperator));
@@ -987,9 +1017,9 @@ void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
const Decl *D, const BlockExpr *blkExpr) {
- FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
+ FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
-
+
// Issue any analysis-based warnings.
if (WP && D)
AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
@@ -1028,15 +1058,15 @@ bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
BlockScopeInfo *Sema::getCurBlock() {
if (FunctionScopes.empty())
return 0;
-
- return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+
+ return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
}
LambdaScopeInfo *Sema::getCurLambda() {
if (FunctionScopes.empty())
return 0;
-
- return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+
+ return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
}
void Sema::ActOnComment(SourceRange Comment) {
@@ -1071,7 +1101,11 @@ ExternalSemaSource::~ExternalSemaSource() {}
void ExternalSemaSource::ReadMethodPool(Selector Sel) { }
void ExternalSemaSource::ReadKnownNamespaces(
- SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+}
+
+void ExternalSemaSource::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) {
}
void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
@@ -1248,7 +1282,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// actually a CallExpr.
SourceLocation ParenInsertionLoc =
PP.getLocForEndOfToken(Range.getEnd());
- Diag(Loc, PD)
+ Diag(Loc, PD)
<< /*zero-arg*/ 1 << Range
<< (IsCallableWithAppend(E.get())
? FixItHint::CreateInsertion(ParenInsertionLoc, "()")
@@ -1269,3 +1303,9 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
E = ExprError();
return true;
}
+
+IdentifierInfo *Sema::getSuperIdentifier() const {
+ if (!Ident_super)
+ Ident_super = &Context.Idents.get("super");
+ return Ident_super;
+}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 58b1a51ae573..79a9d3c9fdc7 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -12,9 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DelayedDiagnostic.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
@@ -22,6 +19,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
using namespace clang;
using namespace sema;
@@ -217,6 +217,15 @@ struct AccessTarget : public AccessedEntity {
return DeclaringClass;
}
+ /// The "effective" naming class is the canonical non-anonymous
+ /// class containing the actual naming class.
+ const CXXRecordDecl *getEffectiveNamingClass() const {
+ const CXXRecordDecl *namingClass = getNamingClass();
+ while (namingClass->isAnonymousStructOrUnion())
+ namingClass = cast<CXXRecordDecl>(namingClass->getParent());
+ return namingClass->getCanonicalDecl();
+ }
+
private:
void initialize() {
HasInstanceContext = (isMemberAccess() &&
@@ -1023,8 +1032,7 @@ static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
assert(Target.isMemberAccess());
- const CXXRecordDecl *NamingClass = Target.getNamingClass();
- NamingClass = NamingClass->getCanonicalDecl();
+ const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
for (EffectiveContext::record_iterator
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
@@ -1089,129 +1097,173 @@ static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
return false;
}
+/// We are unable to access a given declaration due to its direct
+/// access control; diagnose that.
+static void diagnoseBadDirectAccess(Sema &S,
+ const EffectiveContext &EC,
+ AccessTarget &entity) {
+ assert(entity.isMemberAccess());
+ NamedDecl *D = entity.getTargetDecl();
+
+ if (D->getAccess() == AS_protected &&
+ TryDiagnoseProtectedAccess(S, EC, entity))
+ return;
+
+ // Find an original declaration.
+ while (D->isOutOfLine()) {
+ NamedDecl *PrevDecl = 0;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ PrevDecl = VD->getPreviousDecl();
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ PrevDecl = FD->getPreviousDecl();
+ else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
+ PrevDecl = TND->getPreviousDecl();
+ else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
+ break;
+ PrevDecl = TD->getPreviousDecl();
+ }
+ if (!PrevDecl) break;
+ D = PrevDecl;
+ }
+
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+ Decl *ImmediateChild;
+ if (D->getDeclContext() == DeclaringClass)
+ ImmediateChild = D;
+ else {
+ DeclContext *DC = D->getDeclContext();
+ while (DC->getParent() != DeclaringClass)
+ DC = DC->getParent();
+ ImmediateChild = cast<Decl>(DC);
+ }
+
+ // 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)) {
+ isImplicit = false;
+ break;
+ }
+ }
+
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (D->getAccess() == AS_protected)
+ << isImplicit;
+}
+
/// Diagnose the path which caused the given declaration or base class
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
- AccessTarget &Entity) {
- AccessSpecifier Access = Entity.getAccess();
+ AccessTarget &entity) {
+ // Save the instance context to preserve invariants.
+ AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
- NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
- const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
+ // This basically repeats the main algorithm but keeps some more
+ // information.
- // Easy case: the decl's natural access determined its path access.
- // We have to check against AS_private here in case Access is AS_none,
- // indicating a non-public member of a private base class.
- if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
- switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) {
- case AR_inaccessible: {
- if (Access == AS_protected &&
- TryDiagnoseProtectedAccess(S, EC, Entity))
- return;
-
- // Find an original declaration.
- while (D->isOutOfLine()) {
- NamedDecl *PrevDecl = 0;
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- PrevDecl = VD->getPreviousDecl();
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- PrevDecl = FD->getPreviousDecl();
- else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
- PrevDecl = TND->getPreviousDecl();
- else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
- break;
- PrevDecl = TD->getPreviousDecl();
- }
- if (!PrevDecl) break;
- D = PrevDecl;
- }
+ // The natural access so far.
+ AccessSpecifier accessSoFar = AS_public;
- CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
- Decl *ImmediateChild;
- if (D->getDeclContext() == DeclaringClass)
- ImmediateChild = D;
- else {
- DeclContext *DC = D->getDeclContext();
- while (DC->getParent() != DeclaringClass)
- DC = DC->getParent();
- ImmediateChild = cast<Decl>(DC);
- }
-
- // Check whether there's an AccessSpecDecl preceding this in the
- // chain of the DeclContext.
- bool Implicit = true;
- for (CXXRecordDecl::decl_iterator
- I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end();
- I != E; ++I) {
- if (*I == ImmediateChild) break;
- if (isa<AccessSpecDecl>(*I)) {
- Implicit = false;
- break;
- }
- }
+ // Check whether we have special rights to the declaring class.
+ if (entity.isMemberAccess()) {
+ NamedDecl *D = entity.getTargetDecl();
+ accessSoFar = D->getAccess();
+ const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
- S.Diag(D->getLocation(), diag::note_access_natural)
- << (unsigned) (Access == AS_protected)
- << Implicit;
- return;
- }
+ switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
+ // If the declaration is accessible when named in its declaring
+ // class, then we must be constrained by the path.
+ case AR_accessible:
+ accessSoFar = AS_public;
+ entity.suppressInstanceContext();
+ break;
- case AR_accessible: break;
+ case AR_inaccessible:
+ if (accessSoFar == AS_private ||
+ declaringClass == entity.getEffectiveNamingClass())
+ return diagnoseBadDirectAccess(S, EC, entity);
+ break;
case AR_dependent:
- llvm_unreachable("can't diagnose dependent access failures");
+ llvm_unreachable("cannot diagnose dependent access");
}
}
- CXXBasePaths Paths;
- CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths);
+ CXXBasePaths paths;
+ CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);
+ assert(path.Access != AS_public);
- CXXBasePath::iterator I = Path.end(), E = Path.begin();
- while (I != E) {
- --I;
+ CXXBasePath::iterator i = path.end(), e = path.begin();
+ CXXBasePath::iterator constrainingBase = i;
+ while (i != e) {
+ --i;
- const CXXBaseSpecifier *BS = I->Base;
- AccessSpecifier BaseAccess = BS->getAccessSpecifier();
+ assert(accessSoFar != AS_none && accessSoFar != AS_private);
- // If this is public inheritance, or the derived class is a friend,
- // skip this step.
- if (BaseAccess == AS_public)
- continue;
+ // Is the entity accessible when named in the deriving class, as
+ // modified by the base specifier?
+ const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
+ const CXXBaseSpecifier *base = i->Base;
- switch (GetFriendKind(S, EC, I->Class)) {
- case AR_accessible: continue;
+ // If the access to this base is worse than the access we have to
+ // the declaration, remember it.
+ AccessSpecifier baseAccess = base->getAccessSpecifier();
+ if (baseAccess > accessSoFar) {
+ constrainingBase = i;
+ accessSoFar = baseAccess;
+ }
+
+ switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
case AR_inaccessible: break;
+ case AR_accessible:
+ accessSoFar = AS_public;
+ entity.suppressInstanceContext();
+ constrainingBase = 0;
+ break;
case AR_dependent:
- llvm_unreachable("can't diagnose dependent access failures");
+ llvm_unreachable("cannot diagnose dependent access");
}
- // Check whether this base specifier is the tighest point
- // constraining access. We have to check against AS_private for
- // the same reasons as above.
- if (BaseAccess == AS_private || BaseAccess >= Access) {
-
- // We're constrained by inheritance, but we want to say
- // "declared private here" if we're diagnosing a hierarchy
- // conversion and this is the final step.
- unsigned diagnostic;
- if (D) diagnostic = diag::note_access_constrained_by_path;
- else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
- else diagnostic = diag::note_access_constrained_by_path;
-
- S.Diag(BS->getSourceRange().getBegin(), diagnostic)
- << BS->getSourceRange()
- << (BaseAccess == AS_protected)
- << (BS->getAccessSpecifierAsWritten() == AS_none);
-
- if (D)
- S.Diag(D->getLocation(), diag::note_field_decl);
-
- return;
+ // If this was private inheritance, but we don't have access to
+ // the deriving class, we're done.
+ if (accessSoFar == AS_private) {
+ assert(baseAccess == AS_private);
+ assert(constrainingBase == i);
+ break;
}
}
- llvm_unreachable("access not apparently constrained by path");
+ // If we don't have a constraining base, the access failure must be
+ // due to the original declaration.
+ if (constrainingBase == path.end())
+ return diagnoseBadDirectAccess(S, EC, entity);
+
+ // We're constrained by inheritance, but we want to say
+ // "declared private here" if we're diagnosing a hierarchy
+ // conversion and this is the final step.
+ unsigned diagnostic;
+ if (entity.isMemberAccess() ||
+ constrainingBase + 1 != path.end()) {
+ diagnostic = diag::note_access_constrained_by_path;
+ } else {
+ diagnostic = diag::note_access_natural;
+ }
+
+ const CXXBaseSpecifier *base = constrainingBase->Base;
+
+ S.Diag(base->getSourceRange().getBegin(), diagnostic)
+ << base->getSourceRange()
+ << (base->getAccessSpecifier() == AS_protected)
+ << (base->getAccessSpecifierAsWritten() == AS_none);
+
+ if (entity.isMemberAccess())
+ S.Diag(entity.getTargetDecl()->getLocation(), diag::note_field_decl);
}
static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
@@ -1273,10 +1325,7 @@ static AccessResult IsAccessible(Sema &S,
const EffectiveContext &EC,
AccessTarget &Entity) {
// Determine the actual naming class.
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
- while (NamingClass->isAnonymousStructOrUnion())
- NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
- NamingClass = NamingClass->getCanonicalDecl();
+ const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
AccessSpecifier UnprivilegedAccess = Entity.getAccess();
assert(UnprivilegedAccess != AS_public && "public access not weeded out");
@@ -1317,7 +1366,13 @@ static AccessResult IsAccessible(Sema &S,
FinalAccess = Target->getAccess();
switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
case AR_accessible:
+ // Target is accessible at EC when named in its declaring class.
+ // We can now hill-climb and simply check whether the declaring
+ // class is accessible as a base of the naming class. This is
+ // equivalent to checking the access of a notional public
+ // member with no instance context.
FinalAccess = AS_public;
+ Entity.suppressInstanceContext();
break;
case AR_inaccessible: break;
case AR_dependent: return AR_dependent; // see above
@@ -1325,8 +1380,6 @@ static AccessResult IsAccessible(Sema &S,
if (DeclaringClass == NamingClass)
return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
-
- Entity.suppressInstanceContext();
} else {
FinalAccess = AS_public;
}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index f1154c1a8aeb..e12bbde0d0dd 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -13,11 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -309,7 +309,8 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
if (!VisContext)
return;
- if (isa<NamedDecl>(D) && cast<NamedDecl>(D)->getExplicitVisibility())
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ if (ND && ND->getExplicitVisibility(NamedDecl::VisibilityForValue))
return;
VisStack *Stack = static_cast<VisStack*>(VisContext);
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 15bfd1ce6294..01ac8f7fb62d 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -12,21 +12,21 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Template.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "TypeLocBuilder.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
/// \brief Find the current instantiation that associated with the given type.
-static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
+static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
DeclContext *CurContext) {
if (T.isNull())
return 0;
@@ -34,16 +34,10 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!T->isDependentType())
+ if (!Record->isDependentContext() ||
+ Record->isCurrentInstantiation(CurContext))
return Record;
- // This may be a member of a class template or class template partial
- // specialization. If it's part of the current semantic context, then it's
- // an injected-class-name;
- for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
- if (CurContext->Equals(Record))
- return Record;
-
return 0;
} else if (isa<InjectedClassNameType>(Ty))
return cast<InjectedClassNameType>(Ty)->getDecl();
@@ -84,8 +78,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (!SS.isSet() || SS.isInvalid())
return 0;
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ NestedNameSpecifier *NNS = SS.getScopeRep();
if (NNS->isDependent()) {
// If this nested-name-specifier refers to the current
// instantiation, return its DeclContext.
@@ -164,9 +157,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return NNS->isDependent();
+ return SS.getScopeRep()->isDependent();
}
// \brief Determine whether this C++ scope specifier refers to an
@@ -176,9 +167,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
if (!isDependentScopeSpecifier(SS))
return false;
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return getCurrentInstantiationOf(NNS) == 0;
+ return getCurrentInstantiationOf(SS.getScopeRep()) == 0;
}
/// \brief If the given nested name specifier refers to the current
@@ -269,7 +258,7 @@ bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
/// \brief Determines whether the given declaration is an valid acceptable
/// result for name lookup of a nested-name-specifier.
-bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
+bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
if (!SD)
return false;
@@ -285,13 +274,13 @@ bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
if (T->isDependentType())
return true;
- else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
+ else if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
if (TD->getUnderlyingType()->isRecordType() ||
- (Context.getLangOpts().CPlusPlus0x &&
+ (Context.getLangOpts().CPlusPlus11 &&
TD->getUnderlyingType()->isEnumeralType()))
return true;
} else if (isa<RecordDecl>(SD) ||
- (Context.getLangOpts().CPlusPlus0x && isa<EnumDecl>(SD)))
+ (Context.getLangOpts().CPlusPlus11 && isa<EnumDecl>(SD)))
return true;
return false;
@@ -540,7 +529,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
NamedDecl *SD = Found.getAsSingle<NamedDecl>();
if (isAcceptableNestedNameSpecifier(SD)) {
if (!ObjectType.isNull() && !ObjectTypeSearchedInScope &&
- !getLangOpts().CPlusPlus0x) {
+ !getLangOpts().CPlusPlus11) {
// C++03 [basic.lookup.classref]p4:
// [...] If the name is found in both contexts, the
// class-name-or-namespace-name shall refer to the same entity.
@@ -775,8 +764,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){
// Handle a dependent template specialization for which we cannot resolve
// the template name.
- assert(DTN->getQualifier()
- == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
+ assert(DTN->getQualifier() == SS.getScopeRep());
QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
DTN->getQualifier(),
DTN->getIdentifier(),
@@ -883,8 +871,7 @@ void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr,
bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- NestedNameSpecifier *Qualifier =
- static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ NestedNameSpecifier *Qualifier = SS.getScopeRep();
// There are only two places a well-formed program may qualify a
// declarator: first, when defining a namespace or class member
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index bf25c6178541..e2a408476639 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -15,12 +15,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Sema/Initialization.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
using namespace clang;
@@ -258,7 +259,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.SrcExpr.take(), DestTInfo,
- OpLoc, Parens.getEnd()));
+ OpLoc, Parens.getEnd(),
+ AngleBrackets));
case tok::kw_dynamic_cast: {
if (!TypeDependent) {
@@ -269,7 +271,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return Op.complete(CXXDynamicCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
&Op.BasePath, DestTInfo,
- OpLoc, Parens.getEnd()));
+ OpLoc, Parens.getEnd(),
+ AngleBrackets));
}
case tok::kw_reinterpret_cast: {
if (!TypeDependent) {
@@ -280,7 +283,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
0, DestTInfo, OpLoc,
- Parens.getEnd()));
+ Parens.getEnd(),
+ AngleBrackets));
}
case tok::kw_static_cast: {
if (!TypeDependent) {
@@ -292,7 +296,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
&Op.BasePath, DestTInfo,
- OpLoc, Parens.getEnd()));
+ OpLoc, Parens.getEnd(),
+ AngleBrackets));
}
}
}
@@ -678,6 +683,98 @@ void CastOperation::CheckConstCast() {
<< SrcExpr.get()->getType() << DestType << OpRange;
}
+/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
+/// or downcast between respective pointers or references.
+static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
+ QualType DestType,
+ SourceRange OpRange) {
+ QualType SrcType = SrcExpr->getType();
+ // When casting from pointer or reference, get pointee type; use original
+ // type otherwise.
+ const CXXRecordDecl *SrcPointeeRD = SrcType->getPointeeCXXRecordDecl();
+ const CXXRecordDecl *SrcRD =
+ SrcPointeeRD ? SrcPointeeRD : SrcType->getAsCXXRecordDecl();
+
+ // Examining subobjects for records is only possible if the complete and
+ // valid definition is available. Also, template instantiation is not
+ // allowed here.
+ if (!SrcRD || !SrcRD->isCompleteDefinition() || SrcRD->isInvalidDecl())
+ return;
+
+ const CXXRecordDecl *DestRD = DestType->getPointeeCXXRecordDecl();
+
+ if (!DestRD || !DestRD->isCompleteDefinition() || DestRD->isInvalidDecl())
+ return;
+
+ enum {
+ ReinterpretUpcast,
+ ReinterpretDowncast
+ } ReinterpretKind;
+
+ CXXBasePaths BasePaths;
+
+ if (SrcRD->isDerivedFrom(DestRD, BasePaths))
+ ReinterpretKind = ReinterpretUpcast;
+ else if (DestRD->isDerivedFrom(SrcRD, BasePaths))
+ ReinterpretKind = ReinterpretDowncast;
+ else
+ return;
+
+ bool VirtualBase = true;
+ bool NonZeroOffset = false;
+ for (CXXBasePaths::const_paths_iterator I = BasePaths.begin(),
+ E = BasePaths.end();
+ I != E; ++I) {
+ const CXXBasePath &Path = *I;
+ CharUnits Offset = CharUnits::Zero();
+ bool IsVirtual = false;
+ for (CXXBasePath::const_iterator IElem = Path.begin(), EElem = Path.end();
+ IElem != EElem; ++IElem) {
+ IsVirtual = IElem->Base->isVirtual();
+ if (IsVirtual)
+ break;
+ const CXXRecordDecl *BaseRD = IElem->Base->getType()->getAsCXXRecordDecl();
+ assert(BaseRD && "Base type should be a valid unqualified class type");
+ // Don't check if any base has invalid declaration or has no definition
+ // since it has no layout info.
+ const CXXRecordDecl *Class = IElem->Class,
+ *ClassDefinition = Class->getDefinition();
+ if (Class->isInvalidDecl() || !ClassDefinition ||
+ !ClassDefinition->isCompleteDefinition())
+ return;
+
+ const ASTRecordLayout &DerivedLayout =
+ Self.Context.getASTRecordLayout(Class);
+ Offset += DerivedLayout.getBaseClassOffset(BaseRD);
+ }
+ if (!IsVirtual) {
+ // Don't warn if any path is a non-virtually derived base at offset zero.
+ if (Offset.isZero())
+ return;
+ // Offset makes sense only for non-virtual bases.
+ else
+ NonZeroOffset = true;
+ }
+ VirtualBase = VirtualBase && IsVirtual;
+ }
+
+ assert((VirtualBase || NonZeroOffset) &&
+ "Should have returned if has non-virtual base with zero offset");
+
+ QualType BaseType =
+ ReinterpretKind == ReinterpretUpcast? DestType : SrcType;
+ QualType DerivedType =
+ ReinterpretKind == ReinterpretUpcast? SrcType : DestType;
+
+ SourceLocation BeginLoc = OpRange.getBegin();
+ Self.Diag(BeginLoc, diag::warn_reinterpret_different_from_static)
+ << DerivedType << BaseType << !VirtualBase << ReinterpretKind
+ << OpRange;
+ Self.Diag(BeginLoc, diag::note_reinterpret_updowncast_use_static)
+ << ReinterpretKind
+ << FixItHint::CreateReplacement(BeginLoc, "static_cast");
+}
+
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
/// valid.
/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
@@ -710,8 +807,10 @@ void CastOperation::CheckReinterpretCast() {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(),
DestType, /*listInitialization=*/false);
}
- } else if (tcr == TC_Success && Self.getLangOpts().ObjCAutoRefCount) {
- checkObjCARCConversion(Sema::CCK_OtherCast);
+ } else if (tcr == TC_Success) {
+ if (Self.getLangOpts().ObjCAutoRefCount)
+ checkObjCARCConversion(Sema::CCK_OtherCast);
+ DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
}
}
@@ -1479,6 +1578,8 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
QualType DestType) {
QualType SrcType = SrcExpr.get()->getType();
+ if (Self.Context.hasSameType(SrcType, DestType))
+ return;
if (const PointerType *SrcPtrTy = SrcType->getAs<PointerType>())
if (SrcPtrTy->isObjCSelType()) {
QualType DT = DestType;
@@ -1773,7 +1874,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// FIXME: Conditionally-supported behavior should be configurable in the
// TargetInfo or similar.
Self.Diag(OpRange.getBegin(),
- Self.getLangOpts().CPlusPlus0x ?
+ Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
return TC_Success;
@@ -1782,7 +1883,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (DestType->isFunctionPointerType()) {
// See above.
Self.Diag(OpRange.getBegin(),
- Self.getLangOpts().CPlusPlus0x ?
+ Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
return TC_Success;
@@ -2102,6 +2203,15 @@ void CastOperation::CheckCStyleCast() {
}
}
+ if (Self.getLangOpts().OpenCL && !Self.getOpenCLOptions().cl_khr_fp16) {
+ if (DestType->isHalfType()) {
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::err_opencl_cast_to_half)
+ << DestType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
// ARC imposes extra restrictions on casts.
if (Self.getLangOpts().ObjCAutoRefCount) {
checkObjCARCConversion(Sema::CCK_CStyleCast);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 692a210ef304..4e11b3aa7920 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -12,32 +12,31 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/ConvertUTF.h"
#include <limits>
using namespace clang;
using namespace sema;
@@ -488,8 +487,8 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
/// 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, Expr **Args,
- unsigned NumArgs,
+void Sema::checkCall(NamedDecl *FDecl,
+ ArrayRef<const Expr *> Args,
unsigned NumProtoArgs,
bool IsMemberFunction,
SourceLocation Loc,
@@ -503,41 +502,40 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
for (specific_attr_iterator<FormatAttr>
I = FDecl->specific_attr_begin<FormatAttr>(),
E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
- if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, CallType,
- Loc, Range))
+ if (CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, Range))
HandledFormatString = true;
// Refuse POD arguments that weren't caught by the format string
// checks above.
if (!HandledFormatString && CallType != VariadicDoesNotApply)
- for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < Args.size(); ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
- if (Expr *Arg = Args[ArgIdx])
+ if (const Expr *Arg = Args[ArgIdx])
variadicArgumentPODCheck(Arg, CallType);
}
for (specific_attr_iterator<NonNullAttr>
I = FDecl->specific_attr_begin<NonNullAttr>(),
E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
- CheckNonNullArguments(*I, Args, Loc);
+ CheckNonNullArguments(*I, 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);
+ CheckArgumentWithTypeTag(*i, Args.data());
}
}
/// CheckConstructorCall - Check a constructor call for correctness and safety
/// properties not enforced by the C type system.
-void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
- unsigned NumArgs,
+void Sema::CheckConstructorCall(FunctionDecl *FDecl,
+ ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto,
SourceLocation Loc) {
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
- checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(),
+ checkCall(FDecl, Args, Proto->getNumArgs(),
/*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
}
@@ -561,7 +559,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
++Args;
--NumArgs;
}
- checkCall(FDecl, Args, NumArgs, NumProtoArgs,
+ checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
+ NumProtoArgs,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -591,7 +590,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
VariadicCallType CallType =
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
- checkCall(Method, Args, NumArgs, Method->param_size(),
+ checkCall(Method, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
+ Method->param_size(),
/*IsMemberFunction=*/false,
lbrac, Method->getSourceRange(), CallType);
@@ -612,7 +612,9 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
- checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
+ checkCall(NDecl,
+ llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
+ TheCall->getNumArgs()),
NumProtoArgs, /*IsMemberFunction=*/false,
TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -1646,8 +1648,8 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
// format string, we will usually need to emit a warning.
// True string literals are then checked by CheckFormatString.
Sema::StringLiteralCheckType
-Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
- unsigned NumArgs, bool HasVAListArg,
+Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
+ bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
FormatStringType Type, VariadicCallType CallType,
bool inFunctionCall) {
@@ -1672,13 +1674,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
const AbstractConditionalOperator *C =
cast<AbstractConditionalOperator>(E);
StringLiteralCheckType Left =
- checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
+ checkFormatStringExpr(C->getTrueExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
if (Left == SLCT_NotALiteral)
return SLCT_NotALiteral;
StringLiteralCheckType Right =
- checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
+ checkFormatStringExpr(C->getFalseExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
return Left < Right ? Left : Right;
@@ -1729,7 +1731,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
if (InitList->isStringLiteralInit())
Init = InitList->getInit(0)->IgnoreParenImpCasts();
}
- return checkFormatStringExpr(Init, Args, NumArgs,
+ return checkFormatStringExpr(Init, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
/*inFunctionCall*/false);
@@ -1787,7 +1789,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return checkFormatStringExpr(Arg, Args, NumArgs,
+ return checkFormatStringExpr(Arg, Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
@@ -1795,7 +1797,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(Arg, Args, NumArgs,
+ return checkFormatStringExpr(Arg, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
inFunctionCall);
@@ -1815,7 +1817,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
StrE = cast<StringLiteral>(E);
if (StrE) {
- CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
+ CheckFormatString(StrE, E, Args, HasVAListArg, format_idx,
firstDataArg, Type, inFunctionCall, CallType);
return SLCT_CheckedLiteral;
}
@@ -1836,8 +1838,20 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
e = NonNull->args_end();
i != e; ++i) {
const Expr *ArgExpr = ExprArgs[*i];
- if (ArgExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNotNull))
+
+ // 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();
}
}
@@ -1856,25 +1870,26 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
/// CheckFormatArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
/// Returns true if a format string has been fully checked.
-bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
- unsigned NumArgs, bool IsCXXMember,
+bool Sema::CheckFormatArguments(const FormatAttr *Format,
+ ArrayRef<const Expr *> Args,
+ bool IsCXXMember,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
FormatStringInfo FSI;
if (getFormatStringInfo(Format, IsCXXMember, &FSI))
- return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
+ return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format),
CallType, Loc, Range);
return false;
}
-bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
+bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
// CHECK: printf/scanf-like function is called with no format string.
- if (format_idx >= NumArgs) {
+ if (format_idx >= Args.size()) {
Diag(Loc, diag::warn_missing_format_string) << Range;
return false;
}
@@ -1894,7 +1909,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
StringLiteralCheckType CT =
- checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ checkFormatStringExpr(OrigFormatExpr, Args, HasVAListArg,
format_idx, firstDataArg, Type, CallType);
if (CT != SLCT_NotALiteral)
// Literal format string found, check done!
@@ -1915,7 +1930,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (NumArgs == format_idx+1)
+ if (Args.size() == format_idx+1)
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
@@ -1936,8 +1951,7 @@ protected:
const unsigned NumDataArgs;
const char *Beg; // Start of format string.
const bool HasVAListArg;
- const Expr * const *Args;
- const unsigned NumArgs;
+ ArrayRef<const Expr *> Args;
unsigned FormatIdx;
llvm::BitVector CoveredArgs;
bool usesPositionalArgs;
@@ -1948,13 +1962,13 @@ public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
- Expr **args, unsigned numArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType callType)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
Beg(beg), HasVAListArg(hasVAListArg),
- Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
+ Args(Args), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall), CallType(callType) {
CoveredArgs.resize(numDataArgs);
@@ -2066,7 +2080,7 @@ void CheckFormatHandler::HandleInvalidLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
getLocationOfByte(LM.getStart()),
@@ -2099,7 +2113,7 @@ void CheckFormatHandler::HandleNonStandardLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< LM.toString() << 0,
@@ -2126,7 +2140,7 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier(
using namespace analyze_format_string;
// See if we know how to fix this conversion specifier.
- llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
if (FixedCS) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< CS.toString() << /*conversion specifier*/1,
@@ -2346,11 +2360,11 @@ public:
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjC,
const char *beg, bool hasVAListArg,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, NumArgs,
+ numDataArgs, beg, hasVAListArg, Args,
formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
{}
@@ -2690,12 +2704,24 @@ static bool requiresParensToAddCast(const Expr *E) {
switch (Inside->getStmtClass()) {
case Stmt::ArraySubscriptExprClass:
case Stmt::CallExprClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXBoolLiteralExprClass:
case Stmt::DeclRefExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::IntegerLiteralClass:
case Stmt::MemberExprClass:
+ case Stmt::ObjCArrayLiteralClass:
+ case Stmt::ObjCBoolLiteralExprClass:
+ case Stmt::ObjCBoxedExprClass:
+ case Stmt::ObjCDictionaryLiteralClass:
+ case Stmt::ObjCEncodeExprClass:
case Stmt::ObjCIvarRefExprClass:
case Stmt::ObjCMessageExprClass:
case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCSubscriptRefExprClass:
case Stmt::ParenExprClass:
+ case Stmt::StringLiteralClass:
case Stmt::UnaryOperatorClass:
return false;
default:
@@ -2717,8 +2743,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (!AT.isValid())
return true;
- QualType IntendedTy = E->getType();
- if (AT.matchesType(S.Context, IntendedTy))
+ QualType ExprTy = E->getType();
+ if (AT.matchesType(S.Context, ExprTy))
return true;
// Look through argument promotions for our error message's reported type.
@@ -2729,7 +2755,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getCastKind() == CK_IntegralCast ||
ICE->getCastKind() == CK_FloatingCast) {
E = ICE->getSubExpr();
- IntendedTy = E->getType();
+ ExprTy = E->getType();
// Check if we didn't match because of an implicit cast from a 'char'
// or 'short' to an 'int'. This is done because printf is a varargs
@@ -2737,22 +2763,63 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
// All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, IntendedTy))
+ if (AT.matchesType(S.Context, ExprTy))
return true;
}
}
+ } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
+ // Special case for 'a', which has type 'int' in C.
+ // Note, however, that we do /not/ want to treat multibyte constants like
+ // 'MooV' as characters! This form is deprecated but still exists.
+ if (ExprTy == S.Context.IntTy)
+ if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue()))
+ ExprTy = S.Context.CharTy;
+ }
+
+ // %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.
+ QualType IntendedTy = ExprTy;
+ if (ObjCContext &&
+ FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
+ if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
+ !ExprTy->isCharType()) {
+ // 'unichar' is defined as a typedef of unsigned short, but we should
+ // prefer using the typedef if it is visible.
+ IntendedTy = S.Context.UnsignedShortTy;
+
+ LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getLocStart(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(Result, S.getCurScope())) {
+ NamedDecl *ND = Result.getFoundDecl();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
+ if (TD->getUnderlyingType() == IntendedTy)
+ IntendedTy = S.Context.getTypedefType(TD);
+ }
+ }
}
+ // Special-case some of Darwin's platform-independence types by suggesting
+ // casts to primitive types that are known to be large enough.
+ bool ShouldNotPrintDirectly = false;
if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
- // Special-case some of Darwin's platform-independence types.
- if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) {
+ // Use a 'while' to peel off layers of typedefs.
+ QualType TyTy = IntendedTy;
+ while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
- IntendedTy = llvm::StringSwitch<QualType>(Name)
+ QualType CastTy = llvm::StringSwitch<QualType>(Name)
.Case("NSInteger", S.Context.LongTy)
.Case("NSUInteger", S.Context.UnsignedLongTy)
.Case("SInt32", S.Context.IntTy)
.Case("UInt32", S.Context.UnsignedIntTy)
- .Default(IntendedTy);
+ .Default(QualType());
+
+ if (!CastTy.isNull()) {
+ ShouldNotPrintDirectly = true;
+ IntendedTy = CastTy;
+ break;
+ }
+ TyTy = UserTy->desugar();
}
}
@@ -2769,7 +2836,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
- if (IntendedTy != E->getType()) {
+ if (IntendedTy == ExprTy) {
+ // 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
+ << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/false,
+ SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
+
+ } else {
// The canonical type for formatting this value is different from the
// actual type of the expression. (This occurs, for example, with Darwin's
// NSInteger on 32-bit platforms, where it is typedef'd as 'int', but
@@ -2807,26 +2886,28 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
}
- // We extract the name from the typedef because we don't want to show
- // the underlying type in the diagnostic.
- const TypedefType *UserTy = cast<TypedefType>(E->getType());
- StringRef Name = UserTy->getDecl()->getName();
-
- // Finally, emit the diagnostic.
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
- << Name << IntendedTy
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation=*/false,
- SpecRange, Hints);
- } else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << IntendedTy
- << E->getSourceRange(),
- E->getLocStart(),
- /*IsStringLocation*/false,
- SpecRange,
- FixItHint::CreateReplacement(SpecRange, os.str()));
+ if (ShouldNotPrintDirectly) {
+ // The expression has a type that should not be printed directly.
+ // We extract the name from the typedef because we don't want to show
+ // the underlying type in the diagnostic.
+ StringRef Name = cast<TypedefType>(ExprTy)->getDecl()->getName();
+
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
+ << Name << IntendedTy
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation=*/false,
+ SpecRange, Hints);
+ } else {
+ // In this case, the expression could be printed using a different
+ // 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
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false,
+ SpecRange, Hints);
+ }
}
} else {
const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
@@ -2834,17 +2915,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Since the warning for passing non-POD types to variadic functions
// was deferred until now, we emit a warning for non-POD
// arguments here.
- if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
+ if (S.isValidVarArgType(ExprTy) == Sema::VAK_Invalid) {
unsigned DiagKind;
- if (E->getType()->isObjCObjectType())
+ if (ExprTy->isObjCObjectType())
DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
else
DiagKind = diag::warn_non_pod_vararg_with_format_string;
EmitFormatDiagnostic(
S.PDiag(DiagKind)
- << S.getLangOpts().CPlusPlus0x
- << E->getType()
+ << S.getLangOpts().CPlusPlus11
+ << ExprTy
<< CallType
<< AT.getRepresentativeTypeName(S.Context)
<< CSR
@@ -2855,7 +2936,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
} else
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);
@@ -2872,12 +2953,12 @@ public:
CheckScanfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall, CallType)
+ Args, formatIdx, inFunctionCall, CallType)
{}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
@@ -3029,7 +3110,7 @@ bool CheckScanfHandler::HandleScanfSpecifier(
void Sema::CheckFormatString(const StringLiteral *FExpr,
const Expr *OrigFormatExpr,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
bool inFunctionCall, VariadicCallType CallType) {
@@ -3047,7 +3128,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
- const unsigned numDataArgs = NumArgs - firstDataArg;
+ const unsigned numDataArgs = Args.size() - firstDataArg;
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
@@ -3061,7 +3142,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, (Type == FST_NSString),
- Str, HasVAListArg, Args, NumArgs, format_idx,
+ Str, HasVAListArg, Args, format_idx,
inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
@@ -3070,7 +3151,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
H.DoneProcessing();
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
- Str, HasVAListArg, Args, NumArgs, format_idx,
+ Str, HasVAListArg, Args, format_idx,
inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
@@ -3177,7 +3258,8 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
if (UnaryOp->getOpcode() == UO_AddrOf)
ActionIdx = 1; // If its an address-of operator, just remove it.
- if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
+ if (!PointeeTy->isIncompleteType() &&
+ (Context.getTypeSize(PointeeTy) == Context.getCharWidth()))
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
@@ -3922,7 +4004,11 @@ struct IntRange {
unsigned NumPositive = Enum->getNumPositiveBits();
unsigned NumNegative = Enum->getNumNegativeBits();
- return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0);
+ if (NumNegative == 0)
+ return IntRange(NumPositive, true/*NonNegative*/);
+ else
+ return IntRange(std::max(NumPositive + 1, NumNegative),
+ false/*NonNegative*/);
}
const BuiltinType *BT = cast<BuiltinType>(T);
@@ -4328,38 +4414,108 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
Expr *Constant, Expr *Other,
llvm::APSInt Value,
bool RhsConstant) {
+ // 0 values are handled later by CheckTrivialUnsignedComparison().
+ if (Value == 0)
+ 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");
- // FIXME. handle cases for signedness to catch (signed char)N == 200
+
+ bool ConstantSigned = ConstantT->isSignedIntegerType();
+ bool CommonSigned = CommonT->isSignedIntegerType();
+
+ bool EqualityOnly = false;
+
+ // TODO: Investigate using GetExprRange() to get tighter bounds on
+ // on the bit ranges.
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
- IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
- if (OtherRange.Width >= LitRange.Width)
- return;
+ 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;
+ }
+ } 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 { // !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 IsTrue = true;
- if (op == BO_EQ)
- IsTrue = false;
- else if (op == BO_NE)
- IsTrue = true;
- else if (RhsConstant) {
+ 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 = !LitRange.NonNegative;
+ IsTrue = !PositiveConstant;
else // op == BO_LT || op == BO_LE
- IsTrue = LitRange.NonNegative;
+ IsTrue = PositiveConstant;
} else {
if (op == BO_LT || op == BO_LE)
- IsTrue = !LitRange.NonNegative;
+ IsTrue = !PositiveConstant;
else // op == BO_GT || op == BO_GE
- IsTrue = LitRange.NonNegative;
+ IsTrue = PositiveConstant;
}
- SmallString<16> PrettySourceValue(Value.toString(10));
+
+ // If this is a comparison to an enum constant, include that
+ // constant in the diagnostic.
+ const EnumConstantDecl *ED = 0;
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant))
+ ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+ SmallString<64> PrettySourceValue;
+ llvm::raw_svector_ostream OS(PrettySourceValue);
+ if (ED)
+ OS << '\'' << *ED << "' (" << Value << ")";
+ else
+ OS << Value;
+
S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
- << PrettySourceValue << OtherT << IsTrue
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ << OS.str() << OtherT << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
}
/// Analyze the operands of the given comparison. Implements the
@@ -4800,7 +4956,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
== Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
&& !Target->isBlockPointerType() && !Target->isMemberPointerType()
- && Target->isScalarType()) {
+ && Target->isScalarType() && !Target->isNullPtrType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
@@ -4843,7 +4999,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// People want to build with -Wshorten-64-to-32 and not -Wconversion.
if (S.SourceMgr.isInSystemMacro(CC))
return;
-
+
if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64)
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32,
/* pruneControlFlow */ true);
@@ -4887,10 +5043,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (const EnumType *SourceEnum = Source->getAs<EnumType>())
if (const EnumType *TargetEnum = Target->getAs<EnumType>())
- if ((SourceEnum->getDecl()->getIdentifier() ||
- SourceEnum->getDecl()->getTypedefNameForAnonDecl()) &&
- (TargetEnum->getDecl()->getIdentifier() ||
- TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
+ if (SourceEnum->getDecl()->hasNameForLinkage() &&
+ TargetEnum->getDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -5046,6 +5200,462 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
AnalyzeImplicitConversions(*this, E, CC);
}
+/// Diagnose when expression is an integer constant expression and its evaluation
+/// results in integer overflow
+void Sema::CheckForIntOverflow (Expr *E) {
+ if (isa<BinaryOperator>(E->IgnoreParens())) {
+ llvm::SmallVector<PartialDiagnosticAt, 4> Diags;
+ E->EvaluateForOverflow(Context, &Diags);
+ }
+}
+
+namespace {
+/// \brief Visitor for expressions which looks for unsequenced operations on the
+/// same object.
+class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
+ /// \brief A tree of sequenced regions within an expression. Two regions are
+ /// unsequenced if one is an ancestor or a descendent of the other. When we
+ /// finish processing an expression with sequencing, such as a comma
+ /// expression, we fold its tree nodes into its parent, since they are
+ /// unsequenced with respect to nodes we will visit later.
+ class SequenceTree {
+ struct Value {
+ explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {}
+ unsigned Parent : 31;
+ bool Merged : 1;
+ };
+ llvm::SmallVector<Value, 8> Values;
+
+ public:
+ /// \brief A region within an expression which may be sequenced with respect
+ /// to some other region.
+ class Seq {
+ explicit Seq(unsigned N) : Index(N) {}
+ unsigned Index;
+ friend class SequenceTree;
+ public:
+ Seq() : Index(0) {}
+ };
+
+ SequenceTree() { Values.push_back(Value(0)); }
+ Seq root() const { return Seq(0); }
+
+ /// \brief Create a new sequence of operations, which is an unsequenced
+ /// subset of \p Parent. This sequence of operations is sequenced with
+ /// respect to other children of \p Parent.
+ Seq allocate(Seq Parent) {
+ Values.push_back(Value(Parent.Index));
+ return Seq(Values.size() - 1);
+ }
+
+ /// \brief Merge a sequence of operations into its parent.
+ void merge(Seq S) {
+ Values[S.Index].Merged = true;
+ }
+
+ /// \brief Determine whether two operations are unsequenced. This operation
+ /// is asymmetric: \p Cur should be the more recent sequence, and \p Old
+ /// should have been merged into its parent as appropriate.
+ bool isUnsequenced(Seq Cur, Seq Old) {
+ unsigned C = representative(Cur.Index);
+ unsigned Target = representative(Old.Index);
+ while (C >= Target) {
+ if (C == Target)
+ return true;
+ C = Values[C].Parent;
+ }
+ return false;
+ }
+
+ private:
+ /// \brief Pick a representative for a sequence.
+ unsigned representative(unsigned K) {
+ if (Values[K].Merged)
+ // Perform path compression as we go.
+ return Values[K].Parent = representative(Values[K].Parent);
+ return K;
+ }
+ };
+
+ /// An object for which we can track unsequenced uses.
+ typedef NamedDecl *Object;
+
+ /// Different flavors of object usage which we track. We only track the
+ /// least-sequenced usage of each kind.
+ enum UsageKind {
+ /// A read of an object. Multiple unsequenced reads are OK.
+ UK_Use,
+ /// A modification of an object which is sequenced before the value
+ /// computation of the expression, such as ++n.
+ UK_ModAsValue,
+ /// A modification of an object which is not sequenced before the value
+ /// computation of the expression, such as n++.
+ UK_ModAsSideEffect,
+
+ UK_Count = UK_ModAsSideEffect + 1
+ };
+
+ struct Usage {
+ Usage() : Use(0), Seq() {}
+ Expr *Use;
+ SequenceTree::Seq Seq;
+ };
+
+ struct UsageInfo {
+ UsageInfo() : Diagnosed(false) {}
+ Usage Uses[UK_Count];
+ /// Have we issued a diagnostic for this variable already?
+ bool Diagnosed;
+ };
+ typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap;
+
+ Sema &SemaRef;
+ /// Sequenced regions within the expression.
+ SequenceTree Tree;
+ /// Declaration modifications and references which we have seen.
+ UsageInfoMap UsageMap;
+ /// The region we are currently within.
+ SequenceTree::Seq Region;
+ /// Filled in with declarations which were modified as a side-effect
+ /// (that is, post-increment operations).
+ llvm::SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect;
+ /// Expressions to check later. We defer checking these to reduce
+ /// stack usage.
+ llvm::SmallVectorImpl<Expr*> &WorkList;
+
+ /// RAII object wrapping the visitation of a sequenced subexpression of an
+ /// expression. At the end of this process, the side-effects of the evaluation
+ /// become sequenced with respect to the value computation of the result, so
+ /// we downgrade any UK_ModAsSideEffect within the evaluation to
+ /// UK_ModAsValue.
+ struct SequencedSubexpression {
+ SequencedSubexpression(SequenceChecker &Self)
+ : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
+ Self.ModAsSideEffect = &ModAsSideEffect;
+ }
+ ~SequencedSubexpression() {
+ for (unsigned I = 0, E = ModAsSideEffect.size(); I != E; ++I) {
+ UsageInfo &U = Self.UsageMap[ModAsSideEffect[I].first];
+ U.Uses[UK_ModAsSideEffect] = ModAsSideEffect[I].second;
+ Self.addUsage(U, ModAsSideEffect[I].first,
+ ModAsSideEffect[I].second.Use, UK_ModAsValue);
+ }
+ Self.ModAsSideEffect = OldModAsSideEffect;
+ }
+
+ SequenceChecker &Self;
+ llvm::SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
+ llvm::SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect;
+ };
+
+ /// \brief Find the object which is produced by the specified expression,
+ /// if any.
+ Object getObject(Expr *E, bool Mod) const {
+ E = E->IgnoreParenCasts();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
+ return getObject(UO->getSubExpr(), Mod);
+ } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ return getObject(BO->getRHS(), Mod);
+ if (Mod && BO->isAssignmentOp())
+ return getObject(BO->getLHS(), Mod);
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ // FIXME: Check for more interesting cases, like "x.n = ++x.n".
+ if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
+ return ME->getMemberDecl();
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ // FIXME: If this is a reference, map through to its value.
+ return DRE->getDecl();
+ return 0;
+ }
+
+ /// \brief Note that an object was modified or used by an expression.
+ void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) {
+ Usage &U = UI.Uses[UK];
+ if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) {
+ if (UK == UK_ModAsSideEffect && ModAsSideEffect)
+ ModAsSideEffect->push_back(std::make_pair(O, U));
+ U.Use = Ref;
+ U.Seq = Region;
+ }
+ }
+ /// \brief Check whether a modification or use conflicts with a prior usage.
+ void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind,
+ bool IsModMod) {
+ if (UI.Diagnosed)
+ return;
+
+ const Usage &U = UI.Uses[OtherKind];
+ if (!U.Use || !Tree.isUnsequenced(Region, U.Seq))
+ return;
+
+ Expr *Mod = U.Use;
+ Expr *ModOrUse = Ref;
+ if (OtherKind == UK_Use)
+ std::swap(Mod, ModOrUse);
+
+ SemaRef.Diag(Mod->getExprLoc(),
+ IsModMod ? diag::warn_unsequenced_mod_mod
+ : diag::warn_unsequenced_mod_use)
+ << O << SourceRange(ModOrUse->getExprLoc());
+ UI.Diagnosed = true;
+ }
+
+ void notePreUse(Object O, Expr *Use) {
+ UsageInfo &U = UsageMap[O];
+ // Uses conflict with other modifications.
+ checkUsage(O, U, Use, UK_ModAsValue, false);
+ }
+ void notePostUse(Object O, Expr *Use) {
+ UsageInfo &U = UsageMap[O];
+ checkUsage(O, U, Use, UK_ModAsSideEffect, false);
+ addUsage(U, O, Use, UK_Use);
+ }
+
+ void notePreMod(Object O, Expr *Mod) {
+ UsageInfo &U = UsageMap[O];
+ // Modifications conflict with other modifications and with uses.
+ checkUsage(O, U, Mod, UK_ModAsValue, true);
+ checkUsage(O, U, Mod, UK_Use, false);
+ }
+ void notePostMod(Object O, Expr *Use, UsageKind UK) {
+ UsageInfo &U = UsageMap[O];
+ checkUsage(O, U, Use, UK_ModAsSideEffect, true);
+ addUsage(U, O, Use, UK);
+ }
+
+public:
+ SequenceChecker(Sema &S, Expr *E,
+ llvm::SmallVectorImpl<Expr*> &WorkList)
+ : EvaluatedExprVisitor<SequenceChecker>(S.Context), SemaRef(S),
+ Region(Tree.root()), ModAsSideEffect(0), WorkList(WorkList) {
+ Visit(E);
+ }
+
+ void VisitStmt(Stmt *S) {
+ // Skip all statements which aren't expressions for now.
+ }
+
+ void VisitExpr(Expr *E) {
+ // By default, just recurse to evaluated subexpressions.
+ EvaluatedExprVisitor<SequenceChecker>::VisitStmt(E);
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ Object O = Object();
+ if (E->getCastKind() == CK_LValueToRValue)
+ O = getObject(E->getSubExpr(), false);
+
+ if (O)
+ notePreUse(O, E);
+ VisitExpr(E);
+ if (O)
+ notePostUse(O, E);
+ }
+
+ void VisitBinComma(BinaryOperator *BO) {
+ // C++11 [expr.comma]p1:
+ // Every value computation and side effect associated with the left
+ // expression is sequenced before every value computation and side
+ // effect associated with the right expression.
+ SequenceTree::Seq LHS = Tree.allocate(Region);
+ SequenceTree::Seq RHS = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
+ {
+ SequencedSubexpression SeqLHS(*this);
+ Region = LHS;
+ Visit(BO->getLHS());
+ }
+
+ Region = RHS;
+ Visit(BO->getRHS());
+
+ Region = OldRegion;
+
+ // Forget that LHS and RHS are sequenced. They are both unsequenced
+ // with respect to other stuff.
+ Tree.merge(LHS);
+ Tree.merge(RHS);
+ }
+
+ void VisitBinAssign(BinaryOperator *BO) {
+ // The modification is sequenced after the value computation of the LHS
+ // and RHS, so check it before inspecting the operands and update the
+ // map afterwards.
+ Object O = getObject(BO->getLHS(), true);
+ if (!O)
+ return VisitExpr(BO);
+
+ notePreMod(O, BO);
+
+ // C++11 [expr.ass]p7:
+ // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
+ // only once.
+ //
+ // Therefore, for a compound assignment operator, O is considered used
+ // everywhere except within the evaluation of E1 itself.
+ if (isa<CompoundAssignOperator>(BO))
+ notePreUse(O, BO);
+
+ Visit(BO->getLHS());
+
+ if (isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
+
+ Visit(BO->getRHS());
+
+ notePostMod(O, BO, UK_ModAsValue);
+ }
+ void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
+ VisitBinAssign(CAO);
+ }
+
+ void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreIncDec(UnaryOperator *UO) {
+ Object O = getObject(UO->getSubExpr(), true);
+ if (!O)
+ return VisitExpr(UO);
+
+ notePreMod(O, UO);
+ Visit(UO->getSubExpr());
+ notePostMod(O, UO, UK_ModAsValue);
+ }
+
+ void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostIncDec(UnaryOperator *UO) {
+ Object O = getObject(UO->getSubExpr(), true);
+ if (!O)
+ return VisitExpr(UO);
+
+ notePreMod(O, UO);
+ Visit(UO->getSubExpr());
+ notePostMod(O, UO, UK_ModAsSideEffect);
+ }
+
+ /// Don't visit the RHS of '&&' or '||' if it might not be evaluated.
+ void VisitBinLOr(BinaryOperator *BO) {
+ // The side-effects of the LHS of an '&&' are sequenced before the
+ // value computation of the RHS, and hence before the value computation
+ // of the '&&' itself, unless the LHS evaluates to zero. We treat them
+ // as if they were unconditionally sequenced.
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(BO->getLHS());
+ }
+
+ bool Result;
+ if (!BO->getLHS()->isValueDependent() &&
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (!Result)
+ Visit(BO->getRHS());
+ } else {
+ // Check for unsequenced operations in the RHS, treating it as an
+ // entirely separate evaluation.
+ //
+ // FIXME: If there are operations in the RHS which are unsequenced
+ // with respect to operations outside the RHS, and those operations
+ // are unconditionally evaluated, diagnose them.
+ WorkList.push_back(BO->getRHS());
+ }
+ }
+ void VisitBinLAnd(BinaryOperator *BO) {
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(BO->getLHS());
+ }
+
+ bool Result;
+ if (!BO->getLHS()->isValueDependent() &&
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (Result)
+ Visit(BO->getRHS());
+ } else {
+ WorkList.push_back(BO->getRHS());
+ }
+ }
+
+ // Only visit the condition, unless we can be sure which subexpression will
+ // be chosen.
+ void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
+ SequencedSubexpression Sequenced(*this);
+ Visit(CO->getCond());
+
+ bool Result;
+ if (!CO->getCond()->isValueDependent() &&
+ CO->getCond()->EvaluateAsBooleanCondition(Result, SemaRef.Context))
+ Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr());
+ else {
+ WorkList.push_back(CO->getTrueExpr());
+ WorkList.push_back(CO->getFalseExpr());
+ }
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ if (!CCE->isListInitialization())
+ return VisitExpr(CCE);
+
+ // In C++11, list initializations are sequenced.
+ llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SequenceTree::Seq Parent = Region;
+ for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
+ I != E; ++I) {
+ Region = Tree.allocate(Parent);
+ Elts.push_back(Region);
+ Visit(*I);
+ }
+
+ // Forget that the initializers are sequenced.
+ Region = Parent;
+ for (unsigned I = 0; I < Elts.size(); ++I)
+ Tree.merge(Elts[I]);
+ }
+
+ void VisitInitListExpr(InitListExpr *ILE) {
+ if (!SemaRef.getLangOpts().CPlusPlus11)
+ return VisitExpr(ILE);
+
+ // In C++11, list initializations are sequenced.
+ llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SequenceTree::Seq Parent = Region;
+ for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
+ Expr *E = ILE->getInit(I);
+ if (!E) continue;
+ Region = Tree.allocate(Parent);
+ Elts.push_back(Region);
+ Visit(E);
+ }
+
+ // Forget that the initializers are sequenced.
+ Region = Parent;
+ for (unsigned I = 0; I < Elts.size(); ++I)
+ Tree.merge(Elts[I]);
+ }
+};
+}
+
+void Sema::CheckUnsequencedOperations(Expr *E) {
+ llvm::SmallVector<Expr*, 8> WorkList;
+ WorkList.push_back(E);
+ while (!WorkList.empty()) {
+ Expr *Item = WorkList.back();
+ WorkList.pop_back();
+ SequenceChecker(*this, Item, WorkList);
+ }
+}
+
+void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
+ bool IsConstexpr) {
+ CheckImplicitConversions(E, CheckLoc);
+ CheckUnsequencedOperations(E);
+ if (!IsConstexpr && !E->isValueDependent())
+ CheckForIntOverflow(E);
+}
+
void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
FieldDecl *BitField,
Expr *Init) {
@@ -5091,7 +5701,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
QualType PType = Param->getOriginalType();
if (const ArrayType *AT = Context.getAsArrayType(PType)) {
if (AT->getSizeModifier() == ArrayType::Star) {
- // FIXME: This diagnosic should point the '[*]' if source-location
+ // FIXME: This diagnostic should point the '[*]' if source-location
// information is added for it.
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
@@ -5174,16 +5784,16 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();
// Look through typedefs.
- const TypedefTypeLoc *TTL = dyn_cast<TypedefTypeLoc>(&TL);
- if (TTL) {
- const TypedefNameDecl *TDL = TTL->getTypedefNameDecl();
+ if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
+ const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
TInfo = TDL->getTypeSourceInfo();
continue;
}
- ConstantArrayTypeLoc CTL = cast<ConstantArrayTypeLoc>(TL);
- const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
- if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
- return false;
+ if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ }
break;
}
@@ -5574,7 +6184,7 @@ static bool isSetterLikeSelector(Selector sel) {
return false;
if (str.empty()) return true;
- return !islower(str.front());
+ return !isLowercase(str.front());
}
/// Check a message send to see if it's likely to cause a retain cycle.
@@ -5625,21 +6235,59 @@ void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) {
diagnoseRetainCycle(*this, Capturer, Owner);
}
-bool Sema::checkUnsafeAssigns(SourceLocation Loc,
- QualType LHS, Expr *RHS) {
- Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
- if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
+ Expr *RHS, bool isProperty) {
+ // Check if RHS is an Objective-C object literal, which also can get
+ // immediately zapped in a weak reference. Note that we explicitly
+ // allow ObjCStringLiterals, since those are designed to never really die.
+ RHS = RHS->IgnoreParenImpCasts();
+
+ // This enum needs to match with the 'select' in
+ // warn_objc_arc_literal_assign (off-by-1).
+ Sema::ObjCLiteralKind Kind = S.CheckLiteralKind(RHS);
+ if (Kind == Sema::LK_String || Kind == Sema::LK_None)
return false;
- // strip off any implicit cast added to get to the one arc-specific
+
+ S.Diag(Loc, diag::warn_arc_literal_assign)
+ << (unsigned) Kind
+ << (isProperty ? 0 : 1)
+ << RHS->getSourceRange();
+
+ return true;
+}
+
+static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
+ Qualifiers::ObjCLifetime LT,
+ Expr *RHS, bool isProperty) {
+ // Strip off any implicit cast added to get to the one ARC-specific.
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
- Diag(Loc, diag::warn_arc_retained_assign)
- << (LT == Qualifiers::OCL_ExplicitNone) << 1
+ S.Diag(Loc, diag::warn_arc_retained_assign)
+ << (LT == Qualifiers::OCL_ExplicitNone)
+ << (isProperty ? 0 : 1)
<< RHS->getSourceRange();
return true;
}
RHS = cast->getSubExpr();
}
+
+ if (LT == Qualifiers::OCL_Weak &&
+ checkUnsafeAssignLiteral(S, Loc, RHS, isProperty))
+ return true;
+
+ return false;
+}
+
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
+ QualType LHS, Expr *RHS) {
+ Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+
+ if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+ return false;
+
+ if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false))
+ return true;
+
return false;
}
@@ -5702,14 +6350,8 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
}
}
else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) {
- while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
- if (cast->getCastKind() == CK_ARCConsumeObject) {
- Diag(Loc, diag::warn_arc_retained_assign)
- << 0 << 0<< RHS->getSourceRange();
- return;
- }
- RHS = cast->getSubExpr();
- }
+ if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true))
+ return;
}
}
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b1aead8f026d..2db1e2afa26b 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -11,18 +11,19 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Overload.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -45,7 +46,7 @@ namespace {
/// name-lookup routines to specify which declarations should be included in
/// the result set (when it returns true) and which declarations should be
/// filtered out (returns false).
- typedef bool (ResultBuilder::*LookupFilter)(NamedDecl *) const;
+ typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const;
typedef CodeCompletionResult Result;
@@ -56,9 +57,9 @@ namespace {
/// \brief A record of all of the declarations we have found and placed
/// into the result set, used to ensure that no declaration ever gets into
/// the result set twice.
- llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+ llvm::SmallPtrSet<const Decl*, 16> AllDeclsFound;
- typedef std::pair<NamedDecl *, unsigned> DeclIndexPair;
+ typedef std::pair<const NamedDecl *, unsigned> DeclIndexPair;
/// \brief An entry in the shadow map, which is optimized to store
/// a single (declaration, index) mapping (the common case) but
@@ -68,7 +69,7 @@ namespace {
/// \brief Contains either the solitary NamedDecl * or a vector
/// of (declaration, index) pairs.
- llvm::PointerUnion<NamedDecl *, DeclIndexPairVector*> DeclOrVector;
+ llvm::PointerUnion<const NamedDecl *, DeclIndexPairVector*> DeclOrVector;
/// \brief When the entry contains a single declaration, this is
/// the index associated with that entry.
@@ -77,7 +78,7 @@ namespace {
public:
ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) { }
- void Add(NamedDecl *ND, unsigned Index) {
+ void Add(const NamedDecl *ND, unsigned Index) {
if (DeclOrVector.isNull()) {
// 0 - > 1 elements: just set the single element information.
DeclOrVector = ND;
@@ -85,7 +86,8 @@ namespace {
return;
}
- if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
+ if (const NamedDecl *PrevND =
+ DeclOrVector.dyn_cast<const NamedDecl *>()) {
// 1 -> 2 elements: create the vector of results and push in the
// existing declaration.
DeclIndexPairVector *Vec = new DeclIndexPairVector;
@@ -161,7 +163,7 @@ namespace {
/// \brief If we are in an instance method definition, the \@implementation
/// object.
ObjCImplementationDecl *ObjCImplementation;
-
+
void AdjustResultPriorityForDecl(Result &R);
void MaybeAddConstructorResults(Result R);
@@ -195,7 +197,10 @@ namespace {
break;
}
}
-
+
+ /// \brief Determine the priority for a reference to the given declaration.
+ unsigned getBasePriority(const NamedDecl *D);
+
/// \brief Whether we should include code patterns in the completion
/// results.
bool includeCodePatterns() const {
@@ -265,7 +270,8 @@ namespace {
///
/// \param AsNestedNameSpecifier will be set true if this declaration is
/// only interesting when it is a nested-name-specifier.
- bool isInterestingDecl(NamedDecl *ND, bool &AsNestedNameSpecifier) const;
+ bool isInterestingDecl(const NamedDecl *ND,
+ bool &AsNestedNameSpecifier) const;
/// \brief Check whether the result is hidden by the Hiding declaration.
///
@@ -274,7 +280,7 @@ namespace {
/// modified to describe how the result can be found (e.g., via extra
/// qualification).
bool CheckHiddenResult(Result &R, DeclContext *CurContext,
- NamedDecl *Hiding);
+ const NamedDecl *Hiding);
/// \brief Add a new result to this result set (if it isn't already in one
/// of the shadow maps), or replace an existing result (for, e.g., a
@@ -309,7 +315,7 @@ namespace {
void ExitScope();
/// \brief Ignore this declaration, if it is seen again.
- void Ignore(Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }
+ void Ignore(const Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }
/// \name Name lookup predicates
///
@@ -317,29 +323,29 @@ namespace {
/// results of name lookup. All of the predicates have the same type, so that
///
//@{
- bool IsOrdinaryName(NamedDecl *ND) const;
- bool IsOrdinaryNonTypeName(NamedDecl *ND) const;
- bool IsIntegralConstantValue(NamedDecl *ND) const;
- bool IsOrdinaryNonValueName(NamedDecl *ND) const;
- bool IsNestedNameSpecifier(NamedDecl *ND) const;
- bool IsEnum(NamedDecl *ND) const;
- bool IsClassOrStruct(NamedDecl *ND) const;
- bool IsUnion(NamedDecl *ND) const;
- bool IsNamespace(NamedDecl *ND) const;
- bool IsNamespaceOrAlias(NamedDecl *ND) const;
- bool IsType(NamedDecl *ND) const;
- bool IsMember(NamedDecl *ND) const;
- bool IsObjCIvar(NamedDecl *ND) const;
- bool IsObjCMessageReceiver(NamedDecl *ND) const;
- bool IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const;
- bool IsObjCCollection(NamedDecl *ND) const;
- bool IsImpossibleToSatisfy(NamedDecl *ND) const;
+ bool IsOrdinaryName(const NamedDecl *ND) const;
+ bool IsOrdinaryNonTypeName(const NamedDecl *ND) const;
+ bool IsIntegralConstantValue(const NamedDecl *ND) const;
+ bool IsOrdinaryNonValueName(const NamedDecl *ND) const;
+ bool IsNestedNameSpecifier(const NamedDecl *ND) const;
+ bool IsEnum(const NamedDecl *ND) const;
+ bool IsClassOrStruct(const NamedDecl *ND) const;
+ bool IsUnion(const NamedDecl *ND) const;
+ bool IsNamespace(const NamedDecl *ND) const;
+ bool IsNamespaceOrAlias(const NamedDecl *ND) const;
+ bool IsType(const NamedDecl *ND) const;
+ bool IsMember(const NamedDecl *ND) const;
+ bool IsObjCIvar(const NamedDecl *ND) const;
+ bool IsObjCMessageReceiver(const NamedDecl *ND) const;
+ bool IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const;
+ bool IsObjCCollection(const NamedDecl *ND) const;
+ bool IsImpossibleToSatisfy(const NamedDecl *ND) const;
//@}
};
}
class ResultBuilder::ShadowMapEntry::iterator {
- llvm::PointerUnion<NamedDecl*, const DeclIndexPair*> DeclOrIterator;
+ llvm::PointerUnion<const NamedDecl *, const DeclIndexPair *> DeclOrIterator;
unsigned SingleDeclIndex;
public:
@@ -361,14 +367,14 @@ public:
iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { }
- iterator(NamedDecl *SingleDecl, unsigned Index)
+ iterator(const NamedDecl *SingleDecl, unsigned Index)
: DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { }
iterator(const DeclIndexPair *Iterator)
: DeclOrIterator(Iterator), SingleDeclIndex(0) { }
iterator &operator++() {
- if (DeclOrIterator.is<NamedDecl *>()) {
+ if (DeclOrIterator.is<const NamedDecl *>()) {
DeclOrIterator = (NamedDecl *)0;
SingleDeclIndex = 0;
return *this;
@@ -387,7 +393,7 @@ public:
}*/
reference operator*() const {
- if (NamedDecl *ND = DeclOrIterator.dyn_cast<NamedDecl *>())
+ if (const NamedDecl *ND = DeclOrIterator.dyn_cast<const NamedDecl *>())
return reference(ND, SingleDeclIndex);
return *DeclOrIterator.get<const DeclIndexPair*>();
@@ -413,7 +419,7 @@ ResultBuilder::ShadowMapEntry::begin() const {
if (DeclOrVector.isNull())
return iterator();
- if (NamedDecl *ND = DeclOrVector.dyn_cast<NamedDecl *>())
+ if (const NamedDecl *ND = DeclOrVector.dyn_cast<const NamedDecl *>())
return iterator(ND, SingleDeclIndex);
return iterator(DeclOrVector.get<DeclIndexPairVector *>()->begin());
@@ -421,7 +427,7 @@ ResultBuilder::ShadowMapEntry::begin() const {
ResultBuilder::ShadowMapEntry::iterator
ResultBuilder::ShadowMapEntry::end() const {
- if (DeclOrVector.is<NamedDecl *>() || DeclOrVector.isNull())
+ if (DeclOrVector.is<const NamedDecl *>() || DeclOrVector.isNull())
return iterator();
return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
@@ -442,11 +448,11 @@ ResultBuilder::ShadowMapEntry::end() const {
/// NULL if no qualification is needed.
static NestedNameSpecifier *
getRequiredQualification(ASTContext &Context,
- DeclContext *CurContext,
- DeclContext *TargetContext) {
- SmallVector<DeclContext *, 4> TargetParents;
+ const DeclContext *CurContext,
+ const DeclContext *TargetContext) {
+ SmallVector<const DeclContext *, 4> TargetParents;
- for (DeclContext *CommonAncestor = TargetContext;
+ for (const DeclContext *CommonAncestor = TargetContext;
CommonAncestor && !CommonAncestor->Encloses(CurContext);
CommonAncestor = CommonAncestor->getLookupParent()) {
if (CommonAncestor->isTransparentContext() ||
@@ -458,16 +464,16 @@ getRequiredQualification(ASTContext &Context,
NestedNameSpecifier *Result = 0;
while (!TargetParents.empty()) {
- DeclContext *Parent = TargetParents.back();
+ const DeclContext *Parent = TargetParents.back();
TargetParents.pop_back();
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
if (!Namespace->getIdentifier())
continue;
Result = NestedNameSpecifier::Create(Context, Result, Namespace);
}
- else if (TagDecl *TD = dyn_cast<TagDecl>(Parent))
+ else if (const TagDecl *TD = dyn_cast<TagDecl>(Parent))
Result = NestedNameSpecifier::Create(Context, Result,
false,
Context.getTypeDeclType(TD).getTypePtr());
@@ -475,7 +481,7 @@ getRequiredQualification(ASTContext &Context,
return Result;
}
-bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
+bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
bool &AsNestedNameSpecifier) const {
AsNestedNameSpecifier = false;
@@ -547,14 +553,15 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
}
bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext,
- NamedDecl *Hiding) {
+ const NamedDecl *Hiding) {
// In C, there is no way to refer to a hidden name.
// FIXME: This isn't true; we can find a tag name hidden by an ordinary
// name if we introduce the tag type.
if (!SemaRef.getLangOpts().CPlusPlus)
return true;
- DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getRedeclContext();
+ const DeclContext *HiddenCtx =
+ R.Declaration->getDeclContext()->getRedeclContext();
// There is no way to qualify a name declared in a function or method.
if (HiddenCtx->isFunctionOrMethod())
@@ -645,26 +652,27 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {
/// \brief Get the type that a given expression will have if this declaration
/// is used as an expression in its "typical" code-completion form.
-QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) {
+QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ if (const TypeDecl *Type = dyn_cast<TypeDecl>(ND))
return C.getTypeDeclType(Type);
- if (ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND))
+ if (const ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND))
return C.getObjCInterfaceType(Iface);
QualType T;
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
T = Function->getCallResultType();
- else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
T = Method->getSendResultType();
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
+ else if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast<FunctionTemplateDecl>(ND))
T = FunTmpl->getTemplatedDecl()->getCallResultType();
- else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext()));
- else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
- else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+ else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND))
T = Value->getType();
else
return QualType();
@@ -703,11 +711,48 @@ QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) {
return T;
}
+unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {
+ if (!ND)
+ return CCP_Unlikely;
+
+ // Context-based decisions.
+ const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
+ if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
+ // _cmd is relatively rare
+ if (const ImplicitParamDecl *ImplicitParam =
+ dyn_cast<ImplicitParamDecl>(ND))
+ if (ImplicitParam->getIdentifier() &&
+ ImplicitParam->getIdentifier()->isStr("_cmd"))
+ return CCP_ObjC_cmd;
+
+ return CCP_LocalDeclaration;
+ }
+ if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
+ return CCP_MemberDeclaration;
+
+ // Content-based decisions.
+ if (isa<EnumConstantDecl>(ND))
+ return CCP_Constant;
+
+ // Use CCP_Type for type declarations unless we're in a statement, Objective-C
+ // message receiver, or parenthesized expression context. There, it's as
+ // likely that the user will want to write a type as other declarations.
+ if ((isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
+ !(CompletionContext.getKind() == CodeCompletionContext::CCC_Statement ||
+ CompletionContext.getKind()
+ == CodeCompletionContext::CCC_ObjCMessageReceiver ||
+ CompletionContext.getKind()
+ == CodeCompletionContext::CCC_ParenthesizedExpression))
+ return CCP_Type;
+
+ return CCP_Declaration;
+}
+
void ResultBuilder::AdjustResultPriorityForDecl(Result &R) {
// If this is an Objective-C method declaration whose selector matches our
// preferred selector, give it a priority boost.
if (!PreferredSelector.isNull())
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration))
+ if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration))
if (PreferredSelector == Method->getSelector())
R.Priority += CCD_SelectorMatch;
@@ -735,9 +780,9 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) {
return;
ASTContext &Context = SemaRef.Context;
- NamedDecl *D = R.Declaration;
- CXXRecordDecl *Record = 0;
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D))
+ const NamedDecl *D = R.Declaration;
+ const CXXRecordDecl *Record = 0;
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D))
Record = ClassTemplate->getTemplatedDecl();
else if ((Record = dyn_cast<CXXRecordDecl>(D))) {
// Skip specializations and partial specializations.
@@ -757,9 +802,11 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) {
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(RecordTy));
- for (DeclContext::lookup_result Ctors = Record->lookup(ConstructorName);
- Ctors.first != Ctors.second; ++Ctors.first) {
- R.Declaration = *Ctors.first;
+ DeclContext::lookup_const_result Ctors = Record->lookup(ConstructorName);
+ for (DeclContext::lookup_const_iterator I = Ctors.begin(),
+ E = Ctors.end();
+ I != E; ++I) {
+ R.Declaration = *I;
R.CursorKind = getCursorKindForDecl(R.Declaration);
Results.push_back(R);
}
@@ -775,12 +822,16 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
// Look through using declarations.
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
- MaybeAddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext);
+ if (const UsingShadowDecl *Using =
+ dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ MaybeAddResult(Result(Using->getTargetDecl(),
+ getBasePriority(Using->getTargetDecl()),
+ R.Qualifier),
+ CurContext);
return;
}
- Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+ const Decl *CanonDecl = R.Declaration->getCanonicalDecl();
unsigned IDNS = CanonDecl->getIdentifierNamespace();
bool AsNestedNameSpecifier = false;
@@ -800,7 +851,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
for (; I != IEnd; ++I) {
- NamedDecl *ND = I->first;
+ const NamedDecl *ND = I->first;
unsigned Index = I->second;
if (ND->getCanonicalDecl() == CanonDecl) {
// This is a redeclaration. Always pick the newer declaration.
@@ -859,10 +910,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// If this result is supposed to have an informative qualifier, add one.
if (R.QualifierIsInformative && !R.Qualifier &&
!R.StartsNestedNameSpecifier) {
- DeclContext *Ctx = R.Declaration->getDeclContext();
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ const DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
- else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
@@ -887,8 +938,11 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
}
// Look through using declarations.
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
- AddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext, Hiding);
+ if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ AddResult(Result(Using->getTargetDecl(),
+ getBasePriority(Using->getTargetDecl()),
+ R.Qualifier),
+ CurContext, Hiding);
return;
}
@@ -921,10 +975,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
// If this result is supposed to have an informative qualifier, add one.
if (R.QualifierIsInformative && !R.Qualifier &&
!R.StartsNestedNameSpecifier) {
- DeclContext *Ctx = R.Declaration->getDeclContext();
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ const DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
- else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
@@ -938,7 +992,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
AdjustResultPriorityForDecl(R);
if (HasObjectTypeQualifiers)
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
if (Method->isInstance()) {
Qualifiers MethodQuals
= Qualifiers::fromCVRMask(Method->getTypeQualifiers());
@@ -982,7 +1036,7 @@ void ResultBuilder::ExitScope() {
/// \brief Determines whether this given declaration will be found by
/// ordinary name lookup.
-bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
+bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
unsigned IDNS = Decl::IDNS_Ordinary;
@@ -998,7 +1052,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
/// \brief Determines whether this given declaration will be found by
/// ordinary name lookup but is not a type name.
-bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
+bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
return false;
@@ -1014,11 +1068,11 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
return ND->getIdentifierNamespace() & IDNS;
}
-bool ResultBuilder::IsIntegralConstantValue(NamedDecl *ND) const {
+bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const {
if (!IsOrdinaryNonTypeName(ND))
return 0;
- if (ValueDecl *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl()))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl()))
if (VD->getType()->isIntegralOrEnumerationType())
return true;
@@ -1027,7 +1081,7 @@ bool ResultBuilder::IsIntegralConstantValue(NamedDecl *ND) const {
/// \brief Determines whether this given declaration will be found by
/// ordinary name lookup.
-bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
+bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
unsigned IDNS = Decl::IDNS_Ordinary;
@@ -1041,27 +1095,27 @@ bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
/// \brief Determines whether the given declaration is suitable as the
/// start of a C++ nested-name-specifier, e.g., a class or namespace.
-bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
+bool ResultBuilder::IsNestedNameSpecifier(const NamedDecl *ND) const {
// Allow us to find class templates, too.
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
return SemaRef.isAcceptableNestedNameSpecifier(ND);
}
/// \brief Determines whether the given declaration is an enumeration.
-bool ResultBuilder::IsEnum(NamedDecl *ND) const {
+bool ResultBuilder::IsEnum(const NamedDecl *ND) const {
return isa<EnumDecl>(ND);
}
/// \brief Determines whether the given declaration is a class or struct.
-bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
+bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const {
// Allow us to find class templates, too.
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
// For purposes of this check, interfaces match too.
- if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(ND))
return RD->getTagKind() == TTK_Class ||
RD->getTagKind() == TTK_Struct ||
RD->getTagKind() == TTK_Interface;
@@ -1070,31 +1124,31 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
}
/// \brief Determines whether the given declaration is a union.
-bool ResultBuilder::IsUnion(NamedDecl *ND) const {
+bool ResultBuilder::IsUnion(const NamedDecl *ND) const {
// Allow us to find class templates, too.
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
- if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(ND))
return RD->getTagKind() == TTK_Union;
return false;
}
/// \brief Determines whether the given declaration is a namespace.
-bool ResultBuilder::IsNamespace(NamedDecl *ND) const {
+bool ResultBuilder::IsNamespace(const NamedDecl *ND) const {
return isa<NamespaceDecl>(ND);
}
/// \brief Determines whether the given declaration is a namespace or
/// namespace alias.
-bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const {
+bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const {
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
}
/// \brief Determines whether the given declaration is a type.
-bool ResultBuilder::IsType(NamedDecl *ND) const {
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+bool ResultBuilder::IsType(const NamedDecl *ND) const {
+ if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
ND = Using->getTargetDecl();
return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
@@ -1103,8 +1157,8 @@ bool ResultBuilder::IsType(NamedDecl *ND) const {
/// \brief Determines which members of a class should be visible via
/// "." or "->". Only value declarations, nested name specifiers, and
/// using declarations thereof should show up.
-bool ResultBuilder::IsMember(NamedDecl *ND) const {
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+bool ResultBuilder::IsMember(const NamedDecl *ND) const {
+ if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
ND = Using->getTargetDecl();
return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
@@ -1144,7 +1198,7 @@ static bool isObjCReceiverType(ASTContext &C, QualType T) {
return T->isDependentType() || T->isRecordType();
}
-bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCMessageReceiver(const NamedDecl *ND) const {
QualType T = getDeclUsageType(SemaRef.Context, ND);
if (T.isNull())
return false;
@@ -1153,18 +1207,18 @@ bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const {
return isObjCReceiverType(SemaRef.Context, T);
}
-bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const {
if (IsObjCMessageReceiver(ND))
return true;
- VarDecl *Var = dyn_cast<VarDecl>(ND);
+ const VarDecl *Var = dyn_cast<VarDecl>(ND);
if (!Var)
return false;
return Var->hasLocalStorage() && !Var->hasAttr<BlocksAttr>();
}
-bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCCollection(const NamedDecl *ND) const {
if ((SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryName(ND)) ||
(!SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryNonTypeName(ND)))
return false;
@@ -1179,13 +1233,13 @@ bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
(SemaRef.getLangOpts().CPlusPlus && T->isRecordType());
}
-bool ResultBuilder::IsImpossibleToSatisfy(NamedDecl *ND) const {
+bool ResultBuilder::IsImpossibleToSatisfy(const NamedDecl *ND) const {
return false;
}
/// \brief Determines whether the given declaration is an Objective-C
/// instance variable.
-bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCIvar(const NamedDecl *ND) const {
return isa<ObjCIvarDecl>(ND);
}
@@ -1206,7 +1260,8 @@ namespace {
if (Ctx)
Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx);
- ResultBuilder::Result Result(ND, 0, false, Accessible);
+ ResultBuilder::Result Result(ND, Results.getBasePriority(ND), 0, false,
+ Accessible);
Results.AddResult(Result, CurContext, Hiding, InBaseClass);
}
};
@@ -1256,7 +1311,7 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
Builder.AddPlaceholderChunk("name");
Results.AddResult(Result(Builder.TakeString()));
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11) {
Results.AddResult(Result("auto", CCP_Type));
Results.AddResult(Result("char16_t", CCP_Type));
Results.AddResult(Result("char32_t", CCP_Type));
@@ -1421,7 +1476,7 @@ static const char *GetCompletionTypeString(QualType T,
// Anonymous tag types are constant strings.
if (const TagType *TagT = dyn_cast<TagType>(T))
if (TagDecl *Tag = TagT->getDecl())
- if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
+ if (!Tag->hasNameForLinkage()) {
switch (Tag->getTagKind()) {
case TTK_Struct: return "struct <anonymous>";
case TTK_Interface: return "__interface <anonymous>";
@@ -1906,7 +1961,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// FIXME: Rethrow?
- if (SemaRef.getLangOpts().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus11) {
// nullptr
Builder.AddResultTypeChunk("std::nullptr_t");
Builder.AddTypedTextChunk("nullptr");
@@ -1997,7 +2052,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
/// type chunk.
static void AddResultTypeChunk(ASTContext &Context,
const PrintingPolicy &Policy,
- NamedDecl *ND,
+ const NamedDecl *ND,
CodeCompletionBuilder &Result) {
if (!ND)
return;
@@ -2009,19 +2064,20 @@ static void AddResultTypeChunk(ASTContext &Context,
// Determine the type of the declaration (if it has a type).
QualType T;
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
T = Function->getResultType();
- else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
T = Method->getResultType();
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
+ else if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast<FunctionTemplateDecl>(ND))
T = FunTmpl->getTemplatedDecl()->getResultType();
- else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
else if (isa<UnresolvedUsingValueDecl>(ND)) {
/* Do nothing: ignore unresolved using declarations*/
- } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
+ } else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
T = Value->getType();
- } else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ } else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
@@ -2031,7 +2087,8 @@ static void AddResultTypeChunk(ASTContext &Context,
Result.getAllocator()));
}
-static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
+static void MaybeAddSentinel(ASTContext &Context,
+ const NamedDecl *FunctionOrMethod,
CodeCompletionBuilder &Result) {
if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr<SentinelAttr>())
if (Sentinel->getSentinel() == 0) {
@@ -2064,7 +2121,7 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals) {
static std::string FormatFunctionParameter(ASTContext &Context,
const PrintingPolicy &Policy,
- ParmVarDecl *Param,
+ const ParmVarDecl *Param,
bool SuppressName = false,
bool SuppressBlock = false) {
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
@@ -2090,36 +2147,35 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// The argument for a block pointer parameter is a block literal with
// the appropriate type.
- FunctionTypeLoc *Block = 0;
- FunctionProtoTypeLoc *BlockProto = 0;
+ FunctionTypeLoc Block;
+ FunctionProtoTypeLoc BlockProto;
TypeLoc TL;
if (TypeSourceInfo *TSInfo = Param->getTypeSourceInfo()) {
TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
while (true) {
// Look through typedefs.
if (!SuppressBlock) {
- if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
- if (TypeSourceInfo *InnerTSInfo
- = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
+ if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) {
+ if (TypeSourceInfo *InnerTSInfo =
+ TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
continue;
}
}
// Look through qualified types
- if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QualifiedTL->getUnqualifiedLoc();
+ if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QualifiedTL.getUnqualifiedLoc();
continue;
}
}
// Try to get the function prototype behind the block pointer type,
// then we're done.
- if (BlockPointerTypeLoc *BlockPtr
- = dyn_cast<BlockPointerTypeLoc>(&TL)) {
- TL = BlockPtr->getPointeeLoc().IgnoreParens();
- Block = dyn_cast<FunctionTypeLoc>(&TL);
- BlockProto = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ if (BlockPointerTypeLoc BlockPtr = TL.getAs<BlockPointerTypeLoc>()) {
+ TL = BlockPtr.getPointeeLoc().IgnoreParens();
+ Block = TL.getAs<FunctionTypeLoc>();
+ BlockProto = TL.getAs<FunctionProtoTypeLoc>();
}
break;
}
@@ -2147,27 +2203,27 @@ 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()->getResultType();
if (!ResultType->isVoidType() || SuppressBlock)
ResultType.getAsStringInternal(Result, Policy);
// Format the parameter list.
std::string Params;
- if (!BlockProto || Block->getNumArgs() == 0) {
- if (BlockProto && BlockProto->getTypePtr()->isVariadic())
+ if (!BlockProto || Block.getNumArgs() == 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.getNumArgs(); I != N; ++I) {
if (I)
Params += ", ";
- Params += FormatFunctionParameter(Context, Policy, Block->getArg(I),
+ Params += FormatFunctionParameter(Context, Policy, Block.getArg(I),
/*SuppressName=*/false,
/*SuppressBlock=*/true);
- if (I == N - 1 && BlockProto->getTypePtr()->isVariadic())
+ if (I == N - 1 && BlockProto.getTypePtr()->isVariadic())
Params += ", ...";
}
Params += ")";
@@ -2195,14 +2251,14 @@ static std::string FormatFunctionParameter(ASTContext &Context,
/// \brief Add function parameter chunks to the given code completion string.
static void AddFunctionParameterChunks(ASTContext &Context,
const PrintingPolicy &Policy,
- FunctionDecl *Function,
+ const FunctionDecl *Function,
CodeCompletionBuilder &Result,
unsigned Start = 0,
bool InOptional = false) {
bool FirstParameter = true;
for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) {
- ParmVarDecl *Param = Function->getParamDecl(P);
+ const ParmVarDecl *Param = Function->getParamDecl(P);
if (Param->hasDefaultArg() && !InOptional) {
// When we see an optional default argument, put that argument and
@@ -2248,7 +2304,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
/// \brief Add template parameter chunks to the given code completion string.
static void AddTemplateParameterChunks(ASTContext &Context,
const PrintingPolicy &Policy,
- TemplateDecl *Template,
+ const TemplateDecl *Template,
CodeCompletionBuilder &Result,
unsigned MaxParameters = 0,
unsigned Start = 0,
@@ -2346,7 +2402,7 @@ AddQualifierToCompletionString(CodeCompletionBuilder &Result,
static void
AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
- FunctionDecl *Function) {
+ const FunctionDecl *Function) {
const FunctionProtoType *Proto
= Function->getType()->getAs<FunctionProtoType>();
if (!Proto || !Proto->getTypeQuals())
@@ -2383,7 +2439,8 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
/// \brief Add the name of the given declaration
static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
- NamedDecl *ND, CodeCompletionBuilder &Result) {
+ const NamedDecl *ND,
+ CodeCompletionBuilder &Result) {
DeclarationName Name = ND->getDeclName();
if (!Name)
return;
@@ -2484,6 +2541,27 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
if (Declaration) {
Result.addParentContext(Declaration->getDeclContext());
Pattern->ParentName = Result.getParentName();
+ // Provide code completion comment for self.GetterName where
+ // GetterName is the getter method for a property with name
+ // different from the property name (declared via a property
+ // getter attribute.
+ const NamedDecl *ND = Declaration;
+ if (const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(ND))
+ if (M->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = M->findPropertyDecl())
+ if (PDecl->getGetterName() == M->getSelector() &&
+ PDecl->getIdentifier() != M->getIdentifier()) {
+ if (const RawComment *RC =
+ Ctx.getRawCommentForAnyRedecl(M)) {
+ Result.addBriefComment(RC->getBriefText(Ctx));
+ Pattern->BriefComment = Result.getBriefComment();
+ }
+ else if (const RawComment *RC =
+ Ctx.getRawCommentForAnyRedecl(PDecl)) {
+ Result.addBriefComment(RC->getBriefText(Ctx));
+ Pattern->BriefComment = Result.getBriefComment();
+ }
+ }
}
return Pattern;
@@ -2495,8 +2573,9 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
if (Kind == RK_Macro) {
- MacroInfo *MI = PP.getMacroInfoHistory(Macro);
- assert(MI && "Not a macro?");
+ const MacroDirective *MD = PP.getMacroDirectiveHistory(Macro);
+ assert(MD && "Not a macro?");
+ const MacroInfo *MI = MD->getMacroInfo();
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Macro->getName()));
@@ -2540,14 +2619,19 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
assert(Kind == RK_Declaration && "Missed a result kind?");
- NamedDecl *ND = Declaration;
+ const NamedDecl *ND = Declaration;
Result.addParentContext(ND->getDeclContext());
if (IncludeBriefComments) {
// Add documentation comment, if it exists.
if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(ND)) {
Result.addBriefComment(RC->getBriefText(Ctx));
- }
+ }
+ else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
+ if (OMD->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl())
+ if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(PDecl))
+ Result.addBriefComment(RC->getBriefText(Ctx));
}
if (StartsNestedNameSpecifier) {
@@ -2565,7 +2649,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
AddResultTypeChunk(Ctx, Policy, ND, Result);
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
AddTypedNameChunk(Ctx, Policy, ND, Result);
@@ -2576,7 +2660,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
+ if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
@@ -2630,7 +2714,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
+ if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
Result.AddTypedTextChunk(
@@ -2641,7 +2725,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
+ if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
Selector Sel = Method->getSelector();
if (Sel.isUnarySelector()) {
Result.AddTypedTextChunk(Result.getAllocator().CopyString(
@@ -2662,8 +2746,8 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
Result.AddTypedTextChunk("");
}
unsigned Idx = 0;
- for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
+ for (ObjCMethodDecl::param_const_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
P != PEnd; (void)++P, ++Idx) {
if (Idx > 0) {
std::string Keyword;
@@ -2827,7 +2911,7 @@ unsigned clang::getMacroUsagePriority(StringRef MacroName,
return Priority;
}
-CXCursorKind clang::getCursorKindForDecl(Decl *D) {
+CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
if (!D)
return CXCursor_UnexposedDecl;
@@ -2887,7 +2971,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
return CXCursor_ModuleImportDecl;
default:
- if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
case TTK_Interface: // fall through
case TTK_Struct: return CXCursor_StructDecl;
@@ -2930,7 +3014,7 @@ static void AddPrettyFunctionResults(const LangOptions &LangOpts,
Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant));
Results.AddResult(Result("__FUNCTION__", CCP_Constant));
- if (LangOpts.C99 || LangOpts.CPlusPlus0x)
+ if (LangOpts.C99 || LangOpts.CPlusPlus11)
Results.AddResult(Result("__func__", CCP_Constant));
Results.ExitScope();
}
@@ -3036,7 +3120,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
M != MEnd; ++M) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
- CXXMethodDecl *Overridden = const_cast<CXXMethodDecl *>(*M);
+ const CXXMethodDecl *Overridden = *M;
if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl())
continue;
@@ -3092,7 +3176,7 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
typedef CodeCompletionResult Result;
if (Path.empty()) {
// Enumerate all top-level modules.
- llvm::SmallVector<Module *, 8> Modules;
+ SmallVector<Module *, 8> Modules;
PP.getHeaderSearchInfo().collectAllModules(Modules);
for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
Builder.AddTypedTextChunk(
@@ -3265,7 +3349,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
// the initial opening bracket '[' missing. Add appropriate completions.
if (AllowNonIdentifiers && !AllowNestedNameSpecifiers &&
DS.getTypeSpecType() == DeclSpec::TST_typename &&
- DS.getStorageClassSpecAsWritten() == DeclSpec::SCS_unspecified &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
!DS.isThreadSpecified() && !DS.isExternInLinkageSpec() &&
DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified &&
DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
@@ -3395,7 +3479,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
P != PEnd;
++P) {
if (AddedProperties.insert(P->getIdentifier()))
- Results.MaybeAddResult(Result(*P, 0), CurContext);
+ Results.MaybeAddResult(Result(*P, Results.getBasePriority(*P), 0),
+ CurContext);
}
// Add nullary methods
@@ -3432,9 +3517,11 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
- for (ObjCCategoryDecl *Category = IFace->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- AddObjCProperties(Category, AllowCategories, AllowNullaryMethods,
+ 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);
}
@@ -3642,6 +3729,9 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
if (getLangOpts().C99 &&
!(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
Results.AddResult("restrict");
+ if (getLangOpts().C11 &&
+ !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
+ Results.AddResult("_Atomic");
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
Results.getCompletionContext(),
@@ -3724,8 +3814,7 @@ void Sema::CodeCompleteCase(Scope *S) {
if (EnumeratorsSeen.count(*E))
continue;
- CodeCompletionResult R(*E, Qualifier);
- R.Priority = CCP_EnumInCase;
+ CodeCompletionResult R(*E, CCP_EnumInCase, Qualifier);
Results.AddResult(R, CurContext, 0, false);
}
Results.ExitScope();
@@ -4094,7 +4183,8 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
NS = OrigToLatest.begin(),
NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
- Results.AddResult(CodeCompletionResult(NS->second, 0),
+ Results.AddResult(CodeCompletionResult(
+ NS->second, Results.getBasePriority(NS->second), 0),
CurContext, 0, false);
Results.ExitScope();
}
@@ -4308,7 +4398,8 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
continue;
if (Known.insert(Var->getIdentifier()))
- Results.AddResult(CodeCompletionResult(Var), CurContext, 0, false);
+ Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration),
+ CurContext, 0, false);
}
}
@@ -4410,6 +4501,14 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("class");
Results.AddResult(Result(Builder.TakeString()));
+
+ if (Results.getSema().getLangOpts().Modules) {
+ // @import name
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "import"));
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("module");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
void Sema::CodeCompleteObjCAtDirective(Scope *S) {
@@ -4757,10 +4856,15 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
bool InOriginalClass = true) {
typedef CodeCompletionResult Result;
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) {
- if (M->isInstanceMethod() == WantInstanceMethods) {
+ // 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, NumSelIdents,
@@ -4770,7 +4874,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
if (!Selectors.insert(M->getSelector()))
continue;
- Result R = Result(*M, 0);
+ Result R = Result(*M, Results.getBasePriority(*M), 0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = (WantKind != MK_Any);
if (!InOriginalClass)
@@ -4793,7 +4897,6 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
}
}
- ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
if (!IFace || !IFace->hasDefinition())
return;
@@ -4805,9 +4908,13 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
CurContext, Selectors, AllowSameLength, Results, false);
// Add methods in categories.
- for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl;
- CatDecl = CatDecl->getNextClassCategory()) {
- AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = IFace->known_categories_begin(),
+ CatEnd = IFace->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ ObjCCategoryDecl *CatDecl = *Cat;
+
+ AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
NumSelIdents, CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
@@ -4946,6 +5053,11 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
Builder.AddTextChunk("sender");
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
+
+ // If we're completing the return type, provide 'instancetype'.
+ if (!IsParameter) {
+ Results.AddResult(CodeCompletionResult("instancetype"));
+ }
// Add various builtin type names and specifiers.
AddOrdinaryNameResults(PCC_Type, S, *this, Results);
@@ -5075,11 +5187,14 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
// Check in categories or class extensions.
if (!SuperMethod) {
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- if ((SuperMethod = Category->getMethod(CurMethod->getSelector(),
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((SuperMethod = Cat->getMethod(CurMethod->getSelector(),
CurMethod->isInstanceMethod())))
break;
+ }
}
}
@@ -5163,7 +5278,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCMessageReceiver,
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture
: &ResultBuilder::IsObjCMessageReceiver);
@@ -5182,7 +5297,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results);
}
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
addThisCompletion(*this, Results);
Results.ExitScope();
@@ -5224,7 +5339,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
} else {
// "super" may be the name of a type or variable. Figure out which
// it is.
- IdentifierInfo *Super = &Context.Idents.get("super");
+ IdentifierInfo *Super = getSuperIdentifier();
NamedDecl *ND = LookupSingleName(S, Super, SuperLoc,
LookupOrdinaryName);
if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {
@@ -5274,7 +5389,7 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results,
if (R.Kind == Result::RK_Declaration &&
isa<ObjCMethodDecl>(R.Declaration)) {
if (R.Priority <= BestPriority) {
- ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration);
+ const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration);
if (NumSelIdents <= Method->param_size()) {
QualType MyPreferredType = Method->param_begin()[NumSelIdents - 1]
->getType();
@@ -5362,7 +5477,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
NumSelIdents))
continue;
- Result R(MethList->Method, 0);
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, SemaRef.CurContext);
@@ -5538,7 +5653,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
if (!Selectors.insert(MethList->Method->getSelector()))
continue;
- Result R(MethList->Method, 0);
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, CurContext);
@@ -5656,7 +5771,8 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
// Record any protocols we find.
if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
if (!OnlyForwardDeclarations || !Proto->hasDefinition())
- Results.AddResult(Result(Proto, 0), CurContext, 0, false);
+ Results.AddResult(Result(Proto, Results.getBasePriority(Proto), 0),
+ CurContext, 0, false);
}
}
@@ -5724,7 +5840,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
- Results.AddResult(Result(Class, 0), CurContext, 0, false);
+ Results.AddResult(Result(Class, Results.getBasePriority(Class), 0),
+ CurContext, 0, false);
}
}
@@ -5806,11 +5923,15 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
NamedDecl *CurClass
= LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
- if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass))
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- CategoryNames.insert(Category->getIdentifier());
-
+ 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) {
+ CategoryNames.insert(Cat->getIdentifier());
+ }
+ }
+
// Add all of the categories we know about.
Results.EnterNewScope();
TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
@@ -5819,7 +5940,8 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
D != DEnd; ++D)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D))
if (CategoryNames.insert(Category->getIdentifier()))
- Results.AddResult(Result(Category, 0), CurContext, 0, false);
+ Results.AddResult(Result(Category, Results.getBasePriority(Category),0),
+ CurContext, 0, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -5852,11 +5974,15 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.EnterNewScope();
bool IgnoreImplemented = true;
while (Class) {
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- if ((!IgnoreImplemented || !Category->getImplementation()) &&
- CategoryNames.insert(Category->getIdentifier()))
- Results.AddResult(Result(Category, 0), CurContext, 0, false);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = Class->visible_categories_begin(),
+ CatEnd = Class->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((!IgnoreImplemented || !Cat->getImplementation()) &&
+ CategoryNames.insert(Cat->getIdentifier()))
+ Results.AddResult(Result(*Cat, Results.getBasePriority(*Cat), 0),
+ CurContext, 0, false);
+ }
Class = Class->getSuperClass();
IgnoreImplemented = false;
@@ -5956,7 +6082,8 @@ 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, 0), CurContext, 0, false);
+ Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar), 0),
+ CurContext, 0, false);
// Determine whether we've seen an ivar with a name similar to the
// property.
@@ -6032,12 +6159,14 @@ static void FindImplementableMethods(ASTContext &Context,
KnownMethods, InOriginalClass);
// Add methods from any class extensions and categories.
- for (const ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat;
- Cat = Cat->getNextClassCategory())
- FindImplementableMethods(Context, const_cast<ObjCCategoryDecl*>(Cat),
- WantInstanceMethods, ReturnType,
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ FindImplementableMethods(Context, *Cat, WantInstanceMethods, ReturnType,
KnownMethods, false);
-
+ }
+
// Visit the superclass.
if (IFace->getSuperClass())
FindImplementableMethods(Context, IFace->getSuperClass(),
@@ -6167,7 +6296,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// The uppercased name of the property name.
std::string UpperKey = PropName->getName();
if (!UpperKey.empty())
- UpperKey[0] = toupper(UpperKey[0]);
+ UpperKey[0] = toUppercase(UpperKey[0]);
bool ReturnTypeMatchesProperty = ReturnType.isNull() ||
Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(),
@@ -6897,9 +7026,12 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
IFace = Category->getClassInterface();
if (IFace) {
- for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- Containers.push_back(Category);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ Containers.push_back(*Cat);
+ }
}
for (unsigned I = 0, N = Containers.size(); I != N; ++I) {
@@ -6975,7 +7107,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
continue;
}
- Result R(MethList->Method, 0);
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method), 0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = false;
R.DeclaringEntity = true;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0092d5dab1f4..adf3505633bd 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12,15 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/CXXFieldCollector.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -28,18 +24,21 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/ModuleLoader.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/Parse/ParseDiagnostic.h"
+#include "clang/Sema/CXXFieldCollector.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
@@ -677,9 +676,9 @@ Corrected:
(isa<TypeDecl>(UnderlyingFirstDecl) ||
isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) ||
isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) {
- UnqualifiedDiag = diag::err_unknown_typename_suggest;
- QualifiedDiag = diag::err_unknown_nested_typename_suggest;
- }
+ UnqualifiedDiag = diag::err_unknown_typename_suggest;
+ QualifiedDiag = diag::err_unknown_nested_typename_suggest;
+ }
if (SS.isEmpty())
Diag(NameLoc, UnqualifiedDiag)
@@ -1097,7 +1096,7 @@ void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
bool ExplicitInstantiationOrSpecialization) {
- return IdResolver.isDeclInScope(D, Ctx, Context, S,
+ return IdResolver.isDeclInScope(D, Ctx, S,
ExplicitInstantiationOrSpecialization);
}
@@ -1175,6 +1174,31 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) {
return false;
}
+// We need this to handle
+//
+// typedef struct {
+// void *foo() { return 0; }
+// } A;
+//
+// 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.
+// Callers should verify at the end of the TU if it D has external linkage or
+// not.
+bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ while (!DC->isTranslationUnit()) {
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(DC)){
+ if (!RD->hasNameForLinkage())
+ return true;
+ }
+ DC = DC->getParent();
+ }
+
+ return !D->hasExternalLinkage();
+}
+
bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
assert(D);
@@ -1224,10 +1248,7 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
}
// Only warn for unused decls internal to the translation unit.
- if (D->getLinkage() == ExternalLinkage)
- return false;
-
- return true;
+ return mightHaveNonExternalLinkage(D);
}
void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) {
@@ -1368,7 +1389,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (!S->hasErrorOccurred())
+ if (!S->hasUnrecoverableErrorOccurred())
DiagnoseUnusedDecl(D);
// If this was a forward reference to a label, verify it was defined.
@@ -1465,6 +1486,24 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
return S;
}
+/// \brief Looks up the declaration of "struct objc_super" and
+/// saves it for later use in building builtin declaration of
+/// objc_msgSendSuper and objc_msgSendSuper_stret. If no such
+/// pre-existing declaration exists no action takes place.
+static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S,
+ IdentifierInfo *II) {
+ if (!II->isStr("objc_msgSendSuper"))
+ return;
+ ASTContext &Context = ThisSema.Context;
+
+ LookupResult Result(ThisSema, &Context.Idents.get("objc_super"),
+ SourceLocation(), Sema::LookupTagName);
+ ThisSema.LookupName(Result, S);
+ if (Result.getResultKind() == LookupResult::Found)
+ if (const TagDecl *TD = Result.getAsSingle<TagDecl>())
+ Context.setObjCSuperType(Context.getTagDeclType(TD));
+}
+
/// 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
@@ -1472,6 +1511,8 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Scope *S, bool ForRedeclaration,
SourceLocation Loc) {
+ LookupPredefedObjCSuperType(*this, S, II);
+
Builtin::ID BID = (Builtin::ID)bid;
ASTContext::GetBuiltinTypeError Error;
@@ -1516,7 +1557,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Context.getTranslationUnitDecl(),
Loc, Loc, II, R, /*TInfo=*/0,
SC_Extern,
- SC_None, false,
+ false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -1529,7 +1570,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
ParmVarDecl::Create(Context, New, SourceLocation(),
SourceLocation(), 0,
FT->getArgType(i), /*TInfo=*/0,
- SC_None, SC_None, 0);
+ SC_None, 0);
parm->setScopeInfo(0, i);
Params.push_back(parm);
}
@@ -1549,6 +1590,49 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
return New;
}
+/// \brief Filter out any previous declarations that the given declaration
+/// should not consider because they are not permitted to conflict, e.g.,
+/// because they come from hidden sub-modules and do not refer to the same
+/// entity.
+static void filterNonConflictingPreviousDecls(ASTContext &context,
+ NamedDecl *decl,
+ LookupResult &previous){
+ // This is only interesting when modules are enabled.
+ if (!context.getLangOpts().Modules)
+ return;
+
+ // Empty sets are uninteresting.
+ if (previous.empty())
+ return;
+
+ LookupResult::Filter filter = previous.makeFilter();
+ while (filter.hasNext()) {
+ NamedDecl *old = filter.next();
+
+ // Non-hidden declarations are never ignored.
+ if (!old->isHidden())
+ continue;
+
+ // If either has no-external linkage, ignore the old declaration.
+ // If this declaration would have external linkage if it were the first
+ // declaration of this name, then it may in fact be a redeclaration of
+ // some hidden declaration, so include those too. We don't need to worry
+ // about some previous visible declaration giving this declaration external
+ // linkage, because in that case, we'll mark this declaration as a redecl
+ // of the visible decl, and that decl will already be a redecl of the
+ // hidden declaration if that's appropriate.
+ //
+ // Don't cache this linkage computation, because it's not yet correct: we
+ // may later give this declaration a previous declaration which changes
+ // its linkage.
+ if (old->getLinkage() != ExternalLinkage ||
+ !decl->hasExternalLinkageUncached())
+ filter.erase();
+ }
+
+ filter.done();
+}
+
bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
QualType OldType;
if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
@@ -1769,26 +1853,164 @@ DeclHasAttr(const Decl *D, const Attr *A) {
return false;
}
-bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) {
+static bool isAttributeTargetADefinition(Decl *D) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->isThisDeclarationADefinition();
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->isCompleteDefinition() || TD->isBeingDefined();
+ return true;
+}
+
+/// Merge alignment attributes from \p Old to \p New, taking into account the
+/// special semantics of C11's _Alignas specifier and C++11's alignas attribute.
+///
+/// \return \c true if any attributes were added to \p New.
+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;
+ unsigned OldAlign = 0;
+ for (specific_attr_iterator<AlignedAttr>
+ I = Old->specific_attr_begin<AlignedAttr>(),
+ E = Old->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ // FIXME: We have no way of representing inherited dependent alignments
+ // in a case like:
+ // template<int A, int B> struct alignas(A) X;
+ // template<int A, int B> struct alignas(B) X {};
+ // For now, we just ignore any alignas attributes which are not on the
+ // definition in such a case.
+ if (I->isAlignmentDependent())
+ return false;
+
+ if (I->isAlignas())
+ OldAlignasAttr = *I;
+
+ unsigned Align = I->getAlignment(S.Context);
+ if (Align > OldAlign) {
+ OldAlign = Align;
+ OldStrictestAlignAttr = *I;
+ }
+ }
+
+ // Look for alignas attributes on New.
+ AlignedAttr *NewAlignasAttr = 0;
+ unsigned NewAlign = 0;
+ for (specific_attr_iterator<AlignedAttr>
+ I = New->specific_attr_begin<AlignedAttr>(),
+ E = New->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ if (I->isAlignmentDependent())
+ return false;
+
+ if (I->isAlignas())
+ NewAlignasAttr = *I;
+
+ unsigned Align = I->getAlignment(S.Context);
+ if (Align > NewAlign)
+ NewAlign = Align;
+ }
+
+ if (OldAlignasAttr && NewAlignasAttr && OldAlign != NewAlign) {
+ // Both declarations have 'alignas' attributes. We require them to match.
+ // C++11 [dcl.align]p6 and C11 6.7.5/7 both come close to saying this, but
+ // fall short. (If two declarations both have alignas, they must both match
+ // every definition, and so must match each other if there is a definition.)
+
+ // If either declaration only contains 'alignas(0)' specifiers, then it
+ // specifies the natural alignment for the type.
+ if (OldAlign == 0 || NewAlign == 0) {
+ QualType Ty;
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(New))
+ Ty = VD->getType();
+ else
+ Ty = S.Context.getTagDeclType(cast<TagDecl>(New));
+
+ if (OldAlign == 0)
+ OldAlign = S.Context.getTypeAlign(Ty);
+ if (NewAlign == 0)
+ NewAlign = S.Context.getTypeAlign(Ty);
+ }
+
+ if (OldAlign != NewAlign) {
+ S.Diag(NewAlignasAttr->getLocation(), diag::err_alignas_mismatch)
+ << (unsigned)S.Context.toCharUnitsFromBits(OldAlign).getQuantity()
+ << (unsigned)S.Context.toCharUnitsFromBits(NewAlign).getQuantity();
+ S.Diag(OldAlignasAttr->getLocation(), diag::note_previous_declaration);
+ }
+ }
+
+ if (OldAlignasAttr && !NewAlignasAttr && isAttributeTargetADefinition(New)) {
+ // C++11 [dcl.align]p6:
+ // if any declaration of an entity has an alignment-specifier,
+ // every defining declaration of that entity shall specify an
+ // equivalent alignment.
+ // C11 6.7.5/7:
+ // If the definition of an object does not have an alignment
+ // 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();
+ S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration)
+ << OldAlignasAttr->isC11();
+ }
+
+ bool AnyAdded = false;
+
+ // Ensure we have an attribute representing the strictest alignment.
+ if (OldAlign > NewAlign) {
+ AlignedAttr *Clone = OldStrictestAlignAttr->clone(S.Context);
+ Clone->setInherited(true);
+ New->addAttr(Clone);
+ AnyAdded = true;
+ }
+
+ // Ensure we have an alignas attribute if the old declaration had one.
+ if (OldAlignasAttr && !NewAlignasAttr &&
+ !(AnyAdded && OldStrictestAlignAttr->isAlignas())) {
+ AlignedAttr *Clone = OldAlignasAttr->clone(S.Context);
+ Clone->setInherited(true);
+ New->addAttr(Clone);
+ AnyAdded = true;
+ }
+
+ return AnyAdded;
+}
+
+static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
+ bool Override) {
InheritableAttr *NewAttr = NULL;
+ unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
- NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
- AA->getIntroduced(), AA->getDeprecated(),
- AA->getObsoleted(), AA->getUnavailable(),
- AA->getMessage());
+ 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))
- NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility());
+ NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+ AttrSpellingListIndex);
+ else if (TypeVisibilityAttr *VA = dyn_cast<TypeVisibilityAttr>(Attr))
+ NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+ AttrSpellingListIndex);
else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
- NewAttr = mergeDLLImportAttr(D, ImportA->getRange());
+ NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
+ AttrSpellingListIndex);
else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
- NewAttr = mergeDLLExportAttr(D, ExportA->getRange());
+ NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
+ AttrSpellingListIndex);
else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
- NewAttr = mergeFormatAttr(D, FA->getRange(), FA->getType(),
- FA->getFormatIdx(), FA->getFirstArg());
+ NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
+ FA->getFormatIdx(), FA->getFirstArg(),
+ AttrSpellingListIndex);
else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
- NewAttr = mergeSectionAttr(D, SA->getRange(), SA->getName());
+ NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
+ AttrSpellingListIndex);
+ 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 = cast<InheritableAttr>(Attr->clone(Context));
+ NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
if (NewAttr) {
NewAttr->setInherited(true);
@@ -1839,6 +2061,31 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
++I;
continue; // regular attr merging will take care of validating this.
}
+
+ if (isa<C11NoReturnAttr>(NewAttribute)) {
+ // C's _Noreturn is allowed to be added to a function after it is defined.
+ ++I;
+ continue;
+ } else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
+ if (AA->isAlignas()) {
+ // C++11 [dcl.align]p6:
+ // if any declaration of an entity has an alignment-specifier,
+ // every defining declaration of that entity shall specify an
+ // equivalent alignment.
+ // C11 6.7.5/7:
+ // If the definition of an object does not have an alignment
+ // 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();
+ S.Diag(NewAttribute->getLocation(), diag::note_alignas_on_declaration)
+ << AA->isC11();
+ NewAttributes.erase(NewAttributes.begin() + I);
+ --E;
+ continue;
+ }
+ }
+
S.Diag(NewAttribute->getLocation(),
diag::warn_attribute_precede_definition);
S.Diag(Def->getLocation(), diag::note_previous_definition);
@@ -1848,8 +2095,11 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
}
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
-void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
- bool MergeDeprecation) {
+void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
+ AvailabilityMergeKind AMK) {
+ if (!Old->hasAttrs() && !New->hasAttrs())
+ return;
+
// attributes declared post-definition are currently ignored
checkNewAttributesAfterDef(*this, New, Old);
@@ -1866,17 +2116,31 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
i = Old->specific_attr_begin<InheritableAttr>(),
e = Old->specific_attr_end<InheritableAttr>();
i != e; ++i) {
+ bool Override = false;
// Ignore deprecated/unavailable/availability attributes if requested.
- if (!MergeDeprecation &&
- (isa<DeprecatedAttr>(*i) ||
- isa<UnavailableAttr>(*i) ||
- isa<AvailabilityAttr>(*i)))
- continue;
+ if (isa<DeprecatedAttr>(*i) ||
+ isa<UnavailableAttr>(*i) ||
+ isa<AvailabilityAttr>(*i)) {
+ switch (AMK) {
+ case AMK_None:
+ continue;
- if (mergeDeclAttribute(New, *i))
+ case AMK_Redeclaration:
+ break;
+
+ case AMK_Override:
+ Override = true;
+ break;
+ }
+ }
+
+ if (mergeDeclAttribute(*this, New, *i, Override))
foundAny = true;
}
+ if (mergeAlignedAttrs(*this, New, Old))
+ foundAny = true;
+
if (!foundAny) New->dropAttrs();
}
@@ -1884,7 +2148,25 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
/// to the new one.
static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
const ParmVarDecl *oldDecl,
- ASTContext &C) {
+ Sema &S) {
+ // C++11 [dcl.attr.depend]p2:
+ // 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(),
+ 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?
+ const FunctionDecl *FirstFD =
+ cast<FunctionDecl>(oldDecl->getDeclContext())->getFirstDeclaration();
+ const ParmVarDecl *FirstVD =
+ FirstFD->getParamDecl(oldDecl->getFunctionScopeIndex());
+ S.Diag(FirstVD->getLocation(),
+ diag::note_carries_dependency_missing_first_decl) << 1/*Param*/;
+ }
+
if (!oldDecl->hasAttrs())
return;
@@ -1898,7 +2180,8 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
i = oldDecl->specific_attr_begin<InheritableParamAttr>(),
e = oldDecl->specific_attr_end<InheritableParamAttr>(); i != e; ++i) {
if (!DeclHasAttr(newDecl, *i)) {
- InheritableAttr *newAttr = cast<InheritableParamAttr>((*i)->clone(C));
+ InheritableAttr *newAttr =
+ cast<InheritableParamAttr>((*i)->clone(S.Context));
newAttr->setInherited(true);
newDecl->addAttr(newAttr);
foundAny = true;
@@ -1966,6 +2249,22 @@ static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
return ABIDefaultCC == CC;
}
+template <typename T>
+static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) {
+ const DeclContext *DC = Old->getDeclContext();
+ if (DC->isRecord())
+ return false;
+
+ LanguageLinkage OldLinkage = Old->getLanguageLinkage();
+ if (OldLinkage == CXXLanguageLinkage &&
+ New->getDeclContext()->isExternCContext())
+ return true;
+ if (OldLinkage == CLanguageLinkage &&
+ New->getDeclContext()->isExternCXXContext())
+ return true;
+ return false;
+}
+
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -1987,6 +2286,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) {
+ if (New->getFriendObjectKind()) {
+ Diag(New->getLocation(), diag::err_using_decl_friend);
+ Diag(Shadow->getTargetDecl()->getLocation(),
+ diag::note_using_decl_target);
+ Diag(Shadow->getUsingDecl()->getLocation(),
+ diag::note_using_decl) << 0;
+ return true;
+ }
+
Diag(New->getLocation(), diag::err_using_decl_conflict_reverse);
Diag(Shadow->getTargetDecl()->getLocation(),
diag::note_using_decl_target);
@@ -2016,9 +2324,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// Don't complain about this if we're in GNU89 mode and the old function
// is an extern inline function.
+ // Don't complain about specializations. They are not supposed to have
+ // storage classes.
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == SC_Static &&
- Old->getStorageClass() != SC_Static &&
+ isExternalLinkage(Old->getLinkage()) &&
+ !New->getTemplateSpecializationInfo() &&
!canRedefineFunction(Old, getLangOpts())) {
if (getLangOpts().MicrosoftExt) {
Diag(New->getLocation(), diag::warn_static_non_static) << New;
@@ -2060,9 +2371,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
RequiresAdjustment = true;
// Don't complain about mismatches when the default CC is
- // effectively the same as the explict one.
+ // effectively the same as the explict one. Only Old decl contains correct
+ // information about storage class of CXXMethod.
} else if (OldTypeInfo.getCC() == CC_Default &&
- isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) {
+ isABIDefaultCC(*this, NewTypeInfo.getCC(), Old)) {
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
@@ -2116,6 +2428,23 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
New->setType(QualType(NewType, 0));
NewQType = Context.getCanonicalType(New->getType());
}
+
+ // If this redeclaration makes the function inline, we may need to add it to
+ // UndefinedButUsed.
+ if (!Old->isInlined() && New->isInlined() &&
+ !New->hasAttr<GNUInlineAttr>() &&
+ (getLangOpts().CPlusPlus || !getLangOpts().GNUInline) &&
+ Old->isUsed(false) &&
+ !Old->isDefined() && !New->isThisDeclarationADefinition())
+ UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(),
+ SourceLocation()));
+
+ // If this redeclaration makes it newly gnu_inline, we don't want to warn
+ // about it.
+ if (New->hasAttr<GNUInlineAttr>() &&
+ Old->isInlined() && !Old->hasAttr<GNUInlineAttr>()) {
+ UndefinedButUsed.erase(Old->getCanonicalDecl());
+ }
if (getLangOpts().CPlusPlus) {
// (C++98 13.1p2):
@@ -2211,6 +2540,30 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
}
}
+ // C++11 [dcl.attr.noreturn]p1:
+ // 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);
+ Diag(Old->getFirstDeclaration()->getLocation(),
+ diag::note_noreturn_missing_first_decl);
+ }
+
+ // C++11 [dcl.attr.depend]p2:
+ // 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(),
+ diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/;
+ Diag(Old->getFirstDeclaration()->getLocation(),
+ diag::note_carries_dependency_missing_first_decl) << 0/*Function*/;
+ }
+
// (C++98 8.3.5p3):
// All declarations for a function shall agree exactly in both the
// return type and the parameter-type-list.
@@ -2226,6 +2579,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
assert(OldQTypeForComparison.isCanonical());
}
+ if (haveIncompatibleLanguageLinkages(Old, New)) {
+ Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+ Diag(Old->getLocation(), PrevDiag);
+ return true;
+ }
+
if (OldQTypeForComparison == NewQType)
return MergeCompatibleFunctionDecls(New, Old, S);
@@ -2247,7 +2606,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
OldProto->arg_type_end());
NewQType = Context.getFunctionType(NewFuncType->getResultType(),
- ParamTypes.data(), ParamTypes.size(),
+ ParamTypes,
OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -2262,7 +2621,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
SourceLocation(),
SourceLocation(), 0,
*ParamType, /*TInfo=*/0,
- SC_None, SC_None,
+ SC_None,
0);
Param->setScopeInfo(0, Params.size());
Param->setImplicit();
@@ -2330,8 +2689,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
diag::note_previous_declaration);
}
- New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
- ArgTypes.size(),
+ New->setType(Context.getFunctionType(MergedReturn, ArgTypes,
OldProto->getExtProtoInfo()));
return MergeCompatibleFunctionDecls(New, Old, S);
}
@@ -2379,25 +2737,30 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
// Merge the attributes
mergeDeclAttributes(New, Old);
- // Merge the storage class.
- if (Old->getStorageClass() != SC_Extern &&
- Old->getStorageClass() != SC_None)
- New->setStorageClass(Old->getStorageClass());
-
// Merge "pure" flag.
if (Old->isPure())
New->setPure();
+ // Merge "used" flag.
+ if (Old->isUsed(false))
+ New->setUsed();
+
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
for (unsigned i = 0, e = New->getNumParams(); i != e; ++i)
mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i),
- Context);
+ *this);
if (getLangOpts().CPlusPlus)
return MergeCXXFunctionDecl(New, Old, S);
+ // Merge the function types so the we get the composite types for the return
+ // and argument types.
+ QualType Merged = Context.mergeTypes(Old->getType(), New->getType());
+ if (!Merged.isNull())
+ New->setType(Merged);
+
return false;
}
@@ -2406,7 +2769,7 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ObjCMethodDecl *oldMethod) {
// Merge the attributes, including deprecated/unavailable
- mergeDeclAttributes(newMethod, oldMethod, /* mergeDeprecation */true);
+ mergeDeclAttributes(newMethod, oldMethod, AMK_Override);
// Merge attributes from the parameters.
ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(),
@@ -2414,9 +2777,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
for (ObjCMethodDecl::param_iterator
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne && oi != oe; ++ni, ++oi)
- mergeParamDeclAttributes(*ni, *oi, Context);
+ mergeParamDeclAttributes(*ni, *oi, *this);
- CheckObjCMethodOverride(newMethod, oldMethod, true);
+ CheckObjCMethodOverride(newMethod, oldMethod);
}
/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
@@ -2426,7 +2789,7 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
/// to here in AddInitializerToDecl. We can't check them before the initializer
/// is attached.
-void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
+void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
if (New->isInvalidDecl() || Old->isInvalidDecl())
return;
@@ -2447,19 +2810,17 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
// absence of a major array bound (8.3.4).
else if (Old->getType()->isIncompleteArrayType() &&
New->getType()->isArrayType()) {
- CanQual<ArrayType> OldArray
- = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
- CanQual<ArrayType> NewArray
- = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
- if (OldArray->getElementType() == NewArray->getElementType())
+ const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
+ const ArrayType *NewArray = Context.getAsArrayType(New->getType());
+ if (Context.hasSameType(OldArray->getElementType(),
+ NewArray->getElementType()))
MergedT = New->getType();
} else if (Old->getType()->isArrayType() &&
New->getType()->isIncompleteArrayType()) {
- CanQual<ArrayType> OldArray
- = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
- CanQual<ArrayType> NewArray
- = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
- if (OldArray->getElementType() == NewArray->getElementType())
+ const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
+ const ArrayType *NewArray = Context.getAsArrayType(New->getType());
+ if (Context.hasSameType(OldArray->getElementType(),
+ NewArray->getElementType()))
MergedT = Old->getType();
} else if (New->getType()->isObjCObjectPointerType()
&& Old->getType()->isObjCObjectPointerType()) {
@@ -2475,7 +2836,11 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- New->setType(MergedT);
+
+ // Don't actually update the type on the new declaration if the old
+ // declaration was a extern declaration in a different scope.
+ if (!OldWasHidden)
+ New->setType(MergedT);
}
/// MergeVarDecl - We just parsed a variable 'New' which has the same name
@@ -2486,7 +2851,8 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
/// definitions here, since the initializer hasn't been attached.
///
-void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
+void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
+ bool PreviousWasHidden) {
// If the new decl is already invalid, don't do any other checking.
if (New->isInvalidDecl())
return;
@@ -2526,13 +2892,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
// Merge the types.
- MergeVarDeclTypes(New, Old);
+ MergeVarDeclTypes(New, Old, PreviousWasHidden);
if (New->isInvalidDecl())
return;
- // C99 6.2.2p4: Check if we have a static decl followed by a non-static.
+ // [dcl.stc]p8: Check if we have a non-static decl followed by a static.
if (New->getStorageClass() == SC_Static &&
- (Old->getStorageClass() == SC_None || Old->hasExternalStorage())) {
+ !New->isStaticDataMember() &&
+ isExternalLinkage(Old->getLinkage())) {
Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2548,8 +2915,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// identifier has external linkage.
if (New->hasExternalStorage() && Old->hasLinkage())
/* Okay */;
- else if (New->getStorageClass() != SC_Static &&
- Old->getStorageClass() == SC_Static) {
+ else if (New->getCanonicalDecl()->getStorageClass() != SC_Static &&
+ !New->isStaticDataMember() &&
+ Old->getCanonicalDecl()->getStorageClass() == SC_Static) {
Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2562,8 +2930,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- if (Old->hasExternalStorage() &&
- !New->hasLinkage() && New->isLocalVarDecl()) {
+ if (Old->hasLinkage() && New->isLocalVarDecl() &&
+ !New->hasExternalStorage()) {
Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2601,17 +2969,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setInvalidDecl();
return;
}
- // c99 6.2.2 P4.
- // For an identifier declared with the storage-class specifier extern in a
- // scope in which a prior declaration of that identifier is visible, if
- // the prior declaration specifies internal or external linkage, the linkage
- // of the identifier at the later declaration is the same as the linkage
- // specified at the prior declaration.
- // FIXME. revisit this code.
- if (New->hasExternalStorage() &&
- Old->getLinkage() == InternalLinkage &&
- New->getDeclContext() == Old->getDeclContext())
- New->setStorageClass(Old->getStorageClass());
+
+ if (haveIncompatibleLanguageLinkages(Old, New)) {
+ Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return;
+ }
+
+ // Merge "used" flag.
+ if (Old->isUsed(false))
+ New->setUsed();
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
@@ -2628,11 +2996,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
-/// no declarator (e.g. "struct foo;") is parsed. It also accopts template
+/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS,
- MultiTemplateParamsArg TemplateParams) {
+ MultiTemplateParamsArg TemplateParams,
+ bool IsExplicitInstantiation) {
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -2655,6 +3024,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
if (Tag) {
+ getASTContext().addUnnamedTag(Tag);
Tag->setFreeStanding();
if (Tag->isInvalidDecl())
return Tag;
@@ -2684,6 +3054,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return TagD;
}
+ DiagnoseFunctionSpecifiers(DS);
+
if (DS.isFriendSpecified()) {
// If we're dealing with a decl but not a TagDecl, assume that
// whatever routines created it handled the friendship aspect.
@@ -2692,10 +3064,28 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return ActOnFriendTypeDecl(S, DS, TemplateParams);
}
- // Track whether we warned about the fact that there aren't any
- // declarators.
- bool emittedWarning = false;
-
+ CXXScopeSpec &SS = DS.getTypeSpecScope();
+ bool IsExplicitSpecialization =
+ !TemplateParams.empty() && TemplateParams.back()->size() == 0;
+ if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() &&
+ !IsExplicitInstantiation && !IsExplicitSpecialization) {
+ // Per C++ [dcl.type.elab]p1, a class declaration cannot have a
+ // nested-name-specifier unless it is an explicit instantiation
+ // or an explicit specialization.
+ // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either.
+ Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier)
+ << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
+ DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
+ DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
+ DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4)
+ << SS.getRange();
+ return 0;
+ }
+
+ // Track whether this decl-specifier declares anything.
+ bool DeclaresAnything = true;
+
+ // Handle anonymous struct definitions.
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
if (!Record->getDeclName() && Record->isCompleteDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
@@ -2703,13 +3093,11 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Record->getDeclContext()->isRecord())
return BuildAnonymousStructOrUnion(S, DS, AS, Record);
- Diag(DS.getLocStart(), diag::ext_no_declarators)
- << DS.getSourceRange();
- emittedWarning = true;
+ DeclaresAnything = false;
}
}
- // Check for Microsoft C extension: anonymous struct.
+ // Check for Microsoft C extension: anonymous struct member.
if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
CurContext->isRecord() &&
DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
@@ -2726,70 +3114,82 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return BuildMicrosoftCAnonymousStruct(S, DS, Record);
}
}
-
- if (getLangOpts().CPlusPlus &&
+
+ // Skip all the checks below if we have a type error.
+ if (DS.getTypeSpecType() == DeclSpec::TST_error ||
+ (TagD && TagD->isInvalidDecl()))
+ return TagD;
+
+ if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag))
if (Enum->enumerator_begin() == Enum->enumerator_end() &&
- !Enum->getIdentifier() && !Enum->isInvalidDecl()) {
- Diag(Enum->getLocation(), diag::ext_no_declarators)
- << DS.getSourceRange();
- emittedWarning = true;
- }
+ !Enum->getIdentifier() && !Enum->isInvalidDecl())
+ DeclaresAnything = false;
- // Skip all the checks below if we have a type error.
- if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD;
-
if (!DS.isMissingDeclaratorOk()) {
- // Warn about typedefs of enums without names, since this is an
- // extension in both Microsoft and GNU.
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
- Tag && isa<EnumDecl>(Tag)) {
+ // Customize diagnostic for a typedef missing a name.
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
Diag(DS.getLocStart(), diag::ext_typedef_without_a_name)
<< DS.getSourceRange();
- return Tag;
- }
-
- Diag(DS.getLocStart(), diag::ext_no_declarators)
- << DS.getSourceRange();
- emittedWarning = true;
+ else
+ DeclaresAnything = false;
}
- // We're going to complain about a bunch of spurious specifiers;
- // only do this if we're declaring a tag, because otherwise we
- // should be getting diag::ext_no_declarators.
- if (emittedWarning || (TagD && TagD->isInvalidDecl()))
+ if (DS.isModulePrivateSpecified() &&
+ Tag && Tag->getDeclContext()->isFunctionOrMethod())
+ Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class)
+ << Tag->getTagKind()
+ << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
+
+ ActOnDocumentableDecl(TagD);
+
+ // C 6.7/2:
+ // A declaration [...] shall declare at least a declarator [...], a tag,
+ // or the members of an enumeration.
+ // C++ [dcl.dcl]p3:
+ // [If there are no declarators], and except for the declaration of an
+ // unnamed bit-field, the decl-specifier-seq shall introduce one or more
+ // names into the program, or shall redeclare a name introduced by a
+ // previous declaration.
+ if (!DeclaresAnything) {
+ // In C, we allow this as a (popular) extension / bug. Don't bother
+ // producing further diagnostics for redundant qualifiers after this.
+ Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange();
return TagD;
+ }
+
+ // C++ [dcl.stc]p1:
+ // If a storage-class-specifier appears in a decl-specifier-seq, [...] the
+ // init-declarator-list of the declaration shall not be empty.
+ // C++ [dcl.fct.spec]p1:
+ // If a cv-qualifier appears in a decl-specifier-seq, the
+ // init-declarator-list of the declaration shall not be empty.
+ //
+ // Spurious qualifiers here appear to be valid in C.
+ unsigned DiagID = diag::warn_standalone_specifier;
+ if (getLangOpts().CPlusPlus)
+ DiagID = diag::ext_standalone_specifier;
// 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())
- Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier)
- << DeclSpec::getSpecifierName(scs);
+ if (DeclSpec::SCS SCS = DS.getStorageClassSpec())
+ if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef)
+ Diag(DS.getStorageClassSpecLoc(), DiagID)
+ << DeclSpec::getSpecifierName(SCS);
if (DS.isThreadSpecified())
- Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread";
+ Diag(DS.getThreadSpecLoc(), DiagID) << "__thread";
if (DS.getTypeQualifiers()) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
- Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const";
+ Diag(DS.getConstSpecLoc(), DiagID) << "const";
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
- Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile";
+ Diag(DS.getConstSpecLoc(), DiagID) << "volatile";
// Restrict is covered above.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic";
}
- if (DS.isInlineSpecified())
- Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline";
- if (DS.isVirtualSpecified())
- Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual";
- if (DS.isExplicitSpecified())
- Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit";
-
- if (DS.isModulePrivateSpecified() &&
- Tag && Tag->getDeclContext()->isFunctionOrMethod())
- Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class)
- << Tag->getTagKind()
- << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
// Warn about ignored type attributes, for example:
// __attribute__((aligned)) struct A;
@@ -2814,8 +3214,6 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
}
- ActOnDocumentableDecl(TagD);
-
return TagD;
}
@@ -2950,25 +3348,6 @@ StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
llvm_unreachable("unknown storage class specifier");
}
-/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to
-/// a StorageClass. Any error reporting is up to the caller:
-/// illegal input values are mapped to SC_None.
-static StorageClass
-StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
- switch (StorageClassSpec) {
- case DeclSpec::SCS_unspecified: return SC_None;
- case DeclSpec::SCS_extern: return SC_Extern;
- case DeclSpec::SCS_static: return SC_Static;
- case DeclSpec::SCS_private_extern: return SC_PrivateExtern;
- // Illegal SCSs map to None: error reporting is up to the caller.
- case DeclSpec::SCS_auto: // Fall through.
- case DeclSpec::SCS_mutable: // Fall through.
- case DeclSpec::SCS_register: // Fall through.
- case DeclSpec::SCS_typedef: return SC_None;
- }
- llvm_unreachable("unknown storage class specifier");
-}
-
/// 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
@@ -3027,18 +3406,23 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (DS.getTypeQualifiers()) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified)
- << Record->isUnion() << 0
+ << Record->isUnion() << "const"
<< FixItHint::CreateRemoval(DS.getConstSpecLoc());
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
- Diag(DS.getVolatileSpecLoc(),
+ Diag(DS.getVolatileSpecLoc(),
diag::ext_anonymous_struct_union_qualified)
- << Record->isUnion() << 1
+ << Record->isUnion() << "volatile"
<< FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
- Diag(DS.getRestrictSpecLoc(),
+ Diag(DS.getRestrictSpecLoc(),
diag::ext_anonymous_struct_union_qualified)
- << Record->isUnion() << 2
+ << Record->isUnion() << "restrict"
<< FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(DS.getAtomicSpecLoc(),
+ diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << "_Atomic"
+ << FixItHint::CreateRemoval(DS.getAtomicSpecLoc());
DS.ClearTypeQualifiers();
}
@@ -3088,6 +3472,13 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
<< (int)Record->isUnion();
Invalid = true;
}
+ } else {
+ // This is an anonymous type definition within another anonymous type.
+ // This is a popular extension, provided by Plan9, MSVC and GCC, but
+ // not part of standard C++.
+ Diag(MemRecord->getLocation(),
+ diag::ext_anonymous_record_with_anonymous_type)
+ << (int)Record->isUnion();
}
} else if (isa<AccessSpecDecl>(*Mem)) {
// Any access specifier is fine.
@@ -3153,15 +3544,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
SC = SC_None;
}
- SCSpec = DS.getStorageClassSpecAsWritten();
- VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec);
Anon = VarDecl::Create(Context, Owner,
DS.getLocStart(),
Record->getLocation(), /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- TInfo, SC, SCAsWritten);
+ TInfo, SC);
// Default-initialize the implicit variable. This initialization will be
// trivial in almost all cases, except if a union member has an in-class
@@ -3383,7 +3771,7 @@ static QualType getCoreType(QualType Ty) {
static bool hasSimilarParameters(ASTContext &Context,
FunctionDecl *Declaration,
FunctionDecl *Definition,
- llvm::SmallVectorImpl<unsigned> &Params) {
+ SmallVectorImpl<unsigned> &Params) {
Params.clear();
if (Declaration->param_size() != Definition->param_size())
return false;
@@ -3609,8 +3997,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
return false;
}
-Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParamLists) {
+NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParamLists) {
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -3690,8 +4078,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
return 0;
- NamedDecl *New;
-
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
@@ -3776,6 +4162,13 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
Previous.clear();
+ // Check that there are no default arguments other than in the parameters
+ // of a function declaration (C++ only).
+ if (getLangOpts().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ NamedDecl *New;
+
bool AddToScope = true;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
if (TemplateParamLists.size()) {
@@ -3877,29 +4270,29 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
static void
FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) {
- if (PointerTypeLoc* SrcPTL = dyn_cast<PointerTypeLoc>(&SrcTL)) {
- PointerTypeLoc* DstPTL = cast<PointerTypeLoc>(&DstTL);
- FixInvalidVariablyModifiedTypeLoc(SrcPTL->getPointeeLoc(),
- DstPTL->getPointeeLoc());
- DstPTL->setStarLoc(SrcPTL->getStarLoc());
+ if (PointerTypeLoc SrcPTL = SrcTL.getAs<PointerTypeLoc>()) {
+ PointerTypeLoc DstPTL = DstTL.castAs<PointerTypeLoc>();
+ FixInvalidVariablyModifiedTypeLoc(SrcPTL.getPointeeLoc(),
+ DstPTL.getPointeeLoc());
+ DstPTL.setStarLoc(SrcPTL.getStarLoc());
return;
}
- if (ParenTypeLoc* SrcPTL = dyn_cast<ParenTypeLoc>(&SrcTL)) {
- ParenTypeLoc* DstPTL = cast<ParenTypeLoc>(&DstTL);
- FixInvalidVariablyModifiedTypeLoc(SrcPTL->getInnerLoc(),
- DstPTL->getInnerLoc());
- DstPTL->setLParenLoc(SrcPTL->getLParenLoc());
- DstPTL->setRParenLoc(SrcPTL->getRParenLoc());
+ if (ParenTypeLoc SrcPTL = SrcTL.getAs<ParenTypeLoc>()) {
+ ParenTypeLoc DstPTL = DstTL.castAs<ParenTypeLoc>();
+ FixInvalidVariablyModifiedTypeLoc(SrcPTL.getInnerLoc(),
+ DstPTL.getInnerLoc());
+ DstPTL.setLParenLoc(SrcPTL.getLParenLoc());
+ DstPTL.setRParenLoc(SrcPTL.getRParenLoc());
return;
}
- ArrayTypeLoc* SrcATL = cast<ArrayTypeLoc>(&SrcTL);
- ArrayTypeLoc* DstATL = cast<ArrayTypeLoc>(&DstTL);
- TypeLoc SrcElemTL = SrcATL->getElementLoc();
- TypeLoc DstElemTL = DstATL->getElementLoc();
+ ArrayTypeLoc SrcATL = SrcTL.castAs<ArrayTypeLoc>();
+ ArrayTypeLoc DstATL = DstTL.castAs<ArrayTypeLoc>();
+ TypeLoc SrcElemTL = SrcATL.getElementLoc();
+ TypeLoc DstElemTL = DstATL.getElementLoc();
DstElemTL.initializeFullCopy(SrcElemTL);
- DstATL->setLBracketLoc(SrcATL->getLBracketLoc());
- DstATL->setSizeExpr(SrcATL->getSizeExpr());
- DstATL->setRBracketLoc(SrcATL->getRBracketLoc());
+ DstATL.setLBracketLoc(SrcATL.getLBracketLoc());
+ DstATL.setSizeExpr(SrcATL.getSizeExpr());
+ DstATL.setRBracketLoc(SrcATL.getRBracketLoc());
}
/// Helper method to turn variable array types into constant array
@@ -3921,7 +4314,7 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo,
return FixedTInfo;
}
-/// \brief Register the given locally-scoped external C declaration so
+/// \brief Register the given locally-scoped extern "C" declaration so
/// that it can be found later for redeclarations
void
Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
@@ -3930,15 +4323,15 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
"Decl is not a locally-scoped decl!");
// Note that we have a locally-scoped external with this name.
- LocallyScopedExternalDecls[ND->getDeclName()] = ND;
+ LocallyScopedExternCDecls[ND->getDeclName()] = ND;
if (!Previous.isSingleResult())
return;
NamedDecl *PrevDecl = Previous.getFoundDecl();
- // If there was a previous declaration of this variable, it may be
- // in our identifier chain. Update the identifier chain with the new
+ // If there was a previous declaration of this entity, it may be in
+ // our identifier chain. Update the identifier chain with the new
// declaration.
if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
// The previous declaration was found on the identifer resolver
@@ -3962,38 +4355,42 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
}
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
-Sema::findLocallyScopedExternalDecl(DeclarationName Name) {
+Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
if (ExternalSource) {
// Load locally-scoped external decls from the external source.
SmallVector<NamedDecl *, 4> Decls;
- ExternalSource->ReadLocallyScopedExternalDecls(Decls);
+ ExternalSource->ReadLocallyScopedExternCDecls(Decls);
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = LocallyScopedExternalDecls.find(Decls[I]->getDeclName());
- if (Pos == LocallyScopedExternalDecls.end())
- LocallyScopedExternalDecls[Decls[I]->getDeclName()] = Decls[I];
+ = LocallyScopedExternCDecls.find(Decls[I]->getDeclName());
+ if (Pos == LocallyScopedExternCDecls.end())
+ LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I];
}
}
- return LocallyScopedExternalDecls.find(Name);
+ return LocallyScopedExternCDecls.find(Name);
}
/// \brief Diagnose function specifiers on a declaration of an identifier that
/// does not identify a function.
-void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
+void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
// FIXME: We should probably indicate the identifier in question to avoid
// confusion for constructs like "inline int a(), b;"
- if (D.getDeclSpec().isInlineSpecified())
- Diag(D.getDeclSpec().getInlineSpecLoc(),
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(),
diag::err_inline_non_function);
- if (D.getDeclSpec().isVirtualSpecified())
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ if (DS.isVirtualSpecified())
+ Diag(DS.getVirtualSpecLoc(),
diag::err_virtual_non_function);
- if (D.getDeclSpec().isExplicitSpecified())
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ if (DS.isExplicitSpecified())
+ Diag(DS.getExplicitSpecLoc(),
diag::err_explicit_non_function);
+
+ if (DS.isNoreturnSpecified())
+ Diag(DS.getNoreturnSpecLoc(),
+ diag::err_noreturn_non_function);
}
NamedDecl*
@@ -4009,12 +4406,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.clear();
}
- if (getLangOpts().CPlusPlus) {
- // Check that there are no default arguments (C++ only).
- CheckExtraCXXDefaultArguments(D);
- }
-
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
@@ -4090,6 +4482,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
// in an outer scope, it isn't the same thing.
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
/*ExplicitInstantiationOrSpecialization=*/false);
+ filterNonConflictingPreviousDecls(Context, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(NewTD, Previous);
@@ -4220,6 +4613,74 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
return false;
}
+static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
+ // 'weak' only applies to declarations with external linkage.
+ if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) {
+ if (ND.getLinkage() != ExternalLinkage) {
+ S.Diag(Attr->getLocation(), diag::err_attribute_weak_static);
+ ND.dropAttr<WeakAttr>();
+ }
+ }
+ if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) {
+ if (ND.hasExternalLinkage()) {
+ S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static);
+ ND.dropAttr<WeakRefAttr>();
+ }
+ }
+}
+
+/// Given that we are within the definition of the given function,
+/// will that definition behave like C99's 'inline', where the
+/// definition is discarded except for optimization purposes?
+static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) {
+ // Try to avoid calling GetGVALinkageForFunction.
+
+ // All cases of this require the 'inline' keyword.
+ if (!FD->isInlined()) return false;
+
+ // This is only possible in C++ with the gnu_inline attribute.
+ if (S.getLangOpts().CPlusPlus && !FD->hasAttr<GNUInlineAttr>())
+ return false;
+
+ // Okay, go ahead and call the relatively-more-expensive function.
+
+#ifndef NDEBUG
+ // AST quite reasonably asserts that it's working on a function
+ // definition. We don't really have a way to tell it that we're
+ // currently defining the function, so just lie to it in +Asserts
+ // builds. This is an awful hack.
+ FD->setLazyBody(1);
+#endif
+
+ bool isC99Inline = (S.Context.GetGVALinkageForFunction(FD) == GVA_C99Inline);
+
+#ifndef NDEBUG
+ FD->setLazyBody(0);
+#endif
+
+ return isC99Inline;
+}
+
+static bool shouldConsiderLinkage(const VarDecl *VD) {
+ const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
+ if (DC->isFunctionOrMethod())
+ return VD->hasExternalStorage();
+ if (DC->isFileContext())
+ return true;
+ if (DC->isRecord())
+ return false;
+ llvm_unreachable("Unexpected context");
+}
+
+static bool shouldConsiderLinkage(const FunctionDecl *FD) {
+ const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
+ if (DC->isFileContext() || DC->isFunctionOrMethod())
+ return true;
+ if (DC->isRecord())
+ return false;
+ llvm_unreachable("Unexpected context");
+}
+
NamedDecl*
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -4227,14 +4688,21 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
- // Check that there are no default arguments (C++ only).
- if (getLangOpts().CPlusPlus)
- CheckExtraCXXDefaultArguments(D);
-
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+
+ 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 (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -4242,9 +4710,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setInvalidType();
SC = SC_None;
}
- SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
- VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -4253,7 +4718,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
return 0;
}
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
if (!DC->isRecord() && S->getFnParent() == 0) {
// C99 6.9p2: The storage-class specifiers auto and register shall not
@@ -4273,8 +4738,33 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().OpenCL) {
// Set up the special work-group-local storage class for variables in the
// OpenCL __local address space.
- if (R.getAddressSpace() == LangAS::opencl_local)
+ if (R.getAddressSpace() == LangAS::opencl_local) {
SC = SC_OpenCLWorkGroupLocal;
+ }
+
+ // OpenCL v1.2 s6.9.b p4:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local ||
+ R.getAddressSpace() == LangAS::opencl_global)) {
+ Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ }
+
+ // OpenCL 1.2 spec, p6.9 r:
+ // The event type cannot be used to declare a program scope variable.
+ // The event type cannot be used with the __local, __constant and __global
+ // address space qualifiers.
+ if (R->isEventT()) {
+ if (S->getParent() == 0) {
+ Diag(D.getLocStart(), diag::err_event_t_global_var);
+ D.setInvalidType();
+ }
+
+ if (R.getAddressSpace()) {
+ Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
+ D.setInvalidType();
+ }
+ }
}
bool isExplicitSpecialization = false;
@@ -4282,7 +4772,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!getLangOpts().CPlusPlus) {
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
- R, TInfo, SC, SCAsWritten);
+ R, TInfo, SC);
if (D.isInvalidType())
NewVD->setInvalidDecl();
@@ -4293,8 +4783,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
- } else if (SC == SC_None)
- SC = SC_Static;
+ }
}
if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
@@ -4307,7 +4796,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// the program is ill-formed. C++11 drops this restriction.
if (RD->isUnion())
Diag(D.getIdentifierLoc(),
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_static_data_member_in_union
: diag::ext_static_data_member_in_union) << Name;
// We conservatively disallow static data members in anonymous structs.
@@ -4352,7 +4841,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
- R, TInfo, SC, SCAsWritten);
+ R, TInfo, SC);
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
@@ -4388,6 +4877,25 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setThreadSpecified(true);
}
+ // C99 6.7.4p3
+ // An inline definition of a function with external linkage shall
+ // not contain a definition of a modifiable object with static or
+ // thread storage duration...
+ // We only apply this when the function is required to be defined
+ // elsewhere, i.e. when the function is not 'extern inline'. Note
+ // 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 &&
+ !NewVD->getType().isConstQualified()) {
+ FunctionDecl *CurFD = getCurFunctionDecl();
+ if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) {
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::warn_static_local_in_extern_inline);
+ MaybeSuggestAddingStaticToDecl(CurFD);
+ }
+ }
+
if (D.getDeclSpec().isModulePrivateSpecified()) {
if (isExplicitSpecialization)
Diag(NewVD->getLocation(), diag::err_module_private_specialization)
@@ -4405,12 +4913,17 @@ 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 &&
- (NewVD->hasAttr<CUDASharedAttr>() || NewVD->hasAttr<CUDAConstantAttr>()))
+ (NewVD->hasAttr<CUDASharedAttr>() ||
+ NewVD->hasAttr<CUDAConstantAttr>())) {
NewVD->setStorageClass(SC_Static);
+ }
}
// In auto-retain/release, infer strong retension for variables of
@@ -4459,7 +4972,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// 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, DC, S, NewVD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD),
isExplicitSpecialization);
if (!getLangOpts().CPlusPlus) {
@@ -4493,19 +5006,15 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
+ ProcessPragmaWeak(S, NewVD);
+ checkAttributesAfterMerging(*this, *NewVD);
+
// If this is a locally-scoped extern C variable, update the map of
// such variables.
if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
!NewVD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewVD, Previous, S);
- // If there's a #pragma GCC visibility in scope, and this isn't a class
- // member, set the visibility of this variable.
- if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord())
- AddPushedVisibilityAttribute(NewVD);
-
- MarkUnusedFileScopedDecl(NewVD);
-
return NewVD;
}
@@ -4604,6 +5113,32 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
CheckShadow(S, D, R);
}
+template<typename T>
+static bool mayConflictWithNonVisibleExternC(const T *ND) {
+ const DeclContext *DC = ND->getDeclContext();
+ if (DC->getRedeclContext()->isTranslationUnit())
+ return true;
+
+ // We know that is the first decl we see, other than function local
+ // extern C ones. If this is C++ and the decl is not in a extern C context
+ // it cannot have C language linkage. Avoid calling isExternC in that case.
+ // We need to this because of code like
+ //
+ // namespace { struct bar {}; }
+ // auto foo = bar();
+ //
+ // This code runs before the init of foo is set, and therefore before
+ // the type of foo is known. Not knowing the type we cannot know its linkage
+ // unless it is in an extern C block.
+ if (!DC->isExternCContext()) {
+ const ASTContext &Context = ND->getASTContext();
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
+ }
+
+ return ND->isExternC();
+}
+
/// \brief Perform semantic checking on a newly-created variable
/// declaration.
///
@@ -4706,16 +5241,44 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
NewVD->setTypeSourceInfo(FixedTInfo);
}
- if (Previous.empty() && NewVD->isExternC()) {
- // Since we did not find anything by this name and we're declaring
- // an extern "C" variable, look for a non-visible extern "C"
- // declaration with the same name.
+ // If we did not find anything by this name, look for a non-visible
+ // extern "C" declaration with the same name.
+ //
+ // Clang has a lot of problems with extern local declarations.
+ // The actual standards text here is:
+ //
+ // C++11 [basic.link]p6:
+ // The name of a function declared in block scope and the name
+ // of a variable declared by a block scope extern declaration
+ // have linkage. If there is a visible declaration of an entity
+ // with linkage having the same name and type, ignoring entities
+ // declared outside the innermost enclosing namespace scope, the
+ // block scope declaration declares that same entity and
+ // receives the linkage of the previous declaration.
+ //
+ // C11 6.2.7p4:
+ // For an identifier with internal or external linkage declared
+ // in a scope in which a prior declaration of that identifier is
+ // visible, if the prior declaration specifies internal or
+ // external linkage, the type of the identifier at the later
+ // declaration becomes the composite type.
+ //
+ // The most important point here is that we're not allowed to
+ // update our understanding of the type according to declarations
+ // not in scope.
+ bool PreviousWasHidden = false;
+ if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternalDecl(NewVD->getDeclName());
- if (Pos != LocallyScopedExternalDecls.end())
+ = findLocallyScopedExternCDecl(NewVD->getDeclName());
+ if (Pos != LocallyScopedExternCDecls.end()) {
Previous.addDecl(Pos->second);
+ PreviousWasHidden = true;
+ }
}
+ // Filter out any non-conflicting previous declarations.
+ filterNonConflictingPreviousDecls(Context, NewVD, Previous);
+
if (T->isVoidType() && !NewVD->hasExternalStorage()) {
Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
<< T;
@@ -4743,7 +5306,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
}
if (!Previous.empty()) {
- MergeVarDecl(NewVD, Previous);
+ MergeVarDecl(NewVD, Previous, PreviousWasHidden);
return true;
}
return false;
@@ -4778,9 +5341,9 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
}
for (Path.Decls = BaseRecord->lookup(Name);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- NamedDecl *D = *Path.Decls.first;
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ NamedDecl *D = Path.Decls.front();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, false))
return true;
@@ -4832,6 +5395,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
+ !CheckOverridingFunctionAttributes(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
hasDeletedOverridenMethods |= OldMD->isDeleted();
@@ -4878,7 +5442,7 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
if (candidate.getEditDistance() == 0)
return false;
- llvm::SmallVector<unsigned, 1> MismatchedParams;
+ SmallVector<unsigned, 1> MismatchedParams;
for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
CDeclEnd = candidate.end();
CDecl != CDeclEnd; ++CDecl) {
@@ -4924,8 +5488,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
DeclContext *NewDC = NewFD->getDeclContext();
LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- llvm::SmallVector<unsigned, 1> MismatchedParams;
- llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;
+ SmallVector<unsigned, 1> MismatchedParams;
+ SmallVector<std::pair<FunctionDecl *, unsigned>, 1> NearMatches;
TypoCorrection Correction;
bool isFriendDecl = (SemaRef.getLangOpts().CPlusPlus &&
ExtraArgs.D.getDeclSpec().isFriendSpecified());
@@ -5029,7 +5593,7 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
NewFDisConst = NewMD->isConst();
- for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator
+ for (SmallVector<std::pair<FunctionDecl *, unsigned>, 1>::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
NearMatch != NearMatchEnd; ++NearMatch) {
FunctionDecl *FD = NearMatch->first;
@@ -5098,9 +5662,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
FunctionDecl *NewFD = 0;
bool isInline = D.getDeclSpec().isInlineSpecified();
- DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
- FunctionDecl::StorageClass SCAsWritten
- = StorageClassSpecToFunctionDeclStorageClass(SCSpec);
if (!SemaRef.getLangOpts().CPlusPlus) {
// Determine whether the function was written with a
@@ -5114,8 +5675,8 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
NewFD = FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(), NameInfo, R,
- TInfo, SC, SCAsWritten, isInline,
- HasPrototype);
+ TInfo, SC, isInline,
+ HasPrototype, false);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -5164,7 +5725,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// If the class is complete, then we now create the implicit exception
// specification. If the class is incomplete or dependent, we can't do
// it yet.
- if (SemaRef.getLangOpts().CPlusPlus0x && !Record->isDependentType() &&
+ if (SemaRef.getLangOpts().CPlusPlus11 && !Record->isDependentType() &&
Record->getDefinition() && !Record->isBeingDefined() &&
R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
@@ -5182,7 +5743,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(),
D.getIdentifierLoc(), Name, R, TInfo,
- SC, SCAsWritten, isInline,
+ SC, isInline,
/*hasPrototype=*/true, isConstexpr);
}
@@ -5213,36 +5774,21 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return 0;
}
- bool isStatic = SC == SC_Static;
-
- // [class.free]p1:
- // Any allocation function for a class T is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_New ||
- Name.getCXXOverloadedOperator() == OO_Array_New)
- isStatic = true;
-
- // [class.free]p6 Any deallocation function for a class X is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_Delete ||
- Name.getCXXOverloadedOperator() == OO_Array_Delete)
- isStatic = true;
-
- IsVirtualOkay = !isStatic;
-
// This is a C++ method declaration.
- return CXXMethodDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
- D.getLocStart(), NameInfo, R,
- TInfo, isStatic, SCAsWritten, isInline,
- isConstexpr, SourceLocation());
-
+ CXXMethodDecl *Ret = CXXMethodDecl::Create(SemaRef.Context,
+ cast<CXXRecordDecl>(DC),
+ D.getLocStart(), NameInfo, R,
+ TInfo, SC, isInline,
+ isConstexpr, SourceLocation());
+ IsVirtualOkay = !Ret->isStatic();
+ return Ret;
} else {
// Determine whether the function was written with a
// prototype. This true when:
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(),
- NameInfo, R, TInfo, SC, SCAsWritten, isInline,
+ NameInfo, R, TInfo, SC, isInline,
true/*HasPrototype*/, isConstexpr);
}
}
@@ -5291,8 +5837,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
T = Context.getObjCObjectPointerType(T);
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- R = Context.getFunctionType(T, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ R = Context.getFunctionType(T,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
else if (isa<FunctionNoProtoType>(R))
R = Context.getFunctionNoProtoType(T);
@@ -5504,11 +6052,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (isConstexpr) {
- // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors
+ // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
NewFD->setImplicitlyInline();
- // C++0x [dcl.constexpr]p3: functions declared constexpr are required to
+ // C++11 [dcl.constexpr]p3: functions declared constexpr are required to
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
if (isa<CXXDestructorDecl>(NewFD))
@@ -5583,17 +6131,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
if ((Name.getCXXOverloadedOperator() == OO_Delete ||
Name.getCXXOverloadedOperator() == OO_Array_Delete) &&
- getLangOpts().CPlusPlus0x && FPT && !FPT->hasExceptionSpec()) {
+ getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExceptionSpecType = EST_BasicNoexcept;
NewFD->setType(Context.getFunctionType(FPT->getResultType(),
- FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI));
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
}
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -5675,6 +6224,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope);
DeclsInPrototypeScope.clear();
+ if (D.getDeclSpec().isNoreturnSpecified())
+ NewFD->addAttr(
+ ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
+ Context));
+
// Process the non-inheritable attributes on this declaration.
ProcessDeclAttributes(S, NewFD, D,
/*NonInheritable=*/true, /*Inheritable=*/false);
@@ -5691,6 +6245,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
ProcessDeclAttributes(S, NewFD, D,
/*NonInheritable=*/false, /*Inheritable=*/true);
+ QualType RetType = NewFD->getResultType();
+ 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);
+ if (!(MD && MD->getCorrespondingMethodInClass(Ret, true))) {
+ NewFD->addAttr(new (Context) WarnUnusedResultAttr(SourceRange(),
+ Context));
+ }
+ }
+
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
@@ -5788,7 +6354,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
if (SC != SC_None) {
- if (SC != NewFD->getStorageClass())
+ if (SC != NewFD->getTemplateSpecializationInfo()->getTemplate()->getTemplatedDecl()->getStorageClass())
Diag(NewFD->getLocation(),
diag::err_explicit_specialization_inconsistent_storage_class)
<< SC
@@ -5938,6 +6504,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ ProcessPragmaWeak(S, NewFD);
+ checkAttributesAfterMerging(*this, *NewFD);
+
AddKnownFunctionAttributes(NewFD);
if (NewFD->hasAttr<OverloadableAttr>() &&
@@ -5952,13 +6521,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
EPI.Variadic = true;
EPI.ExtInfo = FT->getExtInfo();
- QualType R = Context.getFunctionType(FT->getResultType(), 0, 0, EPI);
+ QualType R = Context.getFunctionType(FT->getResultType(),
+ ArrayRef<QualType>(),
+ EPI);
NewFD->setType(R);
}
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this function.
- if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord())
+ if (!DC->isRecord() && NewFD->hasExternalLinkage())
AddPushedVisibilityAttribute(NewFD);
// If there's a #pragma clang arc_cf_code_audited in scope, consider
@@ -5982,12 +6553,42 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- // OpenCL v1.2 s6.8 static is invalid for kernel functions.
- if ((getLangOpts().OpenCLVersion >= 120)
- && NewFD->hasAttr<OpenCLKernelAttr>()
- && (SC == SC_Static)) {
- Diag(D.getIdentifierLoc(), diag::err_static_kernel);
- D.setInvalidType();
+ if (NewFD->hasAttr<OpenCLKernelAttr>()) {
+ // OpenCL v1.2 s6.8 static is invalid for kernel functions.
+ if ((getLangOpts().OpenCLVersion >= 120)
+ && (SC == SC_Static)) {
+ Diag(D.getIdentifierLoc(), diag::err_static_kernel);
+ D.setInvalidType();
+ }
+
+ // 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);
+ D.setInvalidType();
+ }
+
+ for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
+ PE = NewFD->param_end(); PI != PE; ++PI) {
+ ParmVarDecl *Param = *PI;
+ QualType PT = Param->getType();
+
+ // OpenCL v1.2 s6.9.a:
+ // A kernel function argument cannot be declared as a
+ // pointer to a pointer type.
+ if (PT->isPointerType() && PT->getPointeeType()->isPointerType()) {
+ Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_arg);
+ D.setInvalidType();
+ }
+
+ // OpenCL v1.2 s6.8 n:
+ // A kernel function argument cannot be declared
+ // of event_t type.
+ if (PT->isEventT()) {
+ Diag(Param->getLocation(), diag::err_event_t_kernel_arg);
+ D.setInvalidType();
+ }
+ }
}
MarkUnusedFileScopedDecl(NewFD);
@@ -6043,17 +6644,20 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
&& "Variably modified return types are not handled here");
// Check for a previous declaration of this name.
- if (Previous.empty() && NewFD->isExternC()) {
- // Since we did not find anything by this name and we're declaring
- // an extern "C" function, look for a non-visible extern "C"
- // declaration with the same name.
+ if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) {
+ // Since we did not find anything by this name, look for a non-visible
+ // extern "C" declaration with the same name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternalDecl(NewFD->getDeclName());
- if (Pos != LocallyScopedExternalDecls.end())
+ = findLocallyScopedExternCDecl(NewFD->getDeclName());
+ if (Pos != LocallyScopedExternCDecls.end())
Previous.addDecl(Pos->second);
}
+ // Filter out any non-conflicting previous declarations.
+ filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+
bool Redeclaration = false;
+ NamedDecl *OldDecl = 0;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -6062,8 +6666,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
-
- NamedDecl *OldDecl = 0;
if (!AllowOverloadingOfFunction(Previous, Context)) {
Redeclaration = true;
OldDecl = Previous.getFoundDecl();
@@ -6100,42 +6702,90 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Context));
}
}
+ }
- if (Redeclaration) {
- // NewFD and OldDecl represent declarations that need to be
- // merged.
- if (MergeFunctionDecl(NewFD, OldDecl, S)) {
- NewFD->setInvalidDecl();
- return Redeclaration;
- }
+ // C++11 [dcl.constexpr]p8:
+ // A constexpr specifier for a non-static member function that is not
+ // a constructor declares that member function to be const.
+ //
+ // This needs to be delayed until we know whether this is an out-of-line
+ // definition of a static member function.
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ if (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());
+ 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(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
+ }
+ }
- Previous.clear();
- Previous.addDecl(OldDecl);
-
- if (FunctionTemplateDecl *OldTemplateDecl
- = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
- NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
- FunctionTemplateDecl *NewTemplateDecl
- = NewFD->getDescribedFunctionTemplate();
- assert(NewTemplateDecl && "Template/non-template mismatch");
- if (CXXMethodDecl *Method
- = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
- Method->setAccess(OldTemplateDecl->getAccess());
- NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
- }
-
- // If this is an explicit specialization of a member that is a function
- // template, mark it as a member specialization.
- if (IsExplicitSpecialization &&
- NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
- NewTemplateDecl->setMemberSpecialization();
- assert(OldTemplateDecl->isMemberSpecialization());
+ if (Redeclaration) {
+ // NewFD and OldDecl represent declarations that need to be
+ // merged.
+ if (MergeFunctionDecl(NewFD, OldDecl, S)) {
+ NewFD->setInvalidDecl();
+ return Redeclaration;
+ }
+
+ Previous.clear();
+ Previous.addDecl(OldDecl);
+
+ if (FunctionTemplateDecl *OldTemplateDecl
+ = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ FunctionTemplateDecl *NewTemplateDecl
+ = NewFD->getDescribedFunctionTemplate();
+ assert(NewTemplateDecl && "Template/non-template mismatch");
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
+ Method->setAccess(OldTemplateDecl->getAccess());
+ NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
+ }
+
+ // If this is an explicit specialization of a member that is a function
+ // template, mark it as a member specialization.
+ if (IsExplicitSpecialization &&
+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+ NewTemplateDecl->setMemberSpecialization();
+ assert(OldTemplateDecl->isMemberSpecialization());
+ }
+
+ } else {
+ // This needs to happen first so that 'inline' propagates.
+ NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+
+ if (isa<CXXMethodDecl>(NewFD)) {
+ // A valid redeclaration of a C++ method must be out-of-line,
+ // but (unfortunately) it's not necessarily a definition
+ // because of templates, which means that the previous
+ // declaration is not necessarily from the class definition.
+
+ // For just setting the access, that doesn't matter.
+ CXXMethodDecl *oldMethod = cast<CXXMethodDecl>(OldDecl);
+ NewFD->setAccess(oldMethod->getAccess());
+
+ // Update the key-function state if necessary for this ABI.
+ if (NewFD->isInlined() &&
+ !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ // setNonKeyFunction needs to work with the original
+ // declaration from the class definition, and isVirtual() is
+ // just faster in that case, so map back to that now.
+ oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDeclaration());
+ if (oldMethod->isVirtual()) {
+ Context.setNonKeyFunction(oldMethod);
+ }
}
-
- } else {
- if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
- NewFD->setAccess(OldDecl->getAccess());
- NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
}
}
}
@@ -6208,6 +6858,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// declaration against the expected type for the builtin.
if (unsigned BuiltinID = NewFD->getBuiltinID()) {
ASTContext::GetBuiltinTypeError Error;
+ LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier());
QualType T = Context.GetBuiltinType(BuiltinID, Error);
if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) {
// The type of this function differs from the type of the builtin,
@@ -6219,7 +6870,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// If this function is declared as being extern "C", then check to see if
// the function returns a UDT (class, struct, or union type) that is not C
// compatible, and if it does, warn the user.
- if (NewFD->isExternC()) {
+ // But, issue any diagnostic on the first declaration only.
+ if (NewFD->isExternC() && Previous.empty()) {
QualType R = NewFD->getResultType();
if (R->isIncompleteType() && !R->isVoidType())
Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
@@ -6232,12 +6884,30 @@ 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.
- // C99 6.7.4p4: In a hosted environment, the inline function specifier
- // shall not appear in a declaration of main.
+ // 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.
+ // We accept _Noreturn main as an extension.
if (FD->getStorageClass() == SC_Static)
Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus
? diag::err_static_main : diag::warn_static_main)
@@ -6245,6 +6915,14 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
if (FD->isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_main)
<< FixItHint::CreateRemoval(DS.getInlineSpecLoc());
+ if (DS.isNoreturnSpecified()) {
+ SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc();
+ SourceRange NoreturnRange(NoreturnLoc,
+ PP.getLocForEndOfToken(NoreturnLoc));
+ Diag(NoreturnLoc, diag::ext_noreturn_main);
+ Diag(NoreturnLoc, diag::note_main_remove_noreturn)
+ << FixItHint::CreateRemoval(NoreturnRange);
+ }
if (FD->isConstexpr()) {
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main)
<< FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
@@ -6268,9 +6946,20 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
} 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 {
- Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+ SourceRange ResultRange = getResultSourceRange(FD);
+ if (ResultRange.isValid())
+ Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint)
+ << FixItHint::CreateReplacement(ResultRange, "int");
+ else
+ Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+
FD->setInvalidDecl(true);
}
@@ -6319,7 +7008,8 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
const PointerType* PT;
if ((PT = qs.strip(AT)->getAs<PointerType>()) &&
(PT = qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
- (QualType(qs.strip(PT->getPointeeType()), 0) == Context.CharTy)) {
+ Context.hasSameType(QualType(qs.strip(PT->getPointeeType()), 0),
+ Context.CharTy)) {
qs.removeConst();
mismatch = !qs.empty();
}
@@ -6457,6 +7147,14 @@ namespace {
Visit(Base);
}
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ if (E->getNumArgs() > 0)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getArg(0)))
+ HandleDeclRefExpr(DRE);
+
+ Inherited::VisitCXXOperatorCallExpr(E);
+ }
+
void VisitUnaryOperator(UnaryOperator *E) {
// For POD record types, addresses of its own members are well-defined.
if (E->getOpcode() == UO_AddrOf && isRecordType &&
@@ -6471,11 +7169,17 @@ namespace {
void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; }
void HandleDeclRefExpr(DeclRefExpr *DRE) {
- Decl* ReferenceDecl = DRE->getDecl();
+ Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
- unsigned diag = isReferenceType
- ? diag::warn_uninit_self_reference_in_reference_init
- : diag::warn_uninit_self_reference_in_init;
+ unsigned diag;
+ if (isReferenceType) {
+ diag = diag::warn_uninit_self_reference_in_reference_init;
+ } else if (cast<VarDecl>(OrigDecl)->isStaticLocal()) {
+ diag = diag::warn_static_self_reference_in_init;
+ } else {
+ diag = diag::warn_uninit_self_reference_in_init;
+ }
+
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
S.PDiag(diag)
<< DRE->getNameInfo().getName()
@@ -6572,6 +7276,20 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
DeduceInit = CXXDirectInit->getExpr(0);
}
}
+
+ // Expressions default to 'id' when we're in a debugger.
+ bool DefaultedToAuto = false;
+ if (getLangOpts().DebuggerCastResultToId &&
+ Init->getType() == Context.UnknownAnyTy) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+ Init = Result.take();
+ DefaultedToAuto = true;
+ }
+
TypeSourceInfo *DeducedType = 0;
if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) ==
DAR_Failed)
@@ -6582,8 +7300,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
- VDecl->ClearLinkageCache();
-
+ assert(VDecl->isLinkageValid());
+
// In ARC, infer lifetime.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
@@ -6592,7 +7310,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// 'id' instead of a specific object type prevents most of our usual checks.
// We only want to warn outside of template instantiations, though:
// inside a template, the 'id' could have come from a parameter.
- if (ActiveTemplateInstantiations.empty() &&
+ if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto &&
DeducedType->getType()->isObjCIdType()) {
SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc();
Diag(Loc, diag::warn_auto_var_is_id)
@@ -6602,7 +7320,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl())
- MergeVarDeclTypes(VDecl, Old);
+ MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
}
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
@@ -6683,17 +7401,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
- // Top-level message sends default to 'id' when we're in a debugger
- // and we are assigning it to a variable of 'id' type.
- if (getLangOpts().DebuggerCastResultToId && DclT->isObjCIdType())
- if (Init->getType() == Context.UnknownAnyTy && isa<ObjCMessageExpr>(Init)) {
- ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
- Init = Result.take();
+ // Expressions default to 'id' when we're in a debugger
+ // and we are assigning it to a variable of Objective-C pointer type.
+ if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() &&
+ Init->getType() == Context.UnknownAnyTy) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
}
+ Init = Result.take();
+ }
// Perform the initialization.
if (!VDecl->isInvalidDecl()) {
@@ -6740,9 +7458,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (!VDecl->isInvalidDecl() && (DclT != SavT))
VDecl->setType(DclT);
- // Check any implicit conversions within the expression.
- CheckImplicitConversions(Init, VDecl->getLocation());
-
if (!VDecl->isInvalidDecl()) {
checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
@@ -6765,7 +7480,26 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
}
- Init = MaybeCreateExprWithCleanups(Init);
+ // The initialization is usually a full-expression.
+ //
+ // FIXME: If this is a braced initialization of an aggregate, it is not
+ // an expression, and each individual field initializer is a separate
+ // full-expression. For instance, in:
+ //
+ // struct Temp { ~Temp(); };
+ // struct S { S(Temp); };
+ // struct T { S a, b; } t = { Temp(), Temp() }
+ //
+ // we should destroy the first Temp before constructing the second.
+ ExprResult Result = ActOnFinishFullExpr(Init, VDecl->getLocation(),
+ false,
+ VDecl->isConstexpr());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+ Init = Result.take();
+
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -6817,7 +7551,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
} else if (DclT->isIntegralOrEnumerationType()) {
// Check whether the expression is a constant expression.
SourceLocation Loc;
- if (getLangOpts().CPlusPlus0x && DclT.isVolatileQualified())
+ if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified())
// In C++11, a non-constexpr const static data member with an
// in-class initializer cannot be volatile.
Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile);
@@ -6840,21 +7574,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// We allow foldable floating-point constants as an extension.
} else if (DclT->isFloatingType()) { // also permits complex, which is ok
- Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
- << DclT << Init->getSourceRange();
- if (getLangOpts().CPlusPlus0x)
+ // In C++98, this is a GNU extension. In C++11, it is not, but we support
+ // it anyway and provide a fixit to add the 'constexpr'.
+ if (getLangOpts().CPlusPlus11) {
Diag(VDecl->getLocation(),
- diag::note_in_class_initializer_float_type_constexpr)
- << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
+ diag::ext_in_class_initializer_float_type_cxx11)
+ << DclT << Init->getSourceRange();
+ Diag(VDecl->getLocStart(),
+ diag::note_in_class_initializer_float_type_cxx11)
+ << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
+ } else {
+ Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
+ << DclT << Init->getSourceRange();
- if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) {
- Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
- << Init->getSourceRange();
- VDecl->setInvalidDecl();
+ if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) {
+ Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ VDecl->setInvalidDecl();
+ }
}
// Suggest adding 'constexpr' in C++11 for literal types.
- } else if (getLangOpts().CPlusPlus0x && DclT->isLiteralType()) {
+ } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType()) {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type)
<< DclT << Init->getSourceRange()
<< FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
@@ -6866,9 +7607,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
}
} else if (VDecl->isFileVarDecl()) {
- if (VDecl->getStorageClassAsWritten() == SC_Extern &&
+ if (VDecl->getStorageClass() == SC_Extern &&
(!getLangOpts().CPlusPlus ||
- !Context.getBaseElementType(VDecl->getType()).isConstQualified()))
+ !(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
+ VDecl->isExternC())))
Diag(VDecl->getLocation(), diag::warn_extern_init);
// C99 6.7.8p4. All file scoped initializers need to be constant.
@@ -7155,7 +7897,7 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
// for-range-declaration cannot be given a storage class specifier.
int Error = -1;
- switch (VD->getStorageClassAsWritten()) {
+ switch (VD->getStorageClass()) {
case SC_None:
break;
case SC_Extern:
@@ -7206,7 +7948,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
if (var->isThisDeclarationADefinition() &&
- var->getLinkage() == ExternalLinkage) {
+ var->hasExternalLinkage() &&
+ getDiagnostics().getDiagnosticLevel(
+ diag::warn_missing_variable_declarations,
+ var->getLocation())) {
// Find a previous declaration that's not a definition.
VarDecl *prev = var->getPreviousDecl();
while (prev && prev->isThisDeclarationADefinition())
@@ -7230,12 +7975,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Regardless, we don't want to ignore array nesting when
// constructing this copy.
if (type->isStructureOrClassType()) {
+ EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
SourceLocation poi = var->getLocation();
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
- ExprResult result =
- PerformCopyInitialization(
- InitializedEntity::InitializeBlock(poi, type, false),
- poi, Owned(varRef));
+ ExprResult result
+ = PerformMoveOrCopyInitialization(
+ InitializedEntity::InitializeBlock(poi, type, false),
+ var, var->getType(), varRef, /*AllowNRVO=*/true);
if (!result.isInvalid()) {
result = MaybeCreateExprWithCleanups(result);
Expr *init = result.takeAs<Expr>();
@@ -7259,7 +8005,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
<< Init->getSourceRange();
if (var->isConstexpr()) {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
if (!var->evaluateValue(Notes) || !var->isInitICE()) {
SourceLocation DiagLoc = var->getLocation();
// If the note doesn't add any useful information other than a source
@@ -7294,40 +8040,52 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
// Note that we are no longer parsing the initializer for this declaration.
ParsingInitForAutoVars.erase(ThisDecl);
+ VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDecl);
+ if (!VD)
+ return;
+
+ 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->hasExternalLinkage())
+ AddPushedVisibilityAttribute(VD);
+
+ if (VD->isFileVarDecl())
+ MarkUnusedFileScopedDecl(VD);
+
// Now we have parsed the initializer and can update the table of magic
// tag values.
- if (ThisDecl && ThisDecl->hasAttr<TypeTagForDatatypeAttr>()) {
- const VarDecl *VD = dyn_cast<VarDecl>(ThisDecl);
- if (VD && VD->getType()->isIntegralOrEnumerationType()) {
- for (specific_attr_iterator<TypeTagForDatatypeAttr>
- I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(),
- E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>();
- I != E; ++I) {
- const Expr *MagicValueExpr = VD->getInit();
- if (!MagicValueExpr) {
- continue;
- }
- llvm::APSInt MagicValueInt;
- if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) {
- Diag(I->getRange().getBegin(),
- diag::err_type_tag_for_datatype_not_ice)
- << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
- continue;
- }
- if (MagicValueInt.getActiveBits() > 64) {
- Diag(I->getRange().getBegin(),
- diag::err_type_tag_for_datatype_too_large)
- << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
- continue;
- }
- uint64_t MagicValue = MagicValueInt.getZExtValue();
- RegisterTypeTagForDatatype(I->getArgumentKind(),
- MagicValue,
- I->getMatchingCType(),
- I->getLayoutCompatible(),
- I->getMustBeNull());
- }
+ if (!VD->hasAttr<TypeTagForDatatypeAttr>() ||
+ !VD->getType()->isIntegralOrEnumerationType())
+ return;
+
+ for (specific_attr_iterator<TypeTagForDatatypeAttr>
+ I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(),
+ E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>();
+ I != E; ++I) {
+ const Expr *MagicValueExpr = VD->getInit();
+ if (!MagicValueExpr) {
+ continue;
+ }
+ llvm::APSInt MagicValueInt;
+ if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) {
+ Diag(I->getRange().getBegin(),
+ diag::err_type_tag_for_datatype_not_ice)
+ << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
+ continue;
+ }
+ if (MagicValueInt.getActiveBits() > 64) {
+ Diag(I->getRange().getBegin(),
+ diag::err_type_tag_for_datatype_too_large)
+ << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
+ continue;
}
+ uint64_t MagicValue = MagicValueInt.getZExtValue();
+ RegisterTypeTagForDatatype(I->getArgumentKind(),
+ MagicValue,
+ I->getMatchingCType(),
+ I->getLayoutCompatible(),
+ I->getMustBeNull());
}
}
@@ -7343,6 +8101,10 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (Decl *D = Group[i])
Decls.push_back(D);
+ if (DeclSpec::isDeclRep(DS.getTypeSpecType()))
+ if (const TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()))
+ getASTContext().addUnnamedTag(Tag);
+
return BuildDeclaratorGroup(Decls.data(), Decls.size(),
DS.getTypeSpecType() == DeclSpec::TST_auto);
}
@@ -7449,14 +8211,11 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
// C++03 [dcl.stc]p2 also permits 'auto'.
VarDecl::StorageClass StorageClass = SC_None;
- VarDecl::StorageClass StorageClassAsWritten = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
StorageClass = SC_Register;
- StorageClassAsWritten = SC_Register;
} else if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
StorageClass = SC_Auto;
- StorageClassAsWritten = SC_Auto;
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
@@ -7469,7 +8228,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 0;
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
@@ -7529,7 +8288,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
D.getLocStart(),
D.getIdentifierLoc(), II,
parmDeclType, TInfo,
- StorageClass, StorageClassAsWritten);
+ StorageClass);
if (D.isInvalidType())
New->setInvalidDecl();
@@ -7568,7 +8327,7 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
location for the unnamed parameters, embedding the parameter's type? */
ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, 0,
T, Context.getTrivialTypeSourceInfo(T, Loc),
- SC_None, SC_None, 0);
+ SC_None, 0);
Param->setImplicit();
return Param;
}
@@ -7621,8 +8380,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
SourceLocation NameLoc, IdentifierInfo *Name,
QualType T, TypeSourceInfo *TSInfo,
- VarDecl::StorageClass StorageClass,
- VarDecl::StorageClass StorageClassAsWritten) {
+ VarDecl::StorageClass StorageClass) {
// In ARC, infer a lifetime qualifier for appropriate parameter types.
if (getLangOpts().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -7649,8 +8407,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
Context.getAdjustedParameterType(T),
TSInfo,
- StorageClass, StorageClassAsWritten,
- 0);
+ StorageClass, 0);
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -7730,7 +8487,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
-static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
+static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
+ const FunctionDecl*& PossibleZeroParamPrototype) {
// Don't warn about invalid declarations.
if (FD->isInvalidDecl())
return false;
@@ -7772,6 +8530,8 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
continue;
MissingPrototype = !Prev->getType()->isFunctionProtoType();
+ if (FD->getNumParams() == 0)
+ PossibleZeroParamPrototype = Prev;
break;
}
@@ -7837,8 +8597,22 @@ 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.
- if (ShouldWarnAboutMissingPrototype(FD))
+ const FunctionDecl *PossibleZeroParamPrototype = 0;
+ if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
+
+ if (PossibleZeroParamPrototype) {
+ // We found a declaration that is not a prototype,
+ // but that could be a zero-parameter prototype
+ TypeSourceInfo* TI = PossibleZeroParamPrototype->getTypeSourceInfo();
+ TypeLoc TL = TI->getTypeLoc();
+ if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
+ Diag(PossibleZeroParamPrototype->getLocation(),
+ diag::note_declaration_not_a_prototype)
+ << PossibleZeroParamPrototype
+ << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+ }
+ }
if (FnBodyScope)
PushDeclContext(FnBodyScope, FD);
@@ -7913,7 +8687,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
<< "dllimport";
FD->setInvalidDecl();
- return FD;
+ return D;
}
// Visual C++ appears to not think this is an issue, so only issue
@@ -7930,7 +8704,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// We want to attach documentation to original Decl (which might be
// a function template).
ActOnDocumentableDecl(D);
- return FD;
+ return D;
}
/// \brief Given the set of return statements within a function body,
@@ -7967,6 +8741,33 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true);
}
+bool Sema::canSkipFunctionBody(Decl *D) {
+ if (!Consumer.shouldSkipFunctionBody(D))
+ return false;
+
+ if (isa<ObjCMethodDecl>(D))
+ return true;
+
+ FunctionDecl *FD = 0;
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ FD = FTD->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(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.
+ return !FD->isConstexpr();
+}
+
+Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Decl))
+ FD->setHasSkippedBody();
+ else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl))
+ MD->setHasSkippedBody();
+ return ActOnFinishFunctionBody(Decl, 0);
+}
+
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
return ActOnFinishFunctionBody(D, BodyArg, false);
}
@@ -7986,6 +8787,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
+ // The only way to be included in UndefinedButUsed is if there is an
+ // ODR use before the definition. Avoid the expensive map lookup if this
+ // is the first declaration.
+ if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) {
+ if (FD->getLinkage() != ExternalLinkage)
+ UndefinedButUsed.erase(FD);
+ else if (FD->isInlined() &&
+ (LangOpts.CPlusPlus || !LangOpts.GNUInline) &&
+ (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>()))
+ UndefinedButUsed.erase(FD);
+ }
+
// If the function implicitly returns zero (like 'main') or is naked,
// don't complain about missing return statements.
if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>())
@@ -8068,7 +8881,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (PP.getDiagnostics().hasErrorOccurred() ||
PP.getDiagnostics().getSuppressAllDiagnostics()) {
DiscardCleanupsInEvaluationContext();
- } else if (!isa<FunctionTemplateDecl>(dcl)) {
+ }
+ if (!PP.getDiagnostics().hasUncompilableErrorOccurred() &&
+ !isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
ActivePolicy = &WP;
@@ -8125,8 +8940,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// this name as a function or variable. If so, use that
// (non-visible) declaration, and complain about it.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternalDecl(&II);
- if (Pos != LocallyScopedExternalDecls.end()) {
+ = findLocallyScopedExternCDecl(&II);
+ if (Pos != LocallyScopedExternCDecls.end()) {
Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second;
Diag(Pos->second->getLocation(), diag::note_previous_declaration);
return Pos->second;
@@ -8202,7 +9017,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
DeclContext *PrevDC = CurContext;
CurContext = Context.getTranslationUnitDecl();
- FunctionDecl *FD = dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
+ FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
FD->setImplicit();
CurContext = PrevDC;
@@ -8376,9 +9191,13 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
QualType T = TI->getType();
- if (T->isDependentType() || T->isIntegralType(Context))
+ if (T->isDependentType())
return false;
+ if (const BuiltinType *BT = T->getAs<BuiltinType>())
+ if (BT->isInteger())
+ return false;
+
Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
return true;
}
@@ -8575,6 +9394,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TUK == TUK_Friend,
isExplicitSpecialization,
Invalid)) {
+ if (Kind == TTK_Enum) {
+ Diag(KWLoc, diag::err_enum_template);
+ return 0;
+ }
+
if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
// be a member of another template).
@@ -8703,6 +9527,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// shouldn't be diagnosing.
LookupName(Previous, S);
+ // When declaring or defining a tag, ignore ambiguities introduced
+ // by types using'ed into this scope.
if (Previous.isAmbiguous() &&
(TUK == TUK_Definition || TUK == TUK_Declaration)) {
LookupResult::Filter F = Previous.makeFilter();
@@ -8713,6 +9539,27 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
F.done();
}
+
+ // C++11 [namespace.memdef]p3:
+ // If the name in a friend declaration is neither qualified nor
+ // a template-id and the declaration is a function or an
+ // elaborated-type-specifier, the lookup to determine whether
+ // the entity has been previously declared shall not consider
+ // any scopes outside the innermost enclosing namespace.
+ //
+ // 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();
+ while (F.hasNext()) {
+ NamedDecl *ND = F.next();
+ DeclContext *DC = ND->getDeclContext()->getRedeclContext();
+ if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext()))
+ F.erase();
+ }
+ F.done();
+ }
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
@@ -9070,7 +9917,8 @@ CreateNewDecl:
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
- if (getLangOpts().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) {
+ if ((getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) &&
+ cast<EnumDecl>(New)->isFixed()) {
// C++0x: 7.2p2: opaque-enum-declaration.
// Conflicts are diagnosed above. Do nothing.
}
@@ -9250,7 +10098,9 @@ CreateNewDecl:
AddPushedVisibilityAttribute(New);
OwnedDecl = true;
- return New;
+ // 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;
}
void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
@@ -9330,7 +10180,11 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
-
+
+ if (getCurLexicalContext()->isObjCContainer() &&
+ Tag->getDeclContext()->isFileContext())
+ Tag->setTopLevelDeclInObjCContainer();
+
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
}
@@ -9479,14 +10333,24 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
}
}
- DiagnoseFunctionSpecifiers(D);
+ // TR 18037 does not allow fields to be declared with address spaces.
+ if (T.getQualifiers().hasAddressSpace()) {
+ Diag(Loc, diag::err_field_with_address_space);
+ D.setInvalidType();
+ }
+
+ // OpenCL 1.2 spec, s6.9 r:
+ // The event type cannot be used to declare a structure or union field.
+ if (LangOpts.OpenCL && T->isEventT()) {
+ Diag(Loc, diag::err_event_t_struct_field);
+ D.setInvalidType();
+ }
+
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- if (D.getDeclSpec().isConstexprSpecified())
- Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 2;
-
+
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = 0;
LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
@@ -9587,6 +10451,12 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
}
+ // OpenCL v1.2 s6.9.c: bitfields are not supported.
+ if (BitWidth && getLangOpts().OpenCL) {
+ Diag(Loc, diag::err_opencl_bitfields);
+ InvalidDecl = true;
+ }
+
// C99 6.7.2.1p8: A member of a structure or union may have any type other
// than a variably modified type.
if (!InvalidDecl && T->isVariablyModifiedType()) {
@@ -9686,10 +10556,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// FIXME: We need to pass in the attributes given an AST
// representation, not a parser representation.
- if (D)
+ if (D) {
// FIXME: What to pass instead of TUScope?
ProcessDeclAttributes(TUScope, NewFD, *D);
+ if (NewFD->hasAttrs())
+ CheckAlignasUnderalignment(NewFD);
+ }
+
// In auto-retain/release, infer strong retension for fields of
// retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
@@ -9711,24 +10585,29 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
QualType EltTy = Context.getBaseElementType(FD->getType());
if (const RecordType *RT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+ CXXRecordDecl *RDecl = cast<CXXRecordDecl>(RT->getDecl());
if (RDecl->getDefinition()) {
// We check for copy constructors before constructors
// because otherwise we'll never get complaints about
// copy constructors.
CXXSpecialMember member = CXXInvalid;
- if (!RDecl->hasTrivialCopyConstructor())
+ // We're required to check for any non-trivial constructors. Since the
+ // implicit default constructor is suppressed if there are any
+ // user-declared constructors, we just need to check that there is a
+ // trivial default constructor and a trivial copy constructor. (We don't
+ // worry about move constructors here, since this is a C++98 check.)
+ if (RDecl->hasNonTrivialCopyConstructor())
member = CXXCopyConstructor;
else if (!RDecl->hasTrivialDefaultConstructor())
member = CXXDefaultConstructor;
- else if (!RDecl->hasTrivialCopyAssignment())
+ else if (RDecl->hasNonTrivialCopyAssignment())
member = CXXCopyAssignment;
- else if (!RDecl->hasTrivialDestructor())
+ else if (RDecl->hasNonTrivialDestructor())
member = CXXDestructor;
if (member != CXXInvalid) {
- if (!getLangOpts().CPlusPlus0x &&
+ if (!getLangOpts().CPlusPlus11 &&
getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) {
// Objective-C++ ARC: it is an error to have a non-trivial field of
// a union. However, system headers in Objective-C programs
@@ -9744,192 +10623,17 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
}
}
- Diag(FD->getLocation(), getLangOpts().CPlusPlus0x ?
+ Diag(FD->getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member :
diag::err_illegal_union_or_anon_struct_member)
<< (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
- DiagnoseNontrivial(RT, member);
- return !getLangOpts().CPlusPlus0x;
- }
- }
- }
-
- return false;
-}
-
-/// If the given constructor is user-declared, produce a diagnostic explaining
-/// that it makes the class non-trivial.
-static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT,
- CXXConstructorDecl *CD,
- Sema::CXXSpecialMember CSM) {
- if (CD->isImplicit())
- return false;
-
- SourceLocation CtorLoc = CD->getLocation();
- S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM;
- return true;
-}
-
-/// DiagnoseNontrivial - Given that a class has a non-trivial
-/// special member, figure out why.
-void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
- QualType QT(T, 0U);
- CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
-
- // Check whether the member was user-declared.
- switch (member) {
- case CXXInvalid:
- break;
-
- case CXXDefaultConstructor:
- if (RD->hasUserDeclaredConstructor()) {
- typedef CXXRecordDecl::ctor_iterator ctor_iter;
- for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
- if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member))
- return;
-
- // No user-delcared constructors; look for constructor templates.
- typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
- tmpl_iter;
- for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end());
- TI != TE; ++TI) {
- CXXConstructorDecl *CD =
- dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl());
- if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member))
- return;
- }
- }
- break;
-
- case CXXCopyConstructor:
- if (RD->hasUserDeclaredCopyConstructor()) {
- SourceLocation CtorLoc =
- RD->getCopyConstructor(0)->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXMoveConstructor:
- if (RD->hasUserDeclaredMoveConstructor()) {
- SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXCopyAssignment:
- if (RD->hasUserDeclaredCopyAssignment()) {
- SourceLocation AssignLoc =
- RD->getCopyAssignmentOperator(0)->getLocation();
- Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXMoveAssignment:
- if (RD->hasUserDeclaredMoveAssignment()) {
- SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
- Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXDestructor:
- if (RD->hasUserDeclaredDestructor()) {
- SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
- Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
- }
-
- typedef CXXRecordDecl::base_class_iterator base_iter;
-
- // Virtual bases and members inhibit trivial copying/construction,
- // but not trivial destruction.
- if (member != CXXDestructor) {
- // Check for virtual bases. vbases includes indirect virtual bases,
- // so we just iterate through the direct bases.
- for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
- if (bi->isVirtual()) {
- SourceLocation BaseLoc = bi->getLocStart();
- Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
- return;
- }
-
- // Check for virtual methods.
- typedef CXXRecordDecl::method_iterator meth_iter;
- for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- if (mi->isVirtual()) {
- SourceLocation MLoc = mi->getLocStart();
- Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
- return;
- }
- }
- }
-
- bool (CXXRecordDecl::*hasTrivial)() const;
- switch (member) {
- case CXXDefaultConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break;
- case CXXCopyConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
- case CXXCopyAssignment:
- hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
- case CXXDestructor:
- hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
- default:
- llvm_unreachable("unexpected special member");
- }
-
- // Check for nontrivial bases (and recurse).
- for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
- const RecordType *BaseRT = bi->getType()->getAs<RecordType>();
- assert(BaseRT && "Don't know how to handle dependent bases");
- CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!(BaseRecTy->*hasTrivial)()) {
- SourceLocation BaseLoc = bi->getLocStart();
- Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
- DiagnoseNontrivial(BaseRT, member);
- return;
- }
- }
-
- // Check for nontrivial members (and recurse).
- typedef RecordDecl::field_iterator field_iter;
- for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
- ++fi) {
- QualType EltTy = Context.getBaseElementType(fi->getType());
- if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
-
- if (!(EltRD->*hasTrivial)()) {
- SourceLocation FLoc = fi->getLocation();
- Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
- DiagnoseNontrivial(EltRT, member);
- return;
- }
- }
-
- if (EltTy->isObjCLifetimeType()) {
- switch (EltTy.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Strong:
- Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership)
- << QT << EltTy.getObjCLifetime();
- return;
+ DiagnoseNontrivial(RDecl, member);
+ return !getLangOpts().CPlusPlus11;
}
}
}
- llvm_unreachable("found no explanation for non-trivial member");
+ return false;
}
/// TranslateIvarVisibility - Translate visibility from a token ID to an
@@ -10058,8 +10762,8 @@ Decl *Sema::ActOnIvar(Scope *S,
}
/// ActOnLastBitfield - This routine handles synthesized bitfields rules for
-/// class and class extensions. For every class @interface and class
-/// extension @interface, if the last ivar is a bitfield of any type,
+/// class and class extensions. For every class \@interface and class
+/// extension \@interface, if the last ivar is a bitfield of any type,
/// then add an implicit `char :0` ivar to the end of that interface.
void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
SmallVectorImpl<Decl *> &AllIvarDecls) {
@@ -10259,52 +10963,54 @@ void Sema::ActOnFields(Scope* S,
}
if (Record && FDTTy->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
+ if (Record && FDTTy->getDecl()->hasVolatileMember())
+ Record->setHasVolatileMember(true);
} else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object)
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
- } else if (!getLangOpts().CPlusPlus) {
- if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported) {
- // It's an error in ARC if a field has lifetime.
- // We don't want to report this in a system header, though,
- // so we just make the field unavailable.
- // FIXME: that's really not sufficient; we need to make the type
- // itself invalid to, say, initialize or copy.
- QualType T = FD->getType();
- Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
- if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
- SourceLocation loc = FD->getLocation();
- if (getSourceManager().isInSystemHeader(loc)) {
- if (!FD->hasAttr<UnavailableAttr>()) {
- FD->addAttr(new (Context) UnavailableAttr(loc, Context,
- "this system field has retaining ownership"));
- }
- } else {
- Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct)
- << T->isBlockPointerType();
+ } else if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported &&
+ (!getLangOpts().CPlusPlus || Record->isUnion())) {
+ // It's an error in ARC if a field has lifetime.
+ // We don't want to report this in a system header, though,
+ // so we just make the field unavailable.
+ // FIXME: that's really not sufficient; we need to make the type
+ // itself invalid to, say, initialize or copy.
+ QualType T = FD->getType();
+ Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
+ if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
+ SourceLocation loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(loc)) {
+ if (!FD->hasAttr<UnavailableAttr>()) {
+ FD->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "this system field has retaining ownership"));
}
- ARCErrReported = true;
+ } else {
+ Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
+ << T->isBlockPointerType() << Record->getTagKind();
}
+ ARCErrReported = true;
}
- else if (getLangOpts().ObjC1 &&
+ } else if (getLangOpts().ObjC1 &&
getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
- if (FD->getType()->isObjCObjectPointerType() ||
- FD->getType().isObjCGCStrong())
+ if (FD->getType()->isObjCObjectPointerType() ||
+ FD->getType().isObjCGCStrong())
+ Record->setHasObjectMember(true);
+ else if (Context.getAsArrayType(FD->getType())) {
+ QualType BaseType = Context.getBaseElementType(FD->getType());
+ if (BaseType->isRecordType() &&
+ BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
- else if (Context.getAsArrayType(FD->getType())) {
- QualType BaseType = Context.getBaseElementType(FD->getType());
- if (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
- Record->setHasObjectMember(true);
- else if (BaseType->isObjCObjectPointerType() ||
- BaseType.isObjCGCStrong())
- Record->setHasObjectMember(true);
- }
+ else if (BaseType->isObjCObjectPointerType() ||
+ BaseType.isObjCGCStrong())
+ Record->setHasObjectMember(true);
}
}
+ if (Record && FD->getType().isVolatileQualified())
+ Record->setHasVolatileMember(true);
// Keep track of the number of named members.
if (FD->getIdentifier())
++NumNamedMembers;
@@ -10316,14 +11022,14 @@ void Sema::ActOnFields(Scope* S,
if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
if (!CXXRecord->isInvalidDecl()) {
// Set access bits correctly on the directly-declared conversions.
- UnresolvedSetImpl *Convs = CXXRecord->getConversionFunctions();
- for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end();
- I != E; ++I)
- Convs->setAccess(I, (*I)->getAccess());
+ for (CXXRecordDecl::conversion_iterator
+ I = CXXRecord->conversion_begin(),
+ E = CXXRecord->conversion_end(); I != E; ++I)
+ I.setAccess((*I)->getAccess());
if (!CXXRecord->isDependentType()) {
// Adjust user-defined destructor exception spec.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
CXXRecord->hasUserDeclaredDestructor())
AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
@@ -10376,6 +11082,8 @@ void Sema::ActOnFields(Scope* S,
if (!Completed)
Record->completeDefinition();
+ if (Record->hasAttrs())
+ CheckAlignasUnderalignment(Record);
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -10418,11 +11126,12 @@ void Sema::ActOnFields(Scope* S,
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
- for (const ObjCCategoryDecl *ClsExtDecl =
- IDecl->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- if (const ObjCIvarDecl *ClsExtIvar =
- ClsExtDecl->getIvarDecl(ClsFields[i]->getIdentifier())) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = IDecl->known_extensions_begin(),
+ ExtEnd = IDecl->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (const ObjCIvarDecl *ClsExtIvar
+ = Ext->getIvarDecl(ClsFields[i]->getIdentifier())) {
Diag(ClsFields[i]->getLocation(),
diag::err_duplicate_ivar_declaration);
Diag(ClsExtIvar->getLocation(), diag::note_previous_definition);
@@ -10503,7 +11212,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EltTy = Context.DependentTy;
else {
SourceLocation ExpLoc;
- if (getLangOpts().CPlusPlus0x && Enum->isFixed() &&
+ if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
!getLangOpts().MicrosoftMode) {
// C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
// constant-expression in the enumerator-definition shall be a converted
@@ -10722,6 +11431,182 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
return New;
}
+// Returns true when the enum initial expression does not trigger the
+// duplicate enum warning. A few common cases are exempted as follows:
+// Element2 = Element1
+// Element2 = Element1 + 1
+// Element2 = Element1 - 1
+// Where Element2 and Element1 are from the same enum.
+static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) {
+ Expr *InitExpr = ECD->getInitExpr();
+ if (!InitExpr)
+ return true;
+ InitExpr = InitExpr->IgnoreImpCasts();
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) {
+ if (!BO->isAdditiveOp())
+ return true;
+ IntegerLiteral *IL = dyn_cast<IntegerLiteral>(BO->getRHS());
+ if (!IL)
+ return true;
+ if (IL->getValue() != 1)
+ return true;
+
+ InitExpr = BO->getLHS();
+ }
+
+ // This checks if the elements are from the same enum.
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InitExpr);
+ if (!DRE)
+ return true;
+
+ EnumConstantDecl *EnumConstant = dyn_cast<EnumConstantDecl>(DRE->getDecl());
+ if (!EnumConstant)
+ return true;
+
+ if (cast<EnumDecl>(TagDecl::castFromDeclContext(ECD->getDeclContext())) !=
+ Enum)
+ return true;
+
+ return false;
+}
+
+struct DupKey {
+ int64_t val;
+ bool isTombstoneOrEmptyKey;
+ DupKey(int64_t val, bool isTombstoneOrEmptyKey)
+ : val(val), isTombstoneOrEmptyKey(isTombstoneOrEmptyKey) {}
+};
+
+static DupKey GetDupKey(const llvm::APSInt& Val) {
+ return DupKey(Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(),
+ false);
+}
+
+struct DenseMapInfoDupKey {
+ static DupKey getEmptyKey() { return DupKey(0, true); }
+ static DupKey getTombstoneKey() { return DupKey(1, true); }
+ static unsigned getHashValue(const DupKey Key) {
+ return (unsigned)(Key.val * 37);
+ }
+ static bool isEqual(const DupKey& LHS, const DupKey& RHS) {
+ return LHS.isTombstoneOrEmptyKey == RHS.isTombstoneOrEmptyKey &&
+ LHS.val == RHS.val;
+ }
+};
+
+// Emits a warning when an element is implicitly set a value that
+// a previous element has already been set to.
+static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements,
+ unsigned NumElements, EnumDecl *Enum,
+ QualType EnumType) {
+ if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values,
+ Enum->getLocation()) ==
+ DiagnosticsEngine::Ignored)
+ return;
+ // Avoid anonymous enums
+ if (!Enum->getIdentifier())
+ return;
+
+ // Only check for small enums.
+ if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64)
+ return;
+
+ typedef SmallVector<EnumConstantDecl *, 3> ECDVector;
+ typedef SmallVector<ECDVector *, 3> DuplicatesVector;
+
+ typedef llvm::PointerUnion<EnumConstantDecl*, ECDVector*> DeclOrVector;
+ typedef llvm::DenseMap<DupKey, DeclOrVector, DenseMapInfoDupKey>
+ ValueToVectorMap;
+
+ DuplicatesVector DupVector;
+ ValueToVectorMap EnumMap;
+
+ // Populate the EnumMap with all values represented by enum constants without
+ // an initialier.
+ for (unsigned i = 0; i < NumElements; ++i) {
+ EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+
+ // Null EnumConstantDecl means a previous diagnostic has been emitted for
+ // this constant. Skip this enum since it may be ill-formed.
+ if (!ECD) {
+ return;
+ }
+
+ if (ECD->getInitExpr())
+ continue;
+
+ DupKey Key = GetDupKey(ECD->getInitVal());
+ DeclOrVector &Entry = EnumMap[Key];
+
+ // First time encountering this value.
+ if (Entry.isNull())
+ Entry = ECD;
+ }
+
+ // Create vectors for any values that has duplicates.
+ for (unsigned i = 0; i < NumElements; ++i) {
+ EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+ if (!ValidDuplicateEnum(ECD, Enum))
+ continue;
+
+ DupKey Key = GetDupKey(ECD->getInitVal());
+
+ DeclOrVector& Entry = EnumMap[Key];
+ if (Entry.isNull())
+ continue;
+
+ if (EnumConstantDecl *D = Entry.dyn_cast<EnumConstantDecl*>()) {
+ // Ensure constants are different.
+ if (D == ECD)
+ continue;
+
+ // Create new vector and push values onto it.
+ ECDVector *Vec = new ECDVector();
+ Vec->push_back(D);
+ Vec->push_back(ECD);
+
+ // Update entry to point to the duplicates vector.
+ Entry = Vec;
+
+ // Store the vector somewhere we can consult later for quick emission of
+ // diagnostics.
+ DupVector.push_back(Vec);
+ continue;
+ }
+
+ ECDVector *Vec = Entry.get<ECDVector*>();
+ // Make sure constants are not added more than once.
+ if (*Vec->begin() == ECD)
+ continue;
+
+ Vec->push_back(ECD);
+ }
+
+ // Emit diagnostics.
+ for (DuplicatesVector::iterator DupVectorIter = DupVector.begin(),
+ DupVectorEnd = DupVector.end();
+ DupVectorIter != DupVectorEnd; ++DupVectorIter) {
+ ECDVector *Vec = *DupVectorIter;
+ assert(Vec->size() > 1 && "ECDVector should have at least 2 elements.");
+
+ // Emit warning for one enum constant.
+ ECDVector::iterator I = Vec->begin();
+ S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values)
+ << (*I)->getName() << (*I)->getInitVal().toString(10)
+ << (*I)->getSourceRange();
+ ++I;
+
+ // Emit one note for each of the remaining enum constants with
+ // the same value.
+ for (ECDVector::iterator E = Vec->end(); I != E; ++I)
+ S.Diag((*I)->getLocation(), diag::note_duplicate_element)
+ << (*I)->getName() << (*I)->getInitVal().toString(10)
+ << (*I)->getSourceRange();
+ delete Vec;
+ }
+}
+
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
@@ -10944,6 +11829,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// it needs to go into the function scope.
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
+
+ CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
+
+ // Now that the enum type is defined, ensure it's not been underaligned.
+ if (Enum->hasAttrs())
+ CheckAlignasUnderalignment(Enum);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
@@ -10967,7 +11858,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
if (!Mod)
return true;
- llvm::SmallVector<SourceLocation, 2> IdentifierLocs;
+ SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
// If we've run out of module parents, just drop the remaining identifiers.
@@ -10987,6 +11878,19 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
return Import;
}
+void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
+ // Create the implicit import declaration.
+ TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
+ ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+ Loc, Mod, Loc);
+ TU->addDecl(ImportD);
+ Consumer.HandleImplicitImportDecl(ImportD);
+
+ // Make the module visible.
+ PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc,
+ /*Complain=*/false);
+}
+
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
IdentifierInfo* AliasName,
SourceLocation PragmaLoc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index e326a20c87d0..982e7a5dd81b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -16,14 +16,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace sema;
@@ -37,6 +40,7 @@ enum AttributeDeclKind {
ExpectedFunctionOrMethod,
ExpectedParameter,
ExpectedFunctionMethodOrBlock,
+ ExpectedFunctionMethodOrClass,
ExpectedFunctionMethodOrParameter,
ExpectedClass,
ExpectedVariable,
@@ -44,7 +48,11 @@ enum AttributeDeclKind {
ExpectedVariableFunctionOrLabel,
ExpectedFieldOrGlobalVar,
ExpectedStruct,
- ExpectedTLSVar
+ ExpectedVariableFunctionOrTag,
+ ExpectedTLSVar,
+ ExpectedVariableOrField,
+ ExpectedVariableFieldOrTag,
+ ExpectedTypeOrNamespace
};
//===----------------------------------------------------------------------===//
@@ -293,12 +301,12 @@ static bool isIntOrBool(Expr *Exp) {
static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
DeclContextLookupConstResult Res1 = RT->getDecl()->lookup(
S.Context.DeclarationNames.getCXXOperatorName(OO_Star));
- if (Res1.first == Res1.second)
+ if (Res1.empty())
return false;
DeclContextLookupConstResult Res2 = RT->getDecl()->lookup(
S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow));
- if (Res2.first == Res2.second)
+ if (Res2.empty())
return false;
return true;
@@ -503,18 +511,22 @@ 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));
+ D->addAttr(::new (S.Context)
+ GuardedVarAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handlePtGuardedVarAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
if (!checkGuardedVarAttrCommon(S, D, Attr))
return;
if (!threadSafetyCheckIsPointer(S, D, Attr))
return;
- D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PtGuardedVarAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
@@ -594,11 +606,13 @@ static void handleScopedLockableAttr(Sema &S, Decl *D,
if (!checkLockableAttrCommon(S, D, Attr))
return;
- D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ScopedLockableAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -614,7 +628,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
S.Context));
}
-static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
+static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
assert(!Attr.isInvalid());
@@ -622,13 +636,48 @@ static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ 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) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ 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) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ 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) NoAddressSafetyAnalysisAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context) NoSanitizeThreadAttr(Attr.getRange(),
+ S.Context));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
@@ -673,8 +722,10 @@ static void handleAcquiredAfterAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
- StartArg, Args.size()));
+ D->addAttr(::new (S.Context)
+ AcquiredAfterAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
@@ -684,8 +735,10 @@ static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
- StartArg, Args.size()));
+ D->addAttr(::new (S.Context)
+ AcquiredBeforeAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkLockFunAttrCommon(Sema &S, Decl *D,
@@ -716,9 +769,9 @@ static void handleSharedLockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
- S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ SharedLockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
@@ -729,9 +782,10 @@ static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
- S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ ExclusiveLockFunctionAttr(Attr.getRange(), S.Context,
+ StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
@@ -768,10 +822,10 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ SharedTrylockFunctionAttr(Attr.getRange(), S.Context,
+ Attr.getArg(0), StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
@@ -782,10 +836,10 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ ExclusiveTrylockFunctionAttr(Attr.getRange(), S.Context,
+ Attr.getArg(0), StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkLocksRequiredCommon(Sema &S, Decl *D,
@@ -817,10 +871,10 @@ static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
- S.Context,
- StartArg,
- Args.size()));
+ D->addAttr(::new (S.Context)
+ ExclusiveLocksRequiredAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
@@ -830,10 +884,10 @@ static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
- S.Context,
- StartArg,
- Args.size()));
+ D->addAttr(::new (S.Context)
+ SharedLocksRequiredAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleUnlockFunAttr(Sema &S, Decl *D,
@@ -854,8 +908,9 @@ static void handleUnlockFunAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ UnlockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleLockReturnedAttr(Sema &S, Decl *D,
@@ -878,8 +933,9 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
if (Size == 0)
return;
- D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context,
- Args[0]));
+ D->addAttr(::new (S.Context)
+ LockReturnedAttr(Attr.getRange(), S.Context, Args[0],
+ Attr.getAttributeSpellingListIndex()));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D,
@@ -903,54 +959,24 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ LocksExcludedAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
- TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
- if (tDecl == 0) {
+ 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;
}
- QualType curType = tDecl->getUnderlyingType();
-
- Expr *sizeExpr;
-
- // Special case where the argument is a template id.
- if (Attr.getParameterName()) {
- CXXScopeSpec SS;
- SourceLocation TemplateKWLoc;
- UnqualifiedId id;
- id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
-
- ExprResult Size = S.ActOnIdExpression(scope, SS, TemplateKWLoc, id,
- false, false);
- if (Size.isInvalid())
- return;
-
- sizeExpr = Size.get();
- } else {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
- sizeExpr = Attr.getArg(0);
- }
-
- // Instantiate/Install the vector type, and let Sema build the type for us.
- // This will run the reguired checks.
- QualType T = S.BuildExtVectorType(curType, sizeExpr, Attr.getLoc());
- if (!T.isNull()) {
- // FIXME: preserve the old source info.
- tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T));
-
- // Remember this typedef decl, we will need it later for diagnostics.
- S.ExtVectorDecls.push_back(tDecl);
- }
+ // Remember this typedef decl, we will need it later for diagnostics.
+ S.ExtVectorDecls.push_back(TD);
}
static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -969,14 +995,18 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
+ FD->addAttr(::new (S.Context)
+ PackedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else
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));
+ RD->addAttr(::new (S.Context)
+ MsStructAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -989,7 +1019,9 @@ 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));
+ D->addAttr(::new (S.Context)
+ IBActionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
}
@@ -1030,7 +1062,9 @@ static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkIBOutletCommon(S, D, Attr))
return;
- D->addAttr(::new (S.Context) IBOutletAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ IBOutletAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleIBOutletCollection(Sema &S, Decl *D,
@@ -1064,8 +1098,10 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
}
- D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getRange(),S.Context,
- QT, Attr.getParameterLoc()));
+ D->addAttr(::new (S.Context)
+ IBOutletCollectionAttr(Attr.getRange(),S.Context,
+ QT, Attr.getParameterLoc(),
+ Attr.getAttributeSpellingListIndex()));
}
static void possibleTransparentUnionPointerType(QualType &T) {
@@ -1096,7 +1132,11 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// 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 NumArgs;
+ if (hasFunctionProto(D))
+ NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+ else
+ NumArgs = 0;
SmallVector<unsigned, 8> SizeArgs;
@@ -1148,8 +1188,10 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
}
- D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context,
- SizeArgs.data(), SizeArgs.size()));
+ D->addAttr(::new (S.Context)
+ AllocSizeAttr(Attr.getRange(), S.Context,
+ SizeArgs.data(), SizeArgs.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1164,15 +1206,13 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// 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 NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
SmallVector<unsigned, 10> NonNullArgs;
- for (AttributeList::arg_iterator I=Attr.arg_begin(),
- E=Attr.arg_end(); I!=E; ++I) {
-
-
+ for (AttributeList::arg_iterator I = Attr.arg_begin(),
+ E = Attr.arg_end(); I != E; ++I) {
// The argument must be an integer constant expression.
Expr *Ex = *I;
llvm::APSInt ArgNum(32);
@@ -1219,11 +1259,11 @@ 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 = getFunctionOrMethodNumArgs(D); i != e; ++i) {
+ QualType T = getFunctionOrMethodArgType(D, i).getNonReferenceType();
possibleTransparentUnionPointerType(T);
if (T->isAnyPointerType() || T->isBlockPointerType())
- NonNullArgs.push_back(I);
+ NonNullArgs.push_back(i);
}
// No pointer arguments?
@@ -1236,11 +1276,12 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
- unsigned* start = &NonNullArgs[0];
+ unsigned *start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
llvm::array_pod_sort(start, start + size);
- D->addAttr(::new (S.Context) NonNullAttr(Attr.getRange(), S.Context, start,
- size));
+ D->addAttr(::new (S.Context)
+ NonNullAttr(Attr.getRange(), S.Context, start, size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
@@ -1395,27 +1436,9 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
return;
}
- D->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module,
- start, size));
-}
-
-/// Whether this declaration has internal linkage for the purposes of
-/// things that want to complain about things not have internal linkage.
-static bool hasEffectivelyInternalLinkage(NamedDecl *D) {
- switch (D->getLinkage()) {
- case NoLinkage:
- case InternalLinkage:
- return true;
-
- // Template instantiations that go from external to unique-external
- // shouldn't get diagnosed.
- case UniqueExternalLinkage:
- return true;
-
- case ExternalLinkage:
- return false;
- }
- llvm_unreachable("unknown linkage kind!");
+ D->addAttr(::new (S.Context)
+ OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size,
+ AL.getAttributeSpellingListIndex()));
}
static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1468,11 +1491,6 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// This looks like a bug in gcc. We reject that for now. We should revisit
// it if this behaviour is actually used.
- if (!hasEffectivelyInternalLinkage(nd)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static);
- return;
- }
-
// GCC rejects
// static ((alias ("y"), weakref)).
// Should we? How to check that weakref is before or after alias?
@@ -1493,7 +1511,9 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str->getString()));
}
- D->addAttr(::new (S.Context) WeakRefAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ WeakRefAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1521,7 +1541,8 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// FIXME: check if target symbol exists in current file
D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context,
- Str->getString()));
+ Str->getString(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1535,7 +1556,9 @@ static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) MinSizeAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ MinSizeAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1555,7 +1578,8 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1575,7 +1599,8 @@ static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1589,7 +1614,9 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NakedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
@@ -1606,7 +1633,9 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ AlwaysInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleTLSModelAttr(Sema &S, Decl *D,
@@ -1641,8 +1670,9 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) TLSModelAttr(Attr.getRange(), S.Context,
- Model));
+ D->addAttr(::new (S.Context)
+ TLSModelAttr(Attr.getRange(), S.Context, Model,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1655,7 +1685,9 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getResultType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
- D->addAttr(::new (S.Context) MallocAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ MallocAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
}
}
@@ -1668,13 +1700,17 @@ static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- D->addAttr(::new (S.Context) MayAliasAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ MayAliasAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context) NoCommonAttr(Attr.getRange(), S.Context));
+ 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;
@@ -1683,7 +1719,9 @@ static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context));
+ 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;
@@ -1700,7 +1738,9 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
return;
}
- D->addAttr(::new (S.Context) NoReturnAttr(attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoReturnAttr(attr.getRange(), S.Context,
+ attr.getAttributeSpellingListIndex()));
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
@@ -1727,14 +1767,33 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
if (VD == 0 || (!VD->getType()->isBlockPointerType()
&& !VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
- Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type
: diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
}
- D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ AnalyzerNoReturnAttr(Attr.getRange(), S.Context,
+ 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.
@@ -1795,16 +1854,30 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
count++;
}
- D->addAttr(::new (S.Context) VecReturnAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ VecReturnAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunctionOrMethod(D) && !isa<ParmVarDecl>(D)) {
+static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
+ const AttributeList &Attr) {
+ if (isa<ParmVarDecl>(D)) {
+ // [[carries_dependency]] can only be applied to a parameter if it is a
+ // parameter of a function declaration or lambda.
+ if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) {
+ S.Diag(Attr.getLoc(),
+ 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;
}
- // FIXME: Actually store the attribute on the declaration
+
+ D->addAttr(::new (S.Context) CarriesDependencyAttr(
+ Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1821,7 +1894,9 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) UnusedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ UnusedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleReturnsTwiceAttr(Sema &S, Decl *D,
@@ -1838,7 +1913,9 @@ static void handleReturnsTwiceAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ReturnsTwiceAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ReturnsTwiceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1859,7 +1936,9 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) UsedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ UsedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1888,8 +1967,9 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) ConstructorAttr(Attr.getRange(), S.Context,
- priority));
+ D->addAttr(::new (S.Context)
+ ConstructorAttr(Attr.getRange(), S.Context, priority,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1918,8 +1998,9 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) DestructorAttr(Attr.getRange(), S.Context,
- priority));
+ D->addAttr(::new (S.Context)
+ DestructorAttr(Attr.getRange(), S.Context, priority,
+ Attr.getAttributeSpellingListIndex()));
}
template <typename AttrTy>
@@ -1943,7 +2024,8 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
Str = SE->getString();
}
- D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str));
+ D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
@@ -1954,8 +2036,9 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr(
- Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCRootClassAttr(Sema &S, Decl *D,
@@ -1971,11 +2054,13 @@ static void handleObjCRootClassAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCRootClassAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCRootClassAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
if (!isa<ObjCInterfaceDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_suppress_autosynthesis);
return;
@@ -1987,8 +2072,9 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCRequiresPropertyDefsAttr(
- Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
@@ -2030,13 +2116,33 @@ static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
return false;
}
-AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
+/// \brief Check whether the two versions match.
+///
+/// If either version tuple is empty, then they are assumed to match. If
+/// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y.
+static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
+ bool BeforeIsOkay) {
+ if (X.empty() || Y.empty())
+ return true;
+
+ if (X == Y)
+ return true;
+
+ if (BeforeIsOkay && X < Y)
+ return true;
+
+ return false;
+}
+
+AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
IdentifierInfo *Platform,
VersionTuple Introduced,
VersionTuple Deprecated,
VersionTuple Obsoleted,
bool IsUnavailable,
- StringRef Message) {
+ StringRef Message,
+ bool Override,
+ unsigned AttrSpellingListIndex) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
@@ -2062,18 +2168,47 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
VersionTuple OldDeprecated = OldAA->getDeprecated();
VersionTuple OldObsoleted = OldAA->getObsoleted();
bool OldIsUnavailable = OldAA->getUnavailable();
- StringRef OldMessage = OldAA->getMessage();
-
- if ((!OldIntroduced.empty() && !Introduced.empty() &&
- OldIntroduced != Introduced) ||
- (!OldDeprecated.empty() && !Deprecated.empty() &&
- OldDeprecated != Deprecated) ||
- (!OldObsoleted.empty() && !Obsoleted.empty() &&
- OldObsoleted != Obsoleted) ||
- (OldIsUnavailable != IsUnavailable) ||
- (OldMessage != Message)) {
- Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
- Diag(Range.getBegin(), diag::note_previous_attribute);
+
+ if (!versionsMatch(OldIntroduced, Introduced, Override) ||
+ !versionsMatch(Deprecated, OldDeprecated, Override) ||
+ !versionsMatch(Obsoleted, OldObsoleted, Override) ||
+ !(OldIsUnavailable == IsUnavailable ||
+ (Override && !OldIsUnavailable && IsUnavailable))) {
+ if (Override) {
+ int Which = -1;
+ VersionTuple FirstVersion;
+ VersionTuple SecondVersion;
+ if (!versionsMatch(OldIntroduced, Introduced, Override)) {
+ Which = 0;
+ FirstVersion = OldIntroduced;
+ SecondVersion = Introduced;
+ } else if (!versionsMatch(Deprecated, OldDeprecated, Override)) {
+ Which = 1;
+ FirstVersion = Deprecated;
+ SecondVersion = OldDeprecated;
+ } else if (!versionsMatch(Obsoleted, OldObsoleted, Override)) {
+ Which = 2;
+ FirstVersion = Obsoleted;
+ SecondVersion = OldObsoleted;
+ }
+
+ if (Which == -1) {
+ Diag(OldAA->getLocation(),
+ diag::warn_mismatched_availability_override_unavail)
+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName());
+ } else {
+ Diag(OldAA->getLocation(),
+ diag::warn_mismatched_availability_override)
+ << Which
+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
+ << FirstVersion.getAsString() << SecondVersion.getAsString();
+ }
+ Diag(Range.getBegin(), diag::note_overridden_method);
+ } else {
+ Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ }
+
Attrs.erase(Attrs.begin() + i);
--e;
continue;
@@ -2115,7 +2250,8 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
MergedDeprecated, MergedObsoleted)) {
return ::new (Context) AvailabilityAttr(Range, Context, Platform,
Introduced, Deprecated,
- Obsoleted, IsUnavailable, Message);
+ Obsoleted, IsUnavailable, Message,
+ AttrSpellingListIndex);
}
return NULL;
}
@@ -2124,11 +2260,18 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
IdentifierInfo *Platform = Attr.getParameterName();
SourceLocation PlatformLoc = Attr.getParameterLoc();
-
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+
if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
<< Platform;
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ if (!ND) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ return;
+ }
+
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
@@ -2139,37 +2282,69 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
if (SE)
Str = SE->getString();
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(D, Attr.getRange(),
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(),
Platform,
Introduced.Version,
Deprecated.Version,
Obsoleted.Version,
- IsUnavailable, Str);
+ IsUnavailable, Str,
+ /*Override=*/false,
+ Index);
if (NewAttr)
D->addAttr(NewAttr);
}
+template <class T>
+static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
+ typename T::VisibilityType value,
+ unsigned attrSpellingListIndex) {
+ T *existingAttr = D->getAttr<T>();
+ if (existingAttr) {
+ typename T::VisibilityType existingValue = existingAttr->getVisibility();
+ if (existingValue == value)
+ return NULL;
+ S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
+ S.Diag(range.getBegin(), diag::note_previous_attribute);
+ D->dropAttr<T>();
+ }
+ return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex);
+}
+
VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
- VisibilityAttr::VisibilityType Vis) {
+ VisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex) {
+ return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
+ AttrSpellingListIndex);
+}
+
+TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
+ TypeVisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex) {
+ return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis,
+ AttrSpellingListIndex);
+}
+
+static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool isTypeVisibility) {
+ // Visibility attributes don't mean anything on a typedef.
if (isa<TypedefNameDecl>(D)) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
- return NULL;
+ S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored)
+ << Attr.getName();
+ return;
}
- VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>();
- if (ExistingAttr) {
- VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility();
- if (ExistingVis == Vis)
- return NULL;
- Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
- Diag(Range.getBegin(), diag::note_previous_attribute);
- D->dropAttr<VisibilityAttr>();
+
+ // 'type_visibility' can only go on a type or namespace.
+ if (isTypeVisibility &&
+ !(isa<TagDecl>(D) ||
+ isa<ObjCInterfaceDecl>(D) ||
+ isa<NamespaceDecl>(D))) {
+ S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedTypeOrNamespace;
+ return;
}
- return ::new (Context) VisibilityAttr(Range, Context, Vis);
-}
-static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if(!checkAttributeNumArgs(S, Attr, 1))
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
Expr *Arg = Attr.getArg(0);
@@ -2178,13 +2353,13 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "visibility" << 1;
+ << (isTypeVisibility ? "type_visibility" : "visibility") << 1;
return;
}
StringRef TypeStr = Str->getString();
VisibilityAttr::VisibilityType type;
-
+
if (TypeStr == "default")
type = VisibilityAttr::Default;
else if (TypeStr == "hidden")
@@ -2205,9 +2380,17 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type);
- if (NewAttr)
- D->addAttr(NewAttr);
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ clang::Attr *newAttr;
+ if (isTypeVisibility) {
+ newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(),
+ (TypeVisibilityAttr::VisibilityType) type,
+ Index);
+ } else {
+ newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index);
+ }
+ if (newAttr)
+ D->addAttr(newAttr);
}
static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -2274,7 +2457,9 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCExceptionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2305,7 +2490,9 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
// case.
S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
}
- D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCNSObjectAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void
@@ -2320,7 +2507,9 @@ handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) OverloadableAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ OverloadableAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2344,7 +2533,9 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) BlocksAttr(Attr.getRange(), S.Context, type));
+ D->addAttr(::new (S.Context)
+ BlocksAttr(Attr.getRange(), S.Context, type,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2436,8 +2627,9 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
- D->addAttr(::new (S.Context) SentinelAttr(Attr.getRange(), S.Context, sentinel,
- nullPos));
+ D->addAttr(::new (S.Context)
+ SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2445,9 +2637,9 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
+ if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ << Attr.getName() << ExpectedFunctionMethodOrClass;
return;
}
@@ -2463,7 +2655,9 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
return;
}
- D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ WarnUnusedResultAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2485,13 +2679,9 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
NamedDecl *nd = cast<NamedDecl>(D);
- // 'weak' only applies to declarations with external linkage.
- if (hasEffectivelyInternalLinkage(nd)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weak_static);
- return;
- }
-
- nd->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
+ nd->addAttr(::new (S.Context)
+ WeakAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2518,7 +2708,9 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ WeakImportAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
// Handles reqd_work_group_size and work_group_size_hint.
@@ -2568,15 +2760,57 @@ static void handleWorkGroupSize(Sema &S, Decl *D,
if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize)
D->addAttr(::new (S.Context)
ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2]));
+ 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]));
+ WGSize[0], WGSize[1], WGSize[2],
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(Attr.getKind() == AttributeList::AT_VecTypeHint);
+
+ // Attribute has 1 argument.
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg());
+
+ if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
+ (ParmType->isBooleanType() ||
+ !ParmType->isIntegralType(S.getASTContext()))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint)
+ << ParmType;
+ return;
+ }
+
+ if (Attr.getKind() == AttributeList::AT_VecTypeHint &&
+ D->hasAttr<VecTypeHintAttr>()) {
+ VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>();
+ if (A->getTypeHint() != ParmType) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
+ return;
+ }
+ }
+
+ D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
+ ParmType, Attr.getLoc()));
+}
+
+static void handleEndianAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!dyn_cast<VarDecl>(D))
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "endian"
+ << 9;
+ StringRef EndianType = Attr.getParameterName()->getName();
+ if (EndianType != "host" && EndianType != "device")
+ S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_endian) << EndianType;
}
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
- StringRef Name) {
+ StringRef Name,
+ unsigned AttrSpellingListIndex) {
if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
if (ExistingAttr->getName() == Name)
return NULL;
@@ -2584,7 +2818,8 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
Diag(Range.getBegin(), diag::note_previous_attribute);
return NULL;
}
- return ::new (Context) SectionAttr(Range, Context, Name);
+ return ::new (Context) SectionAttr(Range, Context, Name,
+ AttrSpellingListIndex);
}
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2614,8 +2849,10 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
return;
}
+
+ unsigned Index = Attr.getAttributeSpellingListIndex();
SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(),
- SE->getString());
+ SE->getString(), Index);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2632,7 +2869,9 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
} else {
- D->addAttr(::new (S.Context) NoThrowAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoThrowAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
}
@@ -2647,7 +2886,9 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
} else {
- D->addAttr(::new (S.Context) ConstAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ConstAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex() ));
}
}
@@ -2656,7 +2897,9 @@ static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- D->addAttr(::new (S.Context) PureAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PureAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2715,8 +2958,11 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD));
+ D->addAttr(::new (S.Context)
+ CleanupAttr(Attr.getRange(), S.Context, FD,
+ Attr.getAttributeSpellingListIndex()));
S.MarkFunctionReferenced(Attr.getParameterLoc(), FD);
+ S.DiagnoseUseOfDecl(FD, Attr.getParameterLoc());
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
@@ -2790,8 +3036,9 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) FormatArgAttr(Attr.getRange(), S.Context,
- Idx.getZExtValue()));
+ D->addAttr(::new (S.Context)
+ FormatArgAttr(Attr.getRange(), S.Context, Idx.getZExtValue(),
+ Attr.getAttributeSpellingListIndex()));
}
enum FormatAttrKind {
@@ -2866,12 +3113,14 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
Attr.setInvalid();
return;
}
- D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getRange(), S.Context,
- prioritynum));
+ D->addAttr(::new (S.Context)
+ InitPriorityAttr(Attr.getRange(), S.Context, prioritynum,
+ Attr.getAttributeSpellingListIndex()));
}
FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
- int FormatIdx, int FirstArg) {
+ int FormatIdx, int FirstArg,
+ unsigned AttrSpellingListIndex) {
// Check whether we already have an equivalent format attribute.
for (specific_attr_iterator<FormatAttr>
i = D->specific_attr_begin<FormatAttr>(),
@@ -2889,8 +3138,8 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
}
}
- return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
- FirstArg);
+ return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx, FirstArg,
+ AttrSpellingListIndex);
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
@@ -3030,7 +3279,8 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), Format,
Idx.getZExtValue(),
- FirstArg.getZExtValue());
+ FirstArg.getZExtValue(),
+ Attr.getAttributeSpellingListIndex());
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -3099,7 +3349,9 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
}
}
- RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getRange(), S.Context));
+ RD->addAttr(::new (S.Context)
+ TransparentUnionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3124,8 +3376,10 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if ((*i)->getAnnotation() == SE->getString())
return;
}
- D->addAttr(::new (S.Context) AnnotateAttr(Attr.getRange(), S.Context,
- SE->getString()));
+
+ D->addAttr(::new (S.Context)
+ AnnotateAttr(Attr.getRange(), S.Context, SE->getString(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3135,34 +3389,77 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- //FIXME: The C++0x version of this attribute has more limited applicabilty
- // than GNU's, and should error out when it is used to specify a
- // weaker alignment, rather than being silently ignored.
-
if (Attr.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
- true, 0, Attr.isDeclspecAttribute()));
+ D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
+ true, 0, Attr.getAttributeSpellingListIndex()));
return;
}
- S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0),
- Attr.isDeclspecAttribute());
-}
+ Expr *E = Attr.getArg(0);
+ if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) {
+ S.Diag(Attr.getEllipsisLoc(),
+ diag::err_pack_expansion_without_parameter_packs);
+ return;
+ }
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- bool isDeclSpec) {
- // FIXME: Handle pack-expansions here.
- if (DiagnoseUnexpandedParameterPack(E))
+ if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
return;
+ S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(),
+ Attr.isPackExpansion());
+}
+
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
+ unsigned SpellingListIndex, bool IsPackExpansion) {
+ AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex);
+ SourceLocation AttrLoc = AttrRange.getBegin();
+
+ // C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
+ if (TmpAttr.isAlignas()) {
+ // C++11 [dcl.align]p1:
+ // An alignment-specifier may be applied to a variable or to a class
+ // data member, but it shall not be applied to a bit-field, a function
+ // parameter, the formal parameter of a catch clause, or a variable
+ // declared with the register storage class specifier. An
+ // alignment-specifier may also be applied to the declaration of a class
+ // or enumeration type.
+ // C11 6.7.5/2:
+ // An alignment attribute shall not be specified in a declaration of
+ // a typedef, or a bit-field, or a function, or a parameter, or an
+ // object declared with the register storage-class specifier.
+ int DiagKind = -1;
+ if (isa<ParmVarDecl>(D)) {
+ DiagKind = 0;
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getStorageClass() == SC_Register)
+ DiagKind = 1;
+ if (VD->isExceptionVariable())
+ DiagKind = 2;
+ } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->isBitField())
+ DiagKind = 3;
+ } else if (!isa<TagDecl>(D)) {
+ Diag(AttrLoc, diag::err_attribute_wrong_decl_type)
+ << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'")
+ << (TmpAttr.isC11() ? ExpectedVariableOrField
+ : ExpectedVariableFieldOrTag);
+ return;
+ }
+ if (DiagKind != -1) {
+ Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
+ << TmpAttr.isC11() << DiagKind;
+ return;
+ }
+ }
+
if (E->isTypeDependent() || E->isValueDependent()) {
// Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E,
- isDeclSpec));
+ AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr);
+ AA->setPackExpansion(IsPackExpansion);
+ D->addAttr(AA);
return;
}
-
- SourceLocation AttrLoc = AttrRange.getBegin();
+
// FIXME: Cache the number on the Attr object?
llvm::APSInt Alignment(32);
ExprResult ICE
@@ -3171,32 +3468,79 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
/*AllowFold*/ false);
if (ICE.isInvalid())
return;
- if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
+
+ // C++11 [dcl.align]p2:
+ // -- if the constant expression evaluates to zero, the alignment
+ // specifier shall have no effect
+ // C11 6.7.5p6:
+ // An alignment specification of zero has no effect.
+ if (!(TmpAttr.isAlignas() && !Alignment) &&
+ !llvm::isPowerOf2_64(Alignment.getZExtValue())) {
Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two)
<< E->getSourceRange();
return;
}
- if (isDeclSpec) {
+
+ 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)
+ Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192)
<< E->getSourceRange();
return;
}
}
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take(),
- isDeclSpec));
+ AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true,
+ ICE.take(), SpellingListIndex);
+ AA->setPackExpansion(IsPackExpansion);
+ D->addAttr(AA);
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
- bool isDeclSpec) {
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
+ unsigned SpellingListIndex, bool IsPackExpansion) {
// FIXME: Cache the number on the Attr object if non-dependent?
// FIXME: Perform checking of type validity
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS,
- isDeclSpec));
- return;
+ AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS,
+ SpellingListIndex);
+ AA->setPackExpansion(IsPackExpansion);
+ D->addAttr(AA);
+}
+
+void Sema::CheckAlignasUnderalignment(Decl *D) {
+ assert(D->hasAttrs() && "no attributes on decl");
+
+ QualType Ty;
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ Ty = VD->getType();
+ else
+ Ty = Context.getTagDeclType(cast<TagDecl>(D));
+ if (Ty->isDependentType() || Ty->isIncompleteType())
+ return;
+
+ // C++11 [dcl.align]p5, C11 6.7.5/4:
+ // 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;
+ unsigned Align = 0;
+ for (specific_attr_iterator<AlignedAttr>
+ I = D->specific_attr_begin<AlignedAttr>(),
+ E = D->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ if (I->isAlignmentDependent())
+ return;
+ if (I->isAlignas())
+ AlignasAttr = *I;
+ Align = std::max(Align, I->getAlignment(Context));
+ }
+
+ if (AlignasAttr && Align) {
+ CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
+ CharUnits NaturalAlign = Context.getTypeAlignInChars(Ty);
+ if (NaturalAlign > RequestedAlign)
+ Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned)
+ << Ty << (unsigned)NaturalAlign.getQuantity();
+ }
}
/// handleModeAttr - This attribute modifies the width of a decl with primitive
@@ -3260,6 +3604,10 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Str == "pointer")
DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
break;
+ case 11:
+ if (Str == "unwind_word")
+ DestWidth = S.Context.getTargetInfo().getUnwindWordWidth();
+ break;
}
QualType OldTy;
@@ -3386,7 +3734,9 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoDebugAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3401,7 +3751,9 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NoInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
@@ -3417,8 +3769,9 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NoInstrumentFunctionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3435,7 +3788,9 @@ static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDAConstantAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
}
@@ -3455,7 +3810,9 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDADeviceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
}
@@ -3476,10 +3833,10 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getResultType()->isVoidType()) {
TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
- if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
<< FD->getType()
- << FixItHint::CreateReplacement(FTL->getResultLoc().getSourceRange(),
+ << FixItHint::CreateReplacement(FTL.getResultLoc().getSourceRange(),
"void");
} else {
S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
@@ -3488,7 +3845,9 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAGlobalAttr(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) << "global";
}
@@ -3507,7 +3866,9 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDAHostAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
}
@@ -3519,14 +3880,15 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
-
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));
+ D->addAttr(::new (S.Context)
+ CUDASharedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
}
@@ -3549,16 +3911,19 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ GNUInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (hasDeclarator(D)) return;
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
// Diagnostic is emitted elsewhere: here we store the (valid) Attr
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
- if (S.CheckCallingConvAttr(Attr, CC))
+ if (S.CheckCallingConvAttr(Attr, CC, FD))
return;
if (!isa<ObjCMethodDecl>(D)) {
@@ -3569,19 +3934,29 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
switch (Attr.getKind()) {
case AttributeList::AT_FastCall:
- D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ FastCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_StdCall:
- D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ StdCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_ThisCall:
- D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ThisCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CDecl:
- D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CDeclAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_Pascal:
- D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PascalAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_Pcs: {
PcsAttr::PCSType PCS;
@@ -3596,11 +3971,20 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
llvm_unreachable("unexpected calling convention in pcs attribute");
}
- D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS));
+ D->addAttr(::new (S.Context)
+ PcsAttr(Attr.getRange(), S.Context, PCS,
+ Attr.getAttributeSpellingListIndex()));
return;
}
case AttributeList::AT_PnaclCall:
- D->addAttr(::new (S.Context) PnaclCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PnaclCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+ return;
+ case AttributeList::AT_IntelOclBicc:
+ D->addAttr(::new (S.Context)
+ IntelOclBiccAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
default:
@@ -3613,7 +3997,24 @@ static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context));
}
-bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
+static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){
+ assert(!Attr.isInvalid());
+
+ Expr *E = Attr.getArg(0);
+ llvm::APSInt ArgNum(32);
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(ArgNum, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << Attr.getName()->getName() << 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())
return true;
@@ -3656,6 +4057,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
return true;
}
case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break;
+ case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break;
default: llvm_unreachable("unexpected attribute kind");
}
@@ -3663,7 +4065,12 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
if (A == TargetInfo::CCCR_Warning) {
Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName();
- CC = TI.getDefaultCallingConv();
+
+ TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown;
+ if (FD)
+ MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member :
+ TargetInfo::CCMT_NonMember;
+ CC = TI.getDefaultCallingConv(MT);
}
return false;
@@ -3682,7 +4089,9 @@ static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) RegparmAttr(Attr.getRange(), S.Context, numParams));
+ 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
@@ -3762,9 +4171,11 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
}
}
- D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getRange(), S.Context,
- MaxThreads.getZExtValue(),
- MinBlocks.getZExtValue()));
+ 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";
}
@@ -3815,12 +4226,10 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
}
- D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(Attr.getRange(),
- S.Context,
- ArgumentKind,
- ArgumentIdx,
- TypeTagIdx,
- IsPointer));
+ D->addAttr(::new (S.Context)
+ ArgumentWithTypeTagAttr(Attr.getRange(), S.Context, ArgumentKind,
+ ArgumentIdx, TypeTagIdx, IsPointer,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
@@ -3834,13 +4243,12 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
QualType MatchingCType = S.GetTypeFromParser(Attr.getMatchingCType(), NULL);
- D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
- Attr.getRange(),
- S.Context,
- PointerKind,
- MatchingCType,
- Attr.getLayoutCompatible(),
- Attr.getMustBeNull()));
+ D->addAttr(::new (S.Context)
+ TypeTagForDatatypeAttr(Attr.getRange(), S.Context, PointerKind,
+ MatchingCType,
+ Attr.getLayoutCompatible(),
+ Attr.getMustBeNull(),
+ Attr.getAttributeSpellingListIndex()));
}
//===----------------------------------------------------------------------===//
@@ -3882,9 +4290,13 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (cf)
- param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getRange(), S.Context));
+ param->addAttr(::new (S.Context)
+ CFConsumedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
- param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getRange(), S.Context));
+ param->addAttr(::new (S.Context)
+ NSConsumedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
@@ -3895,7 +4307,9 @@ static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NSConsumesSelfAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
@@ -3947,24 +4361,29 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
default:
llvm_unreachable("invalid ownership attribute");
case AttributeList::AT_NSReturnsAutoreleased:
- D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NSReturnsAutoreleasedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CFReturnsNotRetained:
- D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ CFReturnsNotRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_NSReturnsNotRetained:
- D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NSReturnsNotRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CFReturnsRetained:
- D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ CFReturnsRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_NSReturnsRetained:
- D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NSReturnsRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
};
}
@@ -3994,8 +4413,9 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
return;
}
- method->addAttr(
- ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
+ method->addAttr(::new (S.Context)
+ ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context,
+ attr.getAttributeSpellingListIndex()));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
@@ -4021,8 +4441,9 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
return;
}
- method->addAttr(
- ::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context));
+ method->addAttr(::new (S.Context)
+ ObjCRequiresSuperAttr(attr.getRange(), S.Context,
+ attr.getAttributeSpellingListIndex()));
}
/// Handle cf_audited_transfer and cf_unknown_transfer.
@@ -4052,11 +4473,13 @@ static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
// All clear; add the attribute.
if (IsAudited) {
- D->addAttr(
- ::new (S.Context) CFAuditedTransferAttr(A.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CFAuditedTransferAttr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex()));
} else {
- D->addAttr(
- ::new (S.Context) CFUnknownTransferAttr(A.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CFUnknownTransferAttr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex()));
}
}
@@ -4086,8 +4509,9 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
}
}
- D->addAttr(::new (S.Context) NSBridgedAttr(Attr.getRange(), S.Context,
- ParmName));
+ D->addAttr(::new (S.Context)
+ NSBridgedAttr(Attr.getRange(), S.Context, ParmName,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
@@ -4141,7 +4565,8 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context)
- ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context));
+ ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
//===----------------------------------------------------------------------===//
@@ -4189,15 +4614,16 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
return;
}
- } else if (!isxdigit(*I)) {
+ } else if (!isHexDigit(*I)) {
S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
return;
}
I++;
}
- D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context,
- Str->getString()));
+ D->addAttr(::new (S.Context)
+ UuidAttr(Attr.getRange(), S.Context, Str->getString(),
+ Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
}
@@ -4211,13 +4637,19 @@ static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
AttributeList::Kind Kind = Attr.getKind();
if (Kind == AttributeList::AT_SingleInheritance)
D->addAttr(
- ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
+ ::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));
+ ::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));
+ ::new (S.Context)
+ VirtualInheritanceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -4225,20 +4657,25 @@ static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
AttributeList::Kind Kind = Attr.getKind();
if (Kind == AttributeList::AT_Ptr32)
D->addAttr(
- ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context));
+ ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else if (Kind == AttributeList::AT_Ptr64)
D->addAttr(
- ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context));
+ ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else if (Kind == AttributeList::AT_Win64)
D->addAttr(
- ::new (S.Context) Win64Attr(Attr.getRange(), S.Context));
+ ::new (S.Context) Win64Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.MicrosoftExt)
- D->addAttr(::new (S.Context) ForceInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ForceInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -4261,12 +4698,11 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_IBAction: handleIBAction(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_IBAction: handleIBAction(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_OpenCLImageAccess:
case AttributeList::AT_ObjCGC:
case AttributeList::AT_VectorSize:
case AttributeList::AT_NeonVectorType:
@@ -4291,10 +4727,14 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break;
case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
case AttributeList::AT_CarriesDependency:
- handleDependencyAttr (S, D, Attr); break;
+ 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_CXX11NoReturn:
+ handleCXX11NoReturnAttr(S, D, Attr);
+ break;
case AttributeList::AT_Deprecated:
handleAttrWithMessage<DeprecatedAttr>(S, D, Attr, "deprecated");
break;
@@ -4364,6 +4804,13 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReqdWorkGroupSize:
handleWorkGroupSize(S, D, Attr); break;
+ case AttributeList::AT_VecTypeHint:
+ handleVecTypeHint(S, D, Attr); break;
+
+ case AttributeList::AT_Endian:
+ handleEndianAttr(S, D, Attr);
+ break;
+
case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
@@ -4386,7 +4833,12 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleReturnsTwiceAttr(S, D, Attr);
break;
case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;
- case AttributeList::AT_Visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_Visibility:
+ handleVisibilityAttr(S, D, Attr, false);
+ break;
+ case AttributeList::AT_TypeVisibility:
+ handleVisibilityAttr(S, D, Attr, true);
+ break;
case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
@@ -4423,11 +4875,15 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Pascal:
case AttributeList::AT_Pcs:
case AttributeList::AT_PnaclCall:
+ case AttributeList::AT_IntelOclBicc:
handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_OpenCLKernel:
handleOpenCLKernelAttr(S, D, Attr);
break;
+ case AttributeList::AT_OpenCLImageAccess:
+ handleOpenCLImageAccessAttr(S, D, Attr);
+ break;
// Microsoft attributes:
case AttributeList::AT_MsStruct:
@@ -4460,11 +4916,17 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ScopedLockable:
handleScopedLockableAttr(S, D, Attr);
break;
- case AttributeList::AT_NoAddressSafetyAnalysis:
- handleNoAddressSafetyAttr(S, D, Attr);
+ case AttributeList::AT_NoSanitizeAddress:
+ handleNoSanitizeAddressAttr(S, D, Attr);
break;
case AttributeList::AT_NoThreadSafetyAnalysis:
- handleNoThreadSafetyAttr(S, D, Attr);
+ handleNoThreadSafetyAnalysis(S, D, Attr);
+ break;
+ case AttributeList::AT_NoSanitizeThread:
+ handleNoSanitizeThread(S, D, Attr);
+ break;
+ case AttributeList::AT_NoSanitizeMemory:
+ handleNoSanitizeMemory(S, D, Attr);
break;
case AttributeList::AT_Lockable:
handleLockableAttr(S, D, Attr);
@@ -4530,19 +4992,17 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
-/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
-/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
+/// silently ignore it if a GNU attribute.
static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr,
- bool NonInheritable, bool Inheritable) {
+ bool NonInheritable, bool Inheritable,
+ bool IncludeCXX11Attributes) {
if (Attr.isInvalid())
return;
- // Type attributes are still treated as declaration attributes by
- // ParseMicrosoftTypeAttributes and ParseBorlandTypeAttributes. We don't
- // want to process them, however, because we will simply warn about ignoring
- // them. So instead, we will bail out early.
- if (Attr.isMSTypespecAttribute())
+ // Ignore C++11 attributes on declarator chunks: they appertain to the type
+ // instead.
+ if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
return;
if (NonInheritable)
@@ -4556,17 +5016,19 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
/// attribute list to the specified decl, ignoring any type attributes.
void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
const AttributeList *AttrList,
- bool NonInheritable, bool Inheritable) {
- for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable);
- }
+ bool NonInheritable, bool Inheritable,
+ bool IncludeCXX11Attributes) {
+ for (const AttributeList* l = AttrList; l; l = l->getNext())
+ ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable,
+ IncludeCXX11Attributes);
// GCC accepts
// static int a9 __attribute__((weakref));
// but that looks really pointless. We reject it.
if (Inheritable && D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) <<
- dyn_cast<NamedDecl>(D)->getNameAsString();
+ cast<NamedDecl>(D)->getNameAsString();
+ D->dropAttr<WeakRefAttr>();
return;
}
}
@@ -4592,7 +5054,7 @@ bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) {
for ( ; A; A = A->getNext()) {
// Only warn if the attribute is an unignored, non-type attribute.
- if (A->isUsedAsTypeAttr()) continue;
+ if (A->isUsedAsTypeAttr() || A->isInvalid()) continue;
if (A->getKind() == AttributeList::IgnoredAttribute) continue;
if (A->getKind() == AttributeList::UnknownAttribute) {
@@ -4630,8 +5092,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
Loc, Loc, DeclarationName(II),
FD->getType(), FD->getTypeSourceInfo(),
- SC_None, SC_None,
- false/*isInlineSpecified*/,
+ SC_None, false/*isInlineSpecified*/,
FD->hasPrototype(),
false/*isConstexprSpecified*/);
NewD = NewFD;
@@ -4656,8 +5117,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
VD->getInnerLocStart(), VD->getLocation(), II,
VD->getType(), VD->getTypeSourceInfo(),
- VD->getStorageClass(),
- VD->getStorageClassAsWritten());
+ VD->getStorageClass());
if (VD->getQualifier()) {
VarDecl *NewVD = cast<VarDecl>(NewD);
NewVD->setQualifierInfo(VD->getQualifierLoc());
@@ -4689,30 +5149,37 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
}
}
-/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
-/// it, apply them to D. This is a bit tricky because PD can have attributes
-/// specified in many different places, and we need to find and apply them all.
-void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
- bool NonInheritable, bool Inheritable) {
+void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
// It's valid to "forward-declare" #pragma weak, in which case we
// have to do this.
- if (Inheritable) {
- LoadExternalWeakUndeclaredIdentifiers();
- if (!WeakUndeclaredIdentifiers.empty()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
- if (IdentifierInfo *Id = ND->getIdentifier()) {
- llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
- = WeakUndeclaredIdentifiers.find(Id);
- if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) {
- WeakInfo W = I->second;
- DeclApplyPragmaWeak(S, ND, W);
- WeakUndeclaredIdentifiers[Id] = W;
- }
+ LoadExternalWeakUndeclaredIdentifiers();
+ if (!WeakUndeclaredIdentifiers.empty()) {
+ NamedDecl *ND = NULL;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (VD->isExternC())
+ ND = VD;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isExternC())
+ ND = FD;
+ if (ND) {
+ if (IdentifierInfo *Id = ND->getIdentifier()) {
+ llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
+ = WeakUndeclaredIdentifiers.find(Id);
+ if (I != WeakUndeclaredIdentifiers.end()) {
+ WeakInfo W = I->second;
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[Id] = W;
}
}
}
}
+}
+/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
+/// it, apply them to D. This is a bit tricky because PD can have attributes
+/// specified in many different places, and we need to find and apply them all.
+void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
+ bool NonInheritable, bool Inheritable) {
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList())
ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
@@ -4723,7 +5190,8 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
// when X is a decl attribute.
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
- ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
+ ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable,
+ /*IncludeCXX11Attributes=*/false);
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 16eddf80ae5b..35890e6deb41 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,16 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/CXXFieldCollector.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
-#include "clang/AST/CharUnits.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"
@@ -30,12 +25,18 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ParsedTemplate.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Sema/CXXFieldCollector.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include <map>
#include <set>
@@ -251,7 +252,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
return true;
Arg = Result.takeAs<Expr>();
- CheckImplicitConversions(Arg, EqualLoc);
+ CheckCompletedExpr(Arg, EqualLoc);
Arg = MaybeCreateExprWithCleanups(Arg);
// Okay: add the default argument to the parameter
@@ -351,16 +352,25 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
// parameter pack. If it is specified in a
// parameter-declaration-clause, it shall not occur within a
// declarator or abstract-declarator of a parameter-declaration.
+ bool MightBeFunction = D.isFunctionDeclarationContext();
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorChunk &chunk = D.getTypeObject(i);
if (chunk.Kind == DeclaratorChunk::Function) {
+ if (MightBeFunction) {
+ // This is a function declaration. It can have default arguments, but
+ // keep looking in case its return type is a function type with default
+ // arguments.
+ MightBeFunction = false;
+ continue;
+ }
for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) {
ParmVarDecl *Param =
cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param);
if (Param->hasUnparsedDefaultArg()) {
CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
- << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
+ << SourceRange((*Toks)[1].getLocation(),
+ Toks->back().getLocation());
delete Toks;
chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
} else if (Param->getDefaultArg()) {
@@ -369,6 +379,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
Param->setDefaultArg(0);
}
}
+ } else if (chunk.Kind != DeclaratorChunk::Paren) {
+ MightBeFunction = false;
}
}
}
@@ -517,19 +529,26 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
diag::err_param_default_argument_member_template_redecl)
<< WhichKind
<< NewParam->getDefaultArgRange();
- } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) {
- CXXSpecialMember NewSM = getSpecialMember(Ctor),
- OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old));
- if (NewSM != OldSM) {
- Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special)
- << NewParam->getDefaultArgRange() << NewSM;
- Diag(Old->getLocation(), diag::note_previous_declaration_special)
- << OldSM;
- }
}
}
}
+ // DR1344: If a default argument is added outside a class definition and that
+ // default argument makes the function a special member function, the program
+ // is ill-formed. This can only happen for constructors.
+ if (isa<CXXConstructorDecl>(New) &&
+ New->getMinRequiredArguments() < Old->getMinRequiredArguments()) {
+ CXXSpecialMember NewSM = getSpecialMember(cast<CXXMethodDecl>(New)),
+ OldSM = getSpecialMember(cast<CXXMethodDecl>(Old));
+ if (NewSM != OldSM) {
+ ParmVarDecl *NewParam = New->getParamDecl(New->getMinRequiredArguments());
+ assert(NewParam->hasDefaultArg());
+ Diag(NewParam->getLocation(), diag::err_default_arg_makes_ctor_special)
+ << NewParam->getDefaultArgRange() << NewSM;
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+ }
+
// 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.
@@ -875,7 +894,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// - its function-body shall be [...] a compound-statement that contains only
CompoundStmt *CompBody = cast<CompoundStmt>(Body);
- llvm::SmallVector<SourceLocation, 4> ReturnStmts;
+ SmallVector<SourceLocation, 4> ReturnStmts;
for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
switch ((*BodyIt)->getStmtClass()) {
@@ -985,13 +1004,14 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// C++11 [dcl.constexpr]p4:
// - every constructor involved in initializing non-static data members and
// base class sub-objects shall be a constexpr constructor.
- llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ SmallVector<PartialDiagnosticAt, 8> Diags;
if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
- Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
+ Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl);
for (size_t I = 0, N = Diags.size(); I != N; ++I)
Diag(Diags[I].first, Diags[I].second);
- return false;
+ // Don't return false here: we allow this for compatibility in
+ // system headers.
}
return true;
@@ -1163,6 +1183,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
/// 'public bar' and 'virtual private baz' are each base-specifiers.
BaseResult
Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
+ ParsedAttributes &Attributes,
bool Virtual, AccessSpecifier Access,
ParsedType basetype, SourceLocation BaseLoc,
SourceLocation EllipsisLoc) {
@@ -1174,6 +1195,22 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
if (!Class)
return true;
+ // We do not support any C++11 attributes on base-specifiers yet.
+ // Diagnose any attributes we see.
+ if (!Attributes.empty()) {
+ for (AttributeList *Attr = Attributes.getList(); Attr;
+ Attr = Attr->getNext()) {
+ if (Attr->isInvalid() ||
+ Attr->getKind() == AttributeList::IgnoredAttribute)
+ continue;
+ Diag(Attr->getLoc(),
+ Attr->getKind() == AttributeList::UnknownAttribute
+ ? diag::warn_unknown_attribute_ignored
+ : diag::err_base_specifier_attribute)
+ << Attr->getName();
+ }
+ }
+
TypeSourceInfo *TInfo = 0;
GetTypeFromParser(basetype, &TInfo);
@@ -1274,29 +1311,25 @@ void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
(CXXBaseSpecifier**)(Bases), NumBases);
}
-static CXXRecordDecl *GetClassForType(QualType T) {
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl());
- else if (const InjectedClassNameType *ICT = T->getAs<InjectedClassNameType>())
- return ICT->getDecl();
- else
- return 0;
-}
-
/// \brief Determine whether the type \p Derived is a C++ class that is
/// derived from the type \p Base.
bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
if (!getLangOpts().CPlusPlus)
return false;
- CXXRecordDecl *DerivedRD = GetClassForType(Derived);
+ CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
- CXXRecordDecl *BaseRD = GetClassForType(Base);
+ CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
-
+
+ // If either the base or the derived type is invalid, don't try to
+ // check whether one is derived from the other.
+ if (BaseRD->isInvalidDecl() || DerivedRD->isInvalidDecl())
+ return false;
+
// FIXME: instantiate DerivedRD if necessary. We need a PoI for this.
return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD);
}
@@ -1307,11 +1340,11 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
if (!getLangOpts().CPlusPlus)
return false;
- CXXRecordDecl *DerivedRD = GetClassForType(Derived);
+ CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
- CXXRecordDecl *BaseRD = GetClassForType(Base);
+ CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
@@ -1556,7 +1589,7 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) {
/// bitfield width if there is one, 'InitExpr' specifies the initializer if
/// one has been parsed, and 'InitStyle' is set if an in-class initializer is
/// present (but parsing it has been deferred).
-Decl *
+NamedDecl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BW, const VirtSpecifiers &VS,
@@ -1657,7 +1690,36 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
!isFunc);
- Decl *Member;
+ if (DS.isConstexprSpecified() && isInstField) {
+ SemaDiagnosticBuilder B =
+ 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");
+ } else {
+ B << 1;
+ const char *PrevSpec;
+ unsigned DiagID;
+ if (D.getMutableDeclSpec().SetStorageClassSpec(
+ *this, DeclSpec::SCS_static, ConstexprLoc, PrevSpec, DiagID)) {
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_mutable &&
+ "This is the only DeclSpec that should fail to be applied");
+ B << 1;
+ } else {
+ B << 0 << FixItHint::CreateInsertion(ConstexprLoc, "static ");
+ isInstField = false;
+ }
+ }
+ }
+
+ NamedDecl *Member;
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
@@ -1711,7 +1773,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
InitStyle, AS);
assert(Member && "HandleField never returns null");
} else {
- assert(InitStyle == ICIS_NoInit);
+ assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static);
Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member) {
@@ -1795,7 +1857,11 @@ namespace {
public:
typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
- S(S), VD(VD) {
+ S(S) {
+ if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(VD))
+ this->VD = IFD->getAnonField();
+ else
+ this->VD = VD;
}
void HandleExpr(Expr *E) {
@@ -1812,23 +1878,33 @@ namespace {
if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
if (isa<EnumConstantDecl>(ME->getMemberDecl()))
- return;
+ return;
+
+ // FieldME is the inner-most MemberExpr that is not an anonymous struct
+ // or union.
+ MemberExpr *FieldME = ME;
+
Expr *Base = E;
while (isa<MemberExpr>(Base)) {
- ME = dyn_cast<MemberExpr>(Base);
- if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
- if (VarD->hasGlobalStorage())
- return;
+ ME = cast<MemberExpr>(Base);
+
+ if (isa<VarDecl>(ME->getMemberDecl()))
+ return;
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (!FD->isAnonymousStructOrUnion())
+ FieldME = ME;
+
Base = ME->getBase();
}
- if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
+ if (VD == FieldME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
unsigned diag = VD->getType()->isReferenceType()
? diag::warn_reference_field_is_uninit
: diag::warn_field_is_uninit;
- S.Diag(ME->getExprLoc(), diag) << ME->getMemberNameInfo().getName();
- return;
+ S.Diag(FieldME->getExprLoc(), diag) << VD;
}
+ return;
}
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
@@ -1909,11 +1985,7 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
}
ExprResult Init = InitExpr;
- if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent() &&
- !FD->getDeclContext()->isDependentContext()) {
- // Note: We don't type-check when we're in a dependent context, because
- // the initialization-substitution code does not properly handle direct
- // list initialization. We have the same hackaround for ctor-initializers.
+ if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
<< /*at end of ctor*/1 << InitExpr->getSourceRange();
@@ -1930,14 +2002,12 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
FD->setInvalidDecl();
return;
}
-
- CheckImplicitConversions(Init.get(), InitLoc);
}
- // C++0x [class.base.init]p7:
+ // C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- Init = MaybeCreateExprWithCleanups(Init);
+ Init = ActOnFinishFullExpr(Init.take(), InitLoc);
if (Init.isInvalid()) {
FD->setInvalidDecl();
return;
@@ -2096,10 +2166,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// Look for a member, first.
DeclContext::lookup_result Result
= ClassDecl->lookup(MemberOrBase);
- if (Result.first != Result.second) {
+ if (!Result.empty()) {
ValueDecl *Member;
- if ((Member = dyn_cast<FieldDecl>(*Result.first)) ||
- (Member = dyn_cast<IndirectFieldDecl>(*Result.first))) {
+ if ((Member = dyn_cast<FieldDecl>(Result.front())) ||
+ (Member = dyn_cast<IndirectFieldDecl>(Result.front()))) {
if (EllipsisLoc.isValid())
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
<< MemberOrBase
@@ -2295,10 +2365,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
Args = ParenList->getExprs();
NumArgs = ParenList->getNumExprs();
- } else {
- InitListExpr *InitList = cast<InitListExpr>(Init);
+ } else if (InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
+ } else {
+ // Template instantiation doesn't reconstruct ParenListExprs for us.
+ Args = &Init;
+ NumArgs = 1;
}
if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc)
@@ -2349,29 +2422,15 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (MemberInit.isInvalid())
return true;
- CheckImplicitConversions(MemberInit.get(),
- InitRange.getBegin());
-
- // C++0x [class.base.init]p7:
+ // C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- MemberInit = MaybeCreateExprWithCleanups(MemberInit);
+ MemberInit = ActOnFinishFullExpr(MemberInit.get(), InitRange.getBegin());
if (MemberInit.isInvalid())
return true;
- // If we are in a dependent context, template instantiation will
- // perform this type-checking again. Just save the arguments that we
- // received.
- // FIXME: This isn't quite ideal, since our ASTs don't capture all
- // of the information that we have about the member
- // 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()) {
- // The existing Init will do fine.
- } else {
- Init = MemberInit.get();
- CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
- }
+ Init = MemberInit.get();
+ CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
}
if (DirectMember) {
@@ -2389,7 +2448,7 @@ MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
CXXRecordDecl *ClassDecl) {
SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus11)
return Diag(NameLoc, diag::err_delegating_ctor)
<< TInfo->getTypeLoc().getLocalSourceRange();
Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor);
@@ -2421,12 +2480,11 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
assert(cast<CXXConstructExpr>(DelegationInit.get())->getConstructor() &&
"Delegating constructor with no target?");
- CheckImplicitConversions(DelegationInit.get(), InitRange.getBegin());
-
- // C++0x [class.base.init]p7:
+ // C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- DelegationInit = MaybeCreateExprWithCleanups(DelegationInit);
+ DelegationInit = ActOnFinishFullExpr(DelegationInit.get(),
+ InitRange.getBegin());
if (DelegationInit.isInvalid())
return true;
@@ -2555,12 +2613,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (BaseInit.isInvalid())
return true;
- CheckImplicitConversions(BaseInit.get(), InitRange.getBegin());
-
- // C++0x [class.base.init]p7:
- // The initialization of each base and member constitutes a
+ // C++11 [class.base.init]p7:
+ // The initialization of each base and member constitutes a
// full-expression.
- BaseInit = MaybeCreateExprWithCleanups(BaseInit);
+ BaseInit = ActOnFinishFullExpr(BaseInit.get(), InitRange.getBegin());
if (BaseInit.isInvalid())
return true;
@@ -2582,9 +2638,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
// Create a static_cast\<T&&>(expr).
-static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
- QualType ExprType = E->getType();
- QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType);
+static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
+ if (T.isNull()) T = E->getType();
+ QualType TargetType = SemaRef.BuildReferenceType(
+ T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName());
SourceLocation ExprLoc = E->getLocStart();
TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
TargetType, ExprLoc);
@@ -2599,7 +2656,8 @@ static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
enum ImplicitInitializerKind {
IIK_Default,
IIK_Copy,
- IIK_Move
+ IIK_Move,
+ IIK_Inherit
};
static bool
@@ -2615,6 +2673,35 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ExprResult BaseInit;
switch (ImplicitInitKind) {
+ case IIK_Inherit: {
+ const CXXRecordDecl *Inherited =
+ Constructor->getInheritedConstructor()->getParent();
+ const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
+ if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) {
+ // C++11 [class.inhctor]p8:
+ // Each expression in the expression-list is of the form
+ // static_cast<T&&>(p), where p is the name of the corresponding
+ // constructor parameter and T is the declared type of p.
+ SmallVector<Expr*, 16> Args;
+ for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) {
+ ParmVarDecl *PD = Constructor->getParamDecl(I);
+ ExprResult ArgExpr =
+ SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
+ VK_LValue, SourceLocation());
+ if (ArgExpr.isInvalid())
+ return true;
+ Args.push_back(CastForMoving(SemaRef, ArgExpr.take(), PD->getType()));
+ }
+
+ InitializationKind InitKind = InitializationKind::CreateDirect(
+ Constructor->getLocation(), SourceLocation(), SourceLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ Args.data(), Args.size());
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
+ break;
+ }
+ }
+ // Fall through.
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
@@ -2765,7 +2852,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
= VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc,
IterationVarName, SizeType,
SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None, SC_None);
+ SC_None);
IndexVariables.push_back(IterationVar);
// Create a reference to the iteration variable.
@@ -2837,7 +2924,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
return false;
}
- assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
+ assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) &&
+ "Unhandled implicit init kind!");
QualType FieldBaseElementType =
SemaRef.Context.getBaseElementType(Field->getType());
@@ -2928,6 +3016,8 @@ struct BaseAndFieldInfo {
IIK = IIK_Copy;
else if (Generated && Ctor->isMoveConstructor())
IIK = IIK_Move;
+ else if (Ctor->getInheritedConstructor())
+ IIK = IIK_Inherit;
else
IIK = IIK_Default;
}
@@ -2939,6 +3029,7 @@ struct BaseAndFieldInfo {
return true;
case IIK_Default:
+ case IIK_Inherit:
return false;
}
@@ -3059,19 +3150,17 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
return false;
}
-bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Initializers,
- unsigned NumInitializers,
- bool AnyErrors) {
+bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
+ ArrayRef<CXXCtorInitializer *> Initializers) {
if (Constructor->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
- if (NumInitializers > 0) {
- Constructor->setNumCtorInitializers(NumInitializers);
+ if (!Initializers.empty()) {
+ Constructor->setNumCtorInitializers(Initializers.size());
CXXCtorInitializer **baseOrMemberInitializers =
- new (Context) CXXCtorInitializer*[NumInitializers];
- memcpy(baseOrMemberInitializers, Initializers,
- NumInitializers * sizeof(CXXCtorInitializer*));
+ new (Context) CXXCtorInitializer*[Initializers.size()];
+ memcpy(baseOrMemberInitializers, Initializers.data(),
+ Initializers.size() * sizeof(CXXCtorInitializer*));
Constructor->setCtorInitializers(baseOrMemberInitializers);
}
@@ -3092,7 +3181,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
bool HadError = false;
- for (unsigned i = 0; i < NumInitializers; i++) {
+ for (unsigned i = 0; i < Initializers.size(); i++) {
CXXCtorInitializer *Member = Initializers[i];
if (Member->isBaseInitializer())
@@ -3168,7 +3257,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
// If we're not generating the implicit copy/move constructor, then we'll
// handle anonymous struct/union fields based on their individual
// indirect fields.
- if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default)
+ if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove())
continue;
if (CollectFieldInitializer(*this, Info, F))
@@ -3177,7 +3266,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
}
// Beyond this point, we only consider default initialization.
- if (Info.IIK != IIK_Default)
+ if (Info.isImplicitCopyOrMove())
continue;
if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) {
@@ -3195,7 +3284,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
}
}
- NumInitializers = Info.AllToInit.size();
+ unsigned NumInitializers = Info.AllToInit.size();
if (NumInitializers > 0) {
Constructor->setNumCtorInitializers(NumInitializers);
CXXCtorInitializer **baseOrMemberInitializers =
@@ -3213,13 +3302,17 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
return HadError;
}
-static void *GetKeyForTopLevelField(FieldDecl *Field) {
- // For anonymous unions, use the class declaration as the key.
+static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*> &IdealInits) {
if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
- if (RT->getDecl()->isAnonymousStructOrUnion())
- return static_cast<void *>(RT->getDecl());
+ 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);
+ return;
+ }
}
- return static_cast<void *>(Field);
+ IdealInits.push_back(Field);
}
static void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
@@ -3231,40 +3324,19 @@ static void *GetKeyForMember(ASTContext &Context,
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
- // For fields injected into the class via declaration of an anonymous union,
- // use its anonymous union class declaration as the unique key.
- FieldDecl *Field = Member->getAnyMember();
-
- // If the field is a member of an anonymous struct or union, our key
- // is the anonymous record decl that's a direct child of the class.
- RecordDecl *RD = Field->getParent();
- if (RD->isAnonymousStructOrUnion()) {
- while (true) {
- RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext());
- if (Parent->isAnonymousStructOrUnion())
- RD = Parent;
- else
- break;
- }
-
- return static_cast<void *>(RD);
- }
-
- return static_cast<void *>(Field);
+ return Member->getAnyMember();
}
-static void
-DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
- const CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Inits,
- unsigned NumInits) {
+static void DiagnoseBaseOrMemInitializerOrder(
+ Sema &SemaRef, const CXXConstructorDecl *Constructor,
+ ArrayRef<CXXCtorInitializer *> Inits) {
if (Constructor->getDeclContext()->isDependentContext())
return;
// Don't check initializers order unless the warning is enabled at the
// location of at least one initializer.
bool ShouldCheckOrder = false;
- for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order,
Init->getSourceLocation())
@@ -3303,14 +3375,14 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
if (Field->isUnnamedBitfield())
continue;
- IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
+ PopulateKeysForFields(*Field, IdealInitKeys);
}
unsigned NumIdealInits = IdealInitKeys.size();
unsigned IdealIndex = 0;
CXXCtorInitializer *PrevInit = 0;
- for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
void *InitKey = GetKeyForMember(SemaRef.Context, Init);
@@ -3360,7 +3432,7 @@ bool CheckRedundantInit(Sema &S,
return false;
}
- if (FieldDecl *Field = Init->getMember())
+ if (FieldDecl *Field = Init->getAnyMember())
S.Diag(Init->getSourceLocation(),
diag::err_multiple_mem_initialization)
<< Field->getDeclName()
@@ -3420,8 +3492,7 @@ bool CheckRedundantUnionInit(Sema &S,
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
SourceLocation ColonLoc,
- CXXCtorInitializer **meminits,
- unsigned NumMemInits,
+ ArrayRef<CXXCtorInitializer*> MemInits,
bool AnyErrors) {
if (!ConstructorDecl)
return;
@@ -3436,9 +3507,6 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
return;
}
- CXXCtorInitializer **MemInits =
- reinterpret_cast<CXXCtorInitializer **>(meminits);
-
// Mapping for the duplicate initializers check.
// For member initializers, this is keyed with a FieldDecl*.
// For base initializers, this is keyed with a Type*.
@@ -3448,7 +3516,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
RedundantUnionMap MemberUnions;
bool HadError = false;
- for (unsigned i = 0; i < NumMemInits; i++) {
+ for (unsigned i = 0; i < MemInits.size(); i++) {
CXXCtorInitializer *Init = MemInits[i];
// Set the source order index.
@@ -3466,7 +3534,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
} else {
assert(Init->isDelegatingInitializer());
// This must be the only initializer
- if (NumMemInits != 1) {
+ if (MemInits.size() != 1) {
Diag(Init->getSourceLocation(),
diag::err_delegating_initializer_alone)
<< Init->getSourceRange() << MemInits[i ? 0 : 1]->getSourceRange();
@@ -3481,9 +3549,9 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
if (HadError)
return;
- DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits);
+ DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits);
- SetCtorInitializers(Constructor, MemInits, NumMemInits, AnyErrors);
+ SetCtorInitializers(Constructor, AnyErrors, MemInits);
}
void
@@ -3605,7 +3673,7 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) {
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl))
- SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false);
+ SetCtorInitializers(Constructor, /*AnyErrors=*/false);
}
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
@@ -3748,7 +3816,7 @@ struct CheckAbstractUsage {
switch (TL.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
- case TypeLoc::CLASS: Check(cast<CLASS##TypeLoc>(TL), Sel); break;
+ case TypeLoc::CLASS: Check(TL.castAs<CLASS##TypeLoc>(), Sel); break;
#include "clang/AST/TypeLocNodes.def"
}
}
@@ -3933,9 +4001,10 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// C++ [class.mem]p14:
// In addition, if class T has a user-declared constructor (12.1), every
// non-static data member of class T shall have a name different from T.
- for (DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
- R.first != R.second; ++R.first) {
- NamedDecl *D = *R.first;
+ DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ NamedDecl *D = *I;
if ((isa<FieldDecl>(D) && Record->hasUserDeclaredConstructor()) ||
isa<IndirectFieldDecl>(D)) {
Diag(D->getLocation(), diag::err_member_name_of_class)
@@ -3958,18 +4027,34 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
DiagnoseAbstractType(Record);
}
- // See if a method overloads virtual methods in a base
- /// class without overriding any.
if (!Record->isDependentType()) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
+ // See if a method overloads virtual methods in a base
+ // class without overriding any.
if (!M->isStatic())
DiagnoseHiddenVirtualMethods(Record, *M);
+
+ // Check whether the explicitly-defaulted special members are valid.
+ if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
+ 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);
+ if (CSM != CXXInvalid) {
+ M->setTrivial(SpecialMemberIsTrivial(*M, CSM));
+
+ // Inform the class that we've finished declaring this member.
+ Record->finishedDefaultedOrDeletedMember(*M);
+ }
+ }
}
}
- // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
+ // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
// function that is not a constructor declares that member function to be
// const. [...] The class of which that function is a member shall be
// a literal type.
@@ -3977,7 +4062,10 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// If the class has virtual bases, any constexpr members will already have
// been diagnosed by the checks performed on the member declaration, so
// suppress this (less useful) diagnostic.
- if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
+ //
+ // We delay this until we know whether an explicitly-defaulted (or deleted)
+ // 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();
@@ -4005,22 +4093,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
- // Declare inherited constructors. We do this eagerly here because:
- // - The standard requires an eager diagnostic for conflicting inherited
+ // Declare inheriting constructors. We do this eagerly here because:
+ // - The standard requires an eager diagnostic for conflicting inheriting
// constructors from different classes.
// - The lazy declaration of the other implicit constructors is so as to not
// waste space and performance on classes that are not meant to be
// instantiated (e.g. meta-functions). This doesn't apply to classes that
- // have inherited constructors.
- DeclareInheritedConstructors(Record);
-}
-
-void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
- for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
- ME = Record->method_end();
- MI != ME; ++MI)
- if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
- CheckExplicitlyDefaultedSpecialMember(*MI);
+ // have inheriting constructors.
+ DeclareInheritingConstructors(Record);
}
/// Is the special member function which would be selected to perform the
@@ -4043,7 +4123,7 @@ static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
Sema::CXXSpecialMember CSM,
bool ConstArg) {
- if (!S.getLangOpts().CPlusPlus0x)
+ if (!S.getLangOpts().CPlusPlus11)
return false;
// C++11 [dcl.constexpr]p4:
@@ -4136,7 +4216,9 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
case Sema::CXXInvalid:
break;
}
- llvm_unreachable("only special members have implicit exception specs");
+ assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
+ "only special members have implicit exception specs");
+ return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
}
static void
@@ -4145,8 +4227,7 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
ExceptSpec.getEPI(EPI);
const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
- S.Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI));
+ S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI));
FD->setType(QualType(NewFPT, 0));
}
@@ -4172,9 +4253,6 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
CanonicalFPT, ExceptSpec);
}
-static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl);
-static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl);
-
void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
CXXRecordDecl *RD = MD->getParent();
CXXSpecialMember CSM = getSpecialMember(MD);
@@ -4205,37 +4283,19 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
Diag(MD->getLocation(), diag::err_defaulted_special_member_params)
<< CSM << MD->getSourceRange();
HadError = true;
+ } else if (MD->isVariadic()) {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_variadic)
+ << CSM << MD->getSourceRange();
+ HadError = true;
}
const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
- // Compute argument constness, constexpr, and triviality.
bool CanHaveConstParam = false;
- bool Trivial = false;
- switch (CSM) {
- case CXXDefaultConstructor:
- Trivial = RD->hasTrivialDefaultConstructor();
- break;
- case CXXCopyConstructor:
- CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD);
- Trivial = RD->hasTrivialCopyConstructor();
- break;
- case CXXCopyAssignment:
- CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD);
- Trivial = RD->hasTrivialCopyAssignment();
- break;
- case CXXMoveConstructor:
- Trivial = RD->hasTrivialMoveConstructor();
- break;
- case CXXMoveAssignment:
- Trivial = RD->hasTrivialMoveAssignment();
- break;
- case CXXDestructor:
- Trivial = RD->hasTrivialDestructor();
- break;
- case CXXInvalid:
- llvm_unreachable("non-special member explicitly defaulted!");
- }
+ if (CSM == CXXCopyConstructor)
+ CanHaveConstParam = RD->implicitCopyConstructorHasConstParam();
+ else if (CSM == CXXCopyAssignment)
+ CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam();
QualType ReturnType = Context.VoidTy;
if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
@@ -4284,14 +4344,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
}
HadError = true;
}
-
- // If a function is explicitly defaulted on its first declaration, it shall
- // have the same parameter type as if it had been implicitly declared.
- // (Presumably this is to prevent it from being trivial?)
- if (!HasConstParam && CanHaveConstParam && First)
- Diag(MD->getLocation(),
- diag::err_defaulted_special_member_copy_non_const_param)
- << (CSM == CXXCopyAssignment);
} else if (ExpectedParams) {
// A copy assignment operator can take its argument by value, but a
// defaulted one cannot.
@@ -4300,16 +4352,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
HadError = true;
}
- // Rebuild the type with the implicit exception specification added, if we
- // are going to need it.
- const FunctionProtoType *ImplicitType = 0;
- if (First || Type->hasExceptionSpec()) {
- FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
- computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
- ImplicitType = cast<FunctionProtoType>(
- Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI));
- }
-
// C++11 [dcl.fct.def.default]p2:
// An explicitly-defaulted function may be declared constexpr only if it
// would have been implicitly declared as constexpr,
@@ -4324,13 +4366,23 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// FIXME: Explain why the constructor can't be constexpr.
HadError = true;
}
+
// and may have an explicit exception-specification only if it is compatible
// with the exception-specification on the implicit declaration.
- if (Type->hasExceptionSpec() &&
- CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec) << CSM,
- PDiag(), ImplicitType, SourceLocation(), Type, MD->getLocation()))
- HadError = true;
+ if (Type->hasExceptionSpec()) {
+ // Delay the check if this is the first declaration of the special member,
+ // since we may not have parsed some necessary in-class initializers yet.
+ if (First) {
+ // If the exception specification needs to be instantiated, do so now,
+ // before we clobber it with an EST_Unevaluated specification below.
+ if (Type->getExceptionSpecType() == EST_Uninstantiated) {
+ InstantiateExceptionSpec(MD->getLocStart(), MD);
+ Type = MD->getType()->getAs<FunctionProtoType>();
+ }
+ DelayedDefaultedMemberExceptionSpecs.push_back(std::make_pair(MD, Type));
+ } else
+ CheckExplicitlyDefaultedMemberExceptionSpec(MD, Type);
+ }
// If a function is explicitly defaulted on its first declaration,
if (First) {
@@ -4340,16 +4392,18 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// -- it is implicitly considered to have the same exception-specification
// as if it had been implicitly declared,
- MD->setType(QualType(ImplicitType, 0));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(Trivial);
+ FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = MD;
+ MD->setType(Context.getFunctionType(ReturnType,
+ ArrayRef<QualType>(&ArgType,
+ ExpectedParams),
+ EPI));
}
if (ShouldDeleteSpecialMember(MD, CSM)) {
if (First) {
- MD->setDeletedAsWritten();
+ SetDeclDeleted(MD, MD->getLocation());
} else {
// C++11 [dcl.fct.def.default]p4:
// [For a] user-provided explicitly-defaulted function [...] if such a
@@ -4363,6 +4417,36 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
MD->setInvalidDecl();
}
+/// Check whether the exception specification provided for an
+/// explicitly-defaulted special member matches the exception specification
+/// that would have been generated for an implicit special member, per
+/// C++11 [dcl.fct.def.default]p2.
+void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
+ CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
+ // Compute the implicit exception specification.
+ FunctionProtoType::ExtProtoInfo EPI;
+ computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
+ const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
+ Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI));
+
+ // Ensure that it matches.
+ CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << getSpecialMember(MD), PDiag(),
+ ImplicitType, SourceLocation(),
+ SpecifiedType, MD->getLocation());
+}
+
+void Sema::CheckDelayedExplicitlyDefaultedMemberExceptionSpecs() {
+ for (unsigned I = 0, N = DelayedDefaultedMemberExceptionSpecs.size();
+ I != N; ++I)
+ CheckExplicitlyDefaultedMemberExceptionSpec(
+ DelayedDefaultedMemberExceptionSpecs[I].first,
+ DelayedDefaultedMemberExceptionSpecs[I].second);
+
+ DelayedDefaultedMemberExceptionSpecs.clear();
+}
+
namespace {
struct SpecialMemberDeletionInfo {
Sema &S;
@@ -4688,7 +4772,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
return false;
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
+ if (!LangOpts.CPlusPlus11 || RD->isInvalidDecl())
return false;
// C++11 [expr.lambda.prim]p19:
@@ -4722,12 +4806,28 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
if (RD->hasUserDeclaredMoveConstructor() &&
(!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) {
if (!Diagnose) return true;
- UserDeclaredMove = RD->getMoveConstructor();
+
+ // Find any user-declared move constructor.
+ for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
+ E = RD->ctor_end(); I != E; ++I) {
+ if (I->isMoveConstructor()) {
+ UserDeclaredMove = *I;
+ break;
+ }
+ }
assert(UserDeclaredMove);
} else if (RD->hasUserDeclaredMoveAssignment() &&
(!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) {
if (!Diagnose) return true;
- UserDeclaredMove = RD->getMoveAssignmentOperator();
+
+ // Find any user-declared move assignment operator.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ if (I->isMoveAssignmentOperator()) {
+ UserDeclaredMove = *I;
+ break;
+ }
+ }
assert(UserDeclaredMove);
}
@@ -4783,6 +4883,422 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
return false;
}
+/// Perform lookup for a special member of the specified kind, and determine
+/// whether it is trivial. If the triviality can be determined without the
+/// lookup, skip it. This is intended for use when determining whether a
+/// special member of a containing object is trivial, and thus does not ever
+/// perform overload resolution for default constructors.
+///
+/// If \p Selected is not \c NULL, \c *Selected will be filled in with the
+/// 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) {
+ if (Selected)
+ *Selected = 0;
+
+ switch (CSM) {
+ case Sema::CXXInvalid:
+ llvm_unreachable("not a special member");
+
+ case Sema::CXXDefaultConstructor:
+ // C++11 [class.ctor]p5:
+ // A default constructor is trivial if:
+ // - all the [direct subobjects] have trivial default constructors
+ //
+ // Note, no overload resolution is performed in this case.
+ if (RD->hasTrivialDefaultConstructor())
+ return true;
+
+ if (Selected) {
+ // 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;
+ if (RD->needsImplicitDefaultConstructor())
+ S.DeclareImplicitDefaultConstructor(RD);
+ for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(),
+ CE = RD->ctor_end(); CI != CE; ++CI) {
+ if (!CI->isDefaultConstructor())
+ continue;
+ DefCtor = *CI;
+ if (!DefCtor->isUserProvided())
+ break;
+ }
+
+ *Selected = DefCtor;
+ }
+
+ return false;
+
+ case Sema::CXXDestructor:
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if:
+ // - all the direct [subobjects] have trivial destructors
+ if (RD->hasTrivialDestructor())
+ return true;
+
+ if (Selected) {
+ if (RD->needsImplicitDestructor())
+ S.DeclareImplicitDestructor(RD);
+ *Selected = RD->getDestructor();
+ }
+
+ return false;
+
+ case Sema::CXXCopyConstructor:
+ // C++11 [class.copy]p12:
+ // A copy constructor is trivial if:
+ // - the constructor selected to copy each direct [subobject] is trivial
+ if (RD->hasTrivialCopyConstructor()) {
+ if (Quals == Qualifiers::Const)
+ // We must either select the trivial copy constructor or reach an
+ // ambiguity; no need to actually perform overload resolution.
+ return true;
+ } else if (!Selected) {
+ return false;
+ }
+ // In C++98, we are not supposed to perform overload resolution here, but we
+ // treat that as a language defect, as suggested on cxx-abi-dev, to treat
+ // cases like B as having a non-trivial copy constructor:
+ // struct A { template<typename T> A(T&); };
+ // struct B { mutable A a; };
+ goto NeedOverloadResolution;
+
+ case Sema::CXXCopyAssignment:
+ // C++11 [class.copy]p25:
+ // A copy assignment operator is trivial if:
+ // - the assignment operator selected to copy each direct [subobject] is
+ // trivial
+ if (RD->hasTrivialCopyAssignment()) {
+ if (Quals == Qualifiers::Const)
+ return true;
+ } else if (!Selected) {
+ return false;
+ }
+ // In C++98, we are not supposed to perform overload resolution here, but we
+ // treat that as a language defect.
+ goto NeedOverloadResolution;
+
+ case Sema::CXXMoveConstructor:
+ case Sema::CXXMoveAssignment:
+ NeedOverloadResolution:
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(RD, CSM,
+ Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile,
+ /*RValueThis*/false, /*ConstThis*/false,
+ /*VolatileThis*/false);
+
+ // 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
+ // mandates for the default constructor. This should rarely matter, because
+ // the member will also be deleted.
+ if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ return true;
+
+ if (!SMOR->getMethod()) {
+ assert(SMOR->getKind() ==
+ Sema::SpecialMemberOverloadResult::NoMemberOrDeleted);
+ return false;
+ }
+
+ // We deliberately don't check if we found a deleted special member. We're
+ // not supposed to!
+ if (Selected)
+ *Selected = SMOR->getMethod();
+ return SMOR->getMethod()->isTrivial();
+ }
+
+ llvm_unreachable("unknown special method kind");
+}
+
+static CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) {
+ for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), CE = RD->ctor_end();
+ CI != CE; ++CI)
+ if (!CI->isImplicit())
+ return *CI;
+
+ // Look for constructor templates.
+ typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter;
+ for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) {
+ if (CXXConstructorDecl *CD =
+ dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl()))
+ return CD;
+ }
+
+ return 0;
+}
+
+/// The kind of subobject we are checking for triviality. The values of this
+/// enumeration are used in diagnostics.
+enum TrivialSubobjectKind {
+ /// The subobject is a base class.
+ TSK_BaseClass,
+ /// The subobject is a non-static data member.
+ TSK_Field,
+ /// The object is actually the complete object.
+ TSK_CompleteObject
+};
+
+/// Check whether the special member selected for a given type would be trivial.
+static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
+ QualType SubType,
+ Sema::CXXSpecialMember CSM,
+ TrivialSubobjectKind Kind,
+ bool Diagnose) {
+ CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl();
+ if (!SubRD)
+ return true;
+
+ CXXMethodDecl *Selected;
+ if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(),
+ Diagnose ? &Selected : 0))
+ return true;
+
+ if (Diagnose) {
+ if (!Selected && CSM == Sema::CXXDefaultConstructor) {
+ S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor)
+ << Kind << SubType.getUnqualifiedType();
+ if (CXXConstructorDecl *CD = findUserDeclaredCtor(SubRD))
+ S.Diag(CD->getLocation(), diag::note_user_declared_ctor);
+ } else if (!Selected)
+ S.Diag(SubobjLoc, diag::note_nontrivial_no_copy)
+ << Kind << SubType.getUnqualifiedType() << CSM << SubType;
+ else if (Selected->isUserProvided()) {
+ if (Kind == TSK_CompleteObject)
+ S.Diag(Selected->getLocation(), diag::note_nontrivial_user_provided)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+ else {
+ S.Diag(SubobjLoc, diag::note_nontrivial_user_provided)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+ S.Diag(Selected->getLocation(), diag::note_declared_at);
+ }
+ } else {
+ if (Kind != TSK_CompleteObject)
+ S.Diag(SubobjLoc, diag::note_nontrivial_subobject)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+
+ // Explain why the defaulted or deleted special member isn't trivial.
+ S.SpecialMemberIsTrivial(Selected, CSM, Diagnose);
+ }
+ }
+
+ return false;
+}
+
+/// Check whether the members of a class type allow a special member to be
+/// trivial.
+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) {
+ if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
+ continue;
+
+ QualType FieldType = S.Context.getBaseElementType(FI->getType());
+
+ // Pretend anonymous struct or union members are members of this class.
+ if (FI->isAnonymousStructOrUnion()) {
+ if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(),
+ CSM, ConstArg, Diagnose))
+ return false;
+ continue;
+ }
+
+ // C++11 [class.ctor]p5:
+ // A default constructor is trivial if [...]
+ // -- no non-static data member of its class has a
+ // brace-or-equal-initializer
+ if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) {
+ if (Diagnose)
+ S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << *FI;
+ return false;
+ }
+
+ // Objective C ARC 4.3.5:
+ // [...] nontrivally ownership-qualified types are [...] not trivially
+ // default constructible, copy constructible, move constructible, copy
+ // assignable, move assignable, or destructible [...]
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ FieldType.hasNonTrivialObjCLifetime()) {
+ if (Diagnose)
+ S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership)
+ << RD << FieldType.getObjCLifetime();
+ return false;
+ }
+
+ if (ConstArg && !FI->isMutable())
+ FieldType.addConst();
+ if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, CSM,
+ TSK_Field, Diagnose))
+ return false;
+ }
+
+ return true;
+}
+
+/// Diagnose why the specified class does not have a trivial special member of
+/// 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,
+ TSK_CompleteObject, /*Diagnose*/true);
+}
+
+/// Determine whether a defaulted or deleted special member function is trivial,
+/// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12,
+/// C++11 [class.copy]p25, and C++11 [class.dtor]p5.
+bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose) {
+ assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough");
+
+ CXXRecordDecl *RD = MD->getParent();
+
+ bool ConstArg = false;
+
+ // C++11 [class.copy]p12, p25:
+ // A [special member] is trivial if its declared parameter type is the same
+ // as if it had been implicitly declared [...]
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ case CXXDestructor:
+ // Trivial default constructors and destructors cannot have parameters.
+ break;
+
+ case CXXCopyConstructor:
+ case CXXCopyAssignment: {
+ // Trivial copy operations always have const, non-volatile parameter types.
+ ConstArg = true;
+ const ParmVarDecl *Param0 = MD->getParamDecl(0);
+ const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
+ if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
+ if (Diagnose)
+ Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
+ << Param0->getSourceRange() << Param0->getType()
+ << Context.getLValueReferenceType(
+ Context.getRecordType(RD).withConst());
+ return false;
+ }
+ break;
+ }
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment: {
+ // Trivial move operations always have non-cv-qualified parameters.
+ const ParmVarDecl *Param0 = MD->getParamDecl(0);
+ const RValueReferenceType *RT =
+ Param0->getType()->getAs<RValueReferenceType>();
+ if (!RT || RT->getPointeeType().getCVRQualifiers()) {
+ if (Diagnose)
+ Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
+ << Param0->getSourceRange() << Param0->getType()
+ << Context.getRValueReferenceType(Context.getRecordType(RD));
+ return false;
+ }
+ break;
+ }
+
+ case CXXInvalid:
+ llvm_unreachable("not a special member");
+ }
+
+ // FIXME: We require that the parameter-declaration-clause is equivalent to
+ // that of an implicit declaration, not just that the declared parameter type
+ // matches, in order to prevent absuridities like a function simultaneously
+ // being a trivial copy constructor and a non-trivial default constructor.
+ // This issue has not yet been assigned a core issue number.
+ if (MD->getMinRequiredArguments() < MD->getNumParams()) {
+ if (Diagnose)
+ Diag(MD->getParamDecl(MD->getMinRequiredArguments())->getLocation(),
+ diag::note_nontrivial_default_arg)
+ << MD->getParamDecl(MD->getMinRequiredArguments())->getSourceRange();
+ return false;
+ }
+ if (MD->isVariadic()) {
+ if (Diagnose)
+ Diag(MD->getLocation(), diag::note_nontrivial_variadic);
+ return false;
+ }
+
+ // C++11 [class.ctor]p5, C++11 [class.dtor]p5:
+ // A copy/move [constructor or assignment operator] is trivial if
+ // -- the [member] selected to copy/move each direct base class subobject
+ // is trivial
+ //
+ // C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // 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))
+ return false;
+
+ // C++11 [class.ctor]p5, C++11 [class.dtor]p5:
+ // A copy/move [constructor or assignment operator] for a class X is
+ // trivial if
+ // -- for each non-static data member of X that is of class type (or array
+ // thereof), the constructor selected to copy/move that member is
+ // trivial
+ //
+ // C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor or destructor] is trivial if
+ // -- for all of the non-static data members of its class that are of class
+ // type (or array thereof), each such class has a trivial [default
+ // constructor or destructor]
+ if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose))
+ return false;
+
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if [...]
+ // -- the destructor is not virtual
+ if (CSM == CXXDestructor && MD->isVirtual()) {
+ if (Diagnose)
+ Diag(MD->getLocation(), diag::note_nontrivial_virtual_dtor) << RD;
+ return false;
+ }
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [special member] for class X is trivial if [...]
+ // -- class X has no virtual functions and no virtual base classes
+ if (CSM != CXXDestructor && MD->getParent()->isDynamicClass()) {
+ if (!Diagnose)
+ return false;
+
+ if (RD->getNumVBases()) {
+ // Check for virtual bases. We already know that the corresponding
+ // member in all bases is trivial, so vbases must all be direct.
+ CXXBaseSpecifier &BS = *RD->vbases_begin();
+ assert(BS.isVirtual());
+ Diag(BS.getLocStart(), diag::note_nontrivial_has_virtual) << RD << 1;
+ return false;
+ }
+
+ // Must have a virtual method.
+ for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
+ ME = RD->method_end(); MI != ME; ++MI) {
+ if (MI->isVirtual()) {
+ SourceLocation MLoc = MI->getLocStart();
+ Diag(MLoc, diag::note_nontrivial_has_virtual) << RD << 0;
+ return false;
+ }
+ }
+
+ llvm_unreachable("dynamic class with no vbases and no virtual functions");
+ }
+
+ // Looks like it's trivial!
+ return true;
+}
+
/// \brief Data used with FindHiddenVirtualMethod
namespace {
struct FindHiddenVirtualMethodData {
@@ -4823,9 +5339,9 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
bool foundSameNameMethod = false;
SmallVector<CXXMethodDecl *, 8> overloadedMethods;
for (Path.Decls = BaseRecord->lookup(Name);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- NamedDecl *D = *Path.Decls.first;
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ NamedDecl *D = Path.Decls.front();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
MD = MD->getCanonicalDecl();
foundSameNameMethod = true;
@@ -4877,10 +5393,10 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
// Keep the base methods that were overriden or introduced in the subclass
// by 'using' in a set. A base method not in this set is hidden.
- for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName());
- res.first != res.second; ++res.first) {
- NamedDecl *ND = *res.first;
- if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first))
+ DeclContext::lookup_result R = DC->lookup(MD->getDeclName());
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *ND = *I;
+ if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*I))
ND = shad->getTargetDecl();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods);
@@ -4935,39 +5451,53 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
if (!ClassDecl->hasUserDeclaredConstructor())
++ASTContext::NumImplicitDefaultConstructors;
- if (!ClassDecl->hasUserDeclaredCopyConstructor())
+ if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
++ASTContext::NumImplicitCopyConstructors;
- if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor())
+ // If the properties or semantics of the copy constructor couldn't be
+ // determined while the class was being declared, force a declaration
+ // of it now.
+ if (ClassDecl->needsOverloadResolutionForCopyConstructor())
+ DeclareImplicitCopyConstructor(ClassDecl);
+ }
+
+ if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
++ASTContext::NumImplicitMoveConstructors;
+ if (ClassDecl->needsOverloadResolutionForMoveConstructor())
+ DeclareImplicitMoveConstructor(ClassDecl);
+ }
+
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
-
- // If we have a dynamic class, then the copy assignment operator may be
+
+ // If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
- // it shows up in the right place in the vtable and that we diagnose
- // problems with the implicit exception specification.
- if (ClassDecl->isDynamicClass())
+ // it shows up in the right place in the vtable and that we diagnose
+ // problems with the implicit exception specification.
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
- if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveAssignment()) {
+ if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
++ASTContext::NumImplicitMoveAssignmentOperators;
// Likewise for the move assignment operator.
- if (ClassDecl->isDynamicClass())
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForMoveAssignment())
DeclareImplicitMoveAssignment(ClassDecl);
}
if (!ClassDecl->hasUserDeclaredDestructor()) {
++ASTContext::NumImplicitDestructors;
-
- // If we have a dynamic class, then the destructor may be virtual, so we
+
+ // If we have a dynamic class, then the destructor may be virtual, so we
// have to declare the destructor immediately. This ensures that, e.g., it
// shows up in the right place in the vtable and that we diagnose problems
// with the implicit exception specification.
- if (ClassDecl->isDynamicClass())
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForDestructor())
DeclareImplicitDestructor(ClassDecl);
}
}
@@ -5150,8 +5680,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
- Proto->getNumArgs(), EPI);
+ return Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), EPI);
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -5331,7 +5860,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
EPI.Variadic = false;
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
+ return Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI);
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -5412,12 +5941,13 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// of the errors above fired) and with the conversion type as the
// return type.
if (D.isInvalidType())
- R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo());
+ R = Context.getFunctionType(ConvType, ArrayRef<QualType>(),
+ Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified())
Diag(D.getDeclSpec().getExplicitSpecLoc(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_explicit_conversion_functions :
diag::ext_explicit_conversion_functions)
<< SourceRange(D.getDeclSpec().getExplicitSpecLoc());
@@ -5551,11 +6081,11 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
Decl::IDNS_Namespace;
NamedDecl *PrevDecl = 0;
- for (DeclContext::lookup_result R
- = CurContext->getRedeclContext()->lookup(II);
- R.first != R.second; ++R.first) {
- if ((*R.first)->getIdentifierNamespace() & IDNS) {
- PrevDecl = *R.first;
+ DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ if ((*I)->getIdentifierNamespace() & IDNS) {
+ PrevDecl = *I;
break;
}
}
@@ -5978,7 +6508,9 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
}
- // FIXME: We ignore attributes for now.
+ if (UDir)
+ ProcessDeclAttributeList(S, UDir, AttrList);
+
return UDir;
}
@@ -6019,14 +6551,12 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
case UnqualifiedId::IK_ConstructorTemplateId:
// C++11 inheriting constructors.
Diag(Name.getLocStart(),
- getLangOpts().CPlusPlus0x ?
- // FIXME: Produce warn_cxx98_compat_using_decl_constructor
- // instead once inheriting constructors work.
- diag::err_using_decl_constructor_unsupported :
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_using_decl_constructor :
diag::err_using_decl_constructor)
<< SS.getRange();
- if (getLangOpts().CPlusPlus0x) break;
+ if (getLangOpts().CPlusPlus11) break;
return 0;
@@ -6046,7 +6576,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
if (!TargetName)
return 0;
- // Warn about using declarations.
+ // Warn about access declarations.
// TODO: store that the declaration was written without 'using' and
// talk about access decls instead of using decls in the
// diagnostics.
@@ -6116,7 +6646,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// specialization. The UsingShadowDecl in D<T> then points directly
// to A::foo, which will look well-formed when we instantiate.
// The right solution is to not collapse the shadow-decl chain.
- if (!getLangOpts().CPlusPlus0x && CurContext->isRecord()) {
+ if (!getLangOpts().CPlusPlus11 && CurContext->isRecord()) {
DeclContext *OrigDC = Orig->getDeclContext();
// Handle enums and anonymous structs.
@@ -6605,7 +7135,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext))
return true;
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++0x [namespace.udecl]p3:
// In a using-declaration used as a member-declaration, the
// nested-name-specifier shall name a base class of the class
@@ -6694,6 +7224,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
MultiTemplateParamsArg TemplateParamLists,
SourceLocation UsingLoc,
UnqualifiedId &Name,
+ AttributeList *AttrList,
TypeResult Type) {
// Skip up to the relevant declaration scope.
while (S->getFlags() & Scope::TemplateParamScope)
@@ -6740,6 +7271,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewTD->setInvalidDecl();
+ ProcessDeclAttributeList(S, NewTD, AttrList);
+
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
@@ -6969,6 +7502,43 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
return ExceptSpec;
}
+Sema::ImplicitExceptionSpecification
+Sema::ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD) {
+ ImplicitExceptionSpecification ExceptSpec(*this);
+ // FIXME: Compute the exception spec.
+ return ExceptSpec;
+}
+
+namespace {
+/// RAII object to register a special member as being currently declared.
+struct DeclaringSpecialMember {
+ Sema &S;
+ Sema::SpecialMemberDecl D;
+ bool WasAlreadyBeingDeclared;
+
+ DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
+ : S(S), D(RD, CSM) {
+ WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D);
+ if (WasAlreadyBeingDeclared)
+ // This almost never happens, but if it does, ensure that our cache
+ // doesn't contain a stale result.
+ S.SpecialMemberCache.clear();
+
+ // FIXME: Register a note to be produced if we encounter an error while
+ // declaring the special member.
+ }
+ ~DeclaringSpecialMember() {
+ if (!WasAlreadyBeingDeclared)
+ S.SpecialMembersBeingDeclared.erase(D);
+ }
+
+ /// \brief Are we already trying to declare this special member?
+ bool isAlreadyBeingDeclared() const {
+ return WasAlreadyBeingDeclared;
+ }
+};
+}
+
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
CXXRecordDecl *ClassDecl) {
// C++ [class.ctor]p5:
@@ -6977,9 +7547,13 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// user-declared constructor for class X, a default constructor is
// implicitly declared. An implicitly-declared default constructor
// is an inline public member of its class.
- assert(!ClassDecl->hasUserDeclaredConstructor() &&
+ assert(ClassDecl->needsImplicitDefaultConstructor() &&
"Should not build implicit default constructor!");
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXDefaultConstructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
+
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
CXXDefaultConstructor,
false);
@@ -6998,24 +7572,29 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
- DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = DefaultCon;
- DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ DefaultCon->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
+
+ // We don't need to use SpecialMemberIsTrivial here; triviality for default
+ // constructors is easy to compute.
+ DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
+
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
+ SetDeclDeleted(DefaultCon, ClassLoc);
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
-
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
- if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
- DefaultCon->setDeletedAsWritten();
-
return DefaultCon;
}
@@ -7031,7 +7610,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
SynthesizedFunctionScope Scope(*this, Constructor);
DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
+ if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
@@ -7051,16 +7630,12 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
- if (!D) return;
- AdjustDeclIfTemplate(D);
-
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
-
- if (!ClassDecl->isDependentType())
- CheckExplicitlyDefaultedMethods(ClassDecl);
+ // Check that any explicitly-defaulted methods have exception specifications
+ // compatible with their implicit exception specifications.
+ CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
}
-void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
+void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
// We start with an initial pass over the base classes to collect those that
// inherit constructors from. If there are none, we can forgo all further
// processing.
@@ -7075,6 +7650,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// If we inherit constructors from anything that is dependent, just
// abort processing altogether. We'll get another chance for the
// instantiations.
+ // FIXME: We need to ensure that any call to a constructor of this class
+ // is considered instantiation-dependent in this case.
return;
}
BasesToInheritFrom.push_back(Base->castAs<RecordType>());
@@ -7083,18 +7660,19 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
if (BasesToInheritFrom.empty())
return;
+ // FIXME: Constructor templates.
+
// Now collect the constructors that we already have in the current class.
// Those take precedence over inherited constructors.
- // C++0x [class.inhctor]p3: [...] a constructor is implicitly declared [...]
+ // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...]
// unless there is a user-declared constructor with the same signature in
// the class where the using-declaration appears.
llvm::SmallSet<const Type *, 8> ExistingConstructors;
for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(),
CtorE = ClassDecl->ctor_end();
- CtorIt != CtorE; ++CtorIt) {
+ CtorIt != CtorE; ++CtorIt)
ExistingConstructors.insert(
Context.getCanonicalType(CtorIt->getType()).getTypePtr());
- }
DeclarationName CreatedCtorName =
Context.DeclarationNames.getCXXConstructorName(
@@ -7126,62 +7704,71 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
SourceLocation UsingLoc = UD ? UD->getLocation() :
ClassDecl->getLocation();
- // C++0x [class.inhctor]p1: The candidate set of inherited constructors
- // from the class X named in the using-declaration consists of actual
- // constructors and notional constructors that result from the
- // transformation of defaulted parameters as follows:
- // - all non-template default constructors of X, and
+ // C++11 [class.inhctor]p1:
+ // The candidate set of inherited constructors from the class X named in
+ // the using-declaration consists of actual constructors and notional
+ // constructors that result from the transformation of defaulted
+ // parameters as follows:
+ // - all non-template constructors of X, and
// - for each non-template constructor of X that has at least one
// parameter with a default argument, the set of constructors that
// results from omitting any ellipsis parameter specification and
// successively omitting parameters with a default argument from the
- // end of the parameter-type-list.
+ // end of the parameter-type-list, and
+ // FIXME: ...also constructor templates.
CXXConstructorDecl *BaseCtor = *CtorIt;
bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor();
const FunctionProtoType *BaseCtorType =
BaseCtor->getType()->getAs<FunctionProtoType>();
- for (unsigned params = BaseCtor->getMinRequiredArguments(),
- maxParams = BaseCtor->getNumParams();
- params <= maxParams; ++params) {
+ // Determine whether this would be a copy or move constructor for the
+ // derived class.
+ if (BaseCtorType->getNumArgs() >= 1 &&
+ BaseCtorType->getArgType(0)->isReferenceType() &&
+ Context.hasSameUnqualifiedType(
+ BaseCtorType->getArgType(0)->getPointeeType(),
+ Context.getTagDeclType(ClassDecl)))
+ CanBeCopyOrMove = true;
+
+ ArrayRef<QualType> ArgTypes(BaseCtorType->getArgTypes());
+ FunctionProtoType::ExtProtoInfo EPI = BaseCtorType->getExtProtoInfo();
+ // Core issue (no number yet): the ellipsis is always discarded.
+ if (EPI.Variadic) {
+ Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
+ Diag(BaseCtor->getLocation(),
+ diag::note_using_decl_constructor_ellipsis);
+ EPI.Variadic = false;
+ }
+
+ for (unsigned Params = BaseCtor->getMinRequiredArguments(),
+ MaxParams = BaseCtor->getNumParams();
+ Params <= MaxParams; ++Params) {
// Skip default constructors. They're never inherited.
- if (params == 0)
+ if (Params == 0)
continue;
- // Skip copy and move constructors for the same reason.
- if (CanBeCopyOrMove && params == 1)
+
+ // Skip copy and move constructors for both base and derived class
+ // for the same reason.
+ if (CanBeCopyOrMove && Params == 1)
continue;
// Build up a function type for this particular constructor.
- // FIXME: The working paper does not consider that the exception spec
- // for the inheriting constructor might be larger than that of the
- // source. This code doesn't yet, either. When it does, this code will
- // need to be delayed until after exception specifications and in-class
- // member initializers are attached.
- const Type *NewCtorType;
- if (params == maxParams)
- NewCtorType = BaseCtorType;
- else {
- SmallVector<QualType, 16> Args;
- for (unsigned i = 0; i < params; ++i) {
- Args.push_back(BaseCtorType->getArgType(i));
- }
- FunctionProtoType::ExtProtoInfo ExtInfo =
- BaseCtorType->getExtProtoInfo();
- ExtInfo.Variadic = false;
- NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(),
- Args.data(), params, ExtInfo)
- .getTypePtr();
- }
+ QualType NewCtorType =
+ Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params),
+ EPI);
const Type *CanonicalNewCtorType =
- Context.getCanonicalType(NewCtorType);
+ Context.getCanonicalType(NewCtorType).getTypePtr();
- // Now that we have the type, first check if the class already has a
- // constructor with this signature.
+ // C++11 [class.inhctor]p3:
+ // ... a constructor is implicitly declared with the same constructor
+ // characteristics unless there is a user-declared constructor with
+ // the same signature in the class where the using-declaration appears
if (ExistingConstructors.count(CanonicalNewCtorType))
continue;
- // Then we check if we have already declared an inherited constructor
- // with this signature.
+ // C++11 [class.inhctor]p7:
+ // If two using-declarations declare inheriting constructors with the
+ // same signature, the program is ill-formed
std::pair<ConstructorToSourceMap::iterator, bool> result =
InheritedConstructors.insert(std::make_pair(
CanonicalNewCtorType,
@@ -7203,35 +7790,47 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
diag::note_using_decl_constructor_conflict_previous_ctor);
Diag(PrevCtor->getLocation(),
diag::note_using_decl_constructor_conflict_previous_using);
+ } else {
+ // Core issue (no number): if the same inheriting constructor is
+ // produced by multiple base class constructors from the same base
+ // class, the inheriting constructor is defined as deleted.
+ SetDeclDeleted(result.first->second.second, UsingLoc);
}
continue;
}
// OK, we're there, now add the constructor.
- // C++0x [class.inhctor]p8: [...] that would be performed by a
- // user-written inline constructor [...]
DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
- Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0),
+ Context, ClassDecl, UsingLoc, DNI, NewCtorType,
/*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true,
- // FIXME: Due to a defect in the standard, we treat inherited
- // constructors as constexpr even if that makes them ill-formed.
- /*Constexpr=*/BaseCtor->isConstexpr());
+ /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
NewCtor->setAccess(BaseCtor->getAccess());
+ // Build an unevaluated exception specification for this constructor.
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = NewCtor;
+ NewCtor->setType(Context.getFunctionType(Context.VoidTy,
+ ArgTypes.slice(0, Params),
+ EPI));
+
// Build up the parameter decls and add them.
SmallVector<ParmVarDecl *, 16> ParamDecls;
- for (unsigned i = 0; i < params; ++i) {
- ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor,
- UsingLoc, UsingLoc,
- /*IdentifierInfo=*/0,
- BaseCtorType->getArgType(i),
- /*TInfo=*/0, SC_None,
- SC_None, /*DefaultArg=*/0));
+ for (unsigned i = 0; i < Params; ++i) {
+ ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor,
+ UsingLoc, UsingLoc,
+ /*IdentifierInfo=*/0,
+ BaseCtorType->getArgType(i),
+ /*TInfo=*/0, SC_None,
+ /*DefaultArg=*/0);
+ PD->setScopeInfo(0, i);
+ PD->setImplicit();
+ ParamDecls.push_back(PD);
}
NewCtor->setParams(ParamDecls);
NewCtor->setInheritedConstructor(BaseCtor);
+ if (BaseCtor->isDeleted())
+ SetDeclDeleted(NewCtor, UsingLoc);
ClassDecl->addDecl(NewCtor);
result.first->second.second = NewCtor;
@@ -7240,6 +7839,35 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
}
+void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *Constructor) {
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(Constructor->getInheritedConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted());
+
+ SynthesizedFunctionScope Scope(*this, Constructor);
+ DiagnosticErrorTrap Trap(Diags);
+ if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_inhctor_synthesized_at)
+ << Context.getTagDeclType(ClassDecl);
+ Constructor->setInvalidDecl();
+ return;
+ }
+
+ SourceLocation Loc = Constructor->getLocation();
+ Constructor->setBody(new (Context) CompoundStmt(Loc));
+
+ Constructor->setUsed();
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(Constructor);
+ }
+}
+
+
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
CXXRecordDecl *ClassDecl = MD->getParent();
@@ -7290,6 +7918,11 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
+ assert(ClassDecl->needsImplicitDestructor());
+
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXDestructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
// Create the actual destructor declaration.
CanQualType ClassType
@@ -7305,13 +7938,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
Destructor->setImplicit();
- Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
// Build an exception specification pointing back at this destructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Destructor->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
+
+ AddOverriddenMethods(ClassDecl, Destructor);
+
+ // We don't need to use SpecialMemberIsTrivial here; triviality for
+ // destructors is easy to compute.
+ Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
+
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ SetDeclDeleted(Destructor, ClassLoc);
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
@@ -7321,11 +7964,6 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
- AddOverriddenMethods(ClassDecl, Destructor);
-
- if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
- Destructor->setDeletedAsWritten();
-
return Destructor;
}
@@ -7369,6 +8007,14 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
/// \brief Perform any semantic analysis which needs to be delayed until all
/// pending class member declarations have been parsed.
void Sema::ActOnFinishCXXMemberDecls() {
+ // If the context is an invalid C++ class, just suppress these checks.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
+ if (Record->isInvalidDecl()) {
+ DelayedDestructorExceptionSpecChecks.clear();
+ return;
+ }
+ }
+
// Perform any deferred checking of exception specifications for virtual
// destructors.
for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();
@@ -7385,7 +8031,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
CXXDestructorDecl *Destructor) {
- assert(getLangOpts().CPlusPlus0x &&
+ assert(getLangOpts().CPlusPlus11 &&
"adjusting dtor exception specs was introduced in c++11");
// C++11 [class.dtor]p3:
@@ -7403,7 +8049,9 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Destructor->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
@@ -7412,6 +8060,60 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
// needs to be done somewhere else.
}
+/// When generating a defaulted copy or move assignment operator, if a field
+/// should be copied with __builtin_memcpy rather than via explicit assignments,
+/// do so. This optimization only applies for arrays of scalars, and for arrays
+/// of class type where the selected copy/move-assignment operator is trivial.
+static StmtResult
+buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
+ Expr *To, Expr *From) {
+ // Compute the size of the memory buffer to be copied.
+ QualType SizeType = S.Context.getSizeType();
+ llvm::APInt Size(S.Context.getTypeSize(SizeType),
+ S.Context.getTypeSizeInChars(T).getQuantity());
+
+ // Take the address of the field references for "from" and "to". We
+ // directly construct UnaryOperators here because semantic analysis
+ // does not permit us to take the address of an xvalue.
+ From = new (S.Context) UnaryOperator(From, UO_AddrOf,
+ S.Context.getPointerType(From->getType()),
+ VK_RValue, OK_Ordinary, Loc);
+ To = new (S.Context) UnaryOperator(To, UO_AddrOf,
+ S.Context.getPointerType(To->getType()),
+ VK_RValue, OK_Ordinary, Loc);
+
+ const Type *E = T->getBaseElementTypeUnsafe();
+ bool NeedsCollectableMemCpy =
+ E->isRecordType() && E->getAs<RecordType>()->getDecl()->hasObjectMember();
+
+ // Create a reference to the __builtin_objc_memmove_collectable function
+ StringRef MemCpyName = NeedsCollectableMemCpy ?
+ "__builtin_objc_memmove_collectable" :
+ "__builtin_memcpy";
+ LookupResult R(S, &S.Context.Idents.get(MemCpyName), Loc,
+ Sema::LookupOrdinaryName);
+ S.LookupName(R, S.TUScope, true);
+
+ FunctionDecl *MemCpy = R.getAsSingle<FunctionDecl>();
+ if (!MemCpy)
+ // Something went horribly wrong earlier, and we will have complained
+ // about it.
+ return StmtError();
+
+ ExprResult MemCpyRef = S.BuildDeclRefExpr(MemCpy, S.Context.BuiltinFnTy,
+ VK_RValue, Loc, 0);
+ 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(),
+ Loc, CallArgs, Loc);
+
+ assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
+ return S.Owned(Call.takeAs<Stmt>());
+}
+
/// \brief Builds a statement that copies/moves the given entity from \p From to
/// \c To.
///
@@ -7437,13 +8139,14 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
///
/// \param Depth Internal parameter recording the depth of the recursion.
///
-/// \returns A statement or a loop that copies the expressions.
+/// \returns A statement or a loop that copies the expressions, or StmtResult(0)
+/// if a memcpy should be used instead.
static StmtResult
-BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
- Expr *To, Expr *From,
- bool CopyingBaseSubobject, bool Copying,
- unsigned Depth = 0) {
- // C++0x [class.copy]p28:
+buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
+ Expr *To, Expr *From,
+ bool CopyingBaseSubobject, bool Copying,
+ unsigned Depth = 0) {
+ // C++11 [class.copy]p28:
// Each subobject is assigned in the manner appropriate to its type:
//
// - if the subobject is of class type, as if by a call to operator= with
@@ -7451,32 +8154,41 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// subobject of x as a single function argument (as if by explicit
// qualification; that is, ignoring any possible virtual overriding
// functions in more derived classes);
+ //
+ // C++03 [class.copy]p13:
+ // - if the subobject is of class type, the copy assignment operator for
+ // the class is used (as if by explicit qualification; that is,
+ // ignoring any possible virtual overriding functions in more derived
+ // classes);
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
-
+
// Look for operator=.
DeclarationName Name
= S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName);
S.LookupQualifiedName(OpLookup, ClassDecl, false);
-
- // Filter out any result that isn't a copy/move-assignment operator.
- LookupResult::Filter F = OpLookup.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator() ||
- (!Copying && Method->isMoveAssignmentOperator()))
- continue;
- F.erase();
+ // Prior to C++11, filter out any result that isn't a copy/move-assignment
+ // operator.
+ if (!S.getLangOpts().CPlusPlus11) {
+ LookupResult::Filter F = OpLookup.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator() ||
+ (!Copying && Method->isMoveAssignmentOperator()))
+ continue;
+
+ F.erase();
+ }
+ F.done();
}
- F.done();
-
+
// Suppress the protected check (C++ [class.protected]) for each of the
- // assignment operators we found. This strange dance is required when
+ // assignment operators we found. This strange dance is required when
// we're assigning via a base classes's copy-assignment operator. To
- // ensure that we're getting the right base class subobject (without
+ // ensure that we're getting the right base class subobject (without
// ambiguities), we need to cast "this" to that subobject type; to
// ensure that we don't go through the virtual call mechanism, we need
// to qualify the operator= name with the base class (see below). However,
@@ -7491,20 +8203,20 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
L.setAccess(AS_public);
}
}
-
+
// Create the nested-name-specifier that will be used to qualify the
// reference to operator=; this is required to suppress the virtual
// call mechanism.
CXXScopeSpec SS;
const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr());
- SS.MakeTrivial(S.Context,
- NestedNameSpecifier::Create(S.Context, 0, false,
+ SS.MakeTrivial(S.Context,
+ NestedNameSpecifier::Create(S.Context, 0, false,
CanonicalT),
Loc);
-
+
// Create the reference to operator=.
ExprResult OpEqualRef
- = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS,
+ = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS,
/*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/0,
OpLookup,
@@ -7512,39 +8224,46 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
/*SuppressQualifierCheck=*/true);
if (OpEqualRef.isInvalid())
return StmtError();
-
+
// Build the call to the assignment operator.
- ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
+ ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
OpEqualRef.takeAs<Expr>(),
Loc, &From, 1, Loc);
if (Call.isInvalid())
return StmtError();
-
- return S.Owned(Call.takeAs<Stmt>());
+
+ // If we built a call to a trivial 'operator=' while copying an array,
+ // 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);
+
+ // Convert to an expression-statement, and clean up any produced
+ // temporaries.
+ return S.ActOnExprStmt(Call);
}
- // - if the subobject is of scalar type, the built-in assignment
+ // - if the subobject is of scalar type, the built-in assignment
// operator is used.
- const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
+ const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
if (!ArrayTy) {
ExprResult Assignment = S.CreateBuiltinBinOp(Loc, BO_Assign, To, From);
if (Assignment.isInvalid())
return StmtError();
-
- return S.Owned(Assignment.takeAs<Stmt>());
+ return S.ActOnExprStmt(Assignment);
}
-
- // - if the subobject is an array, each element is assigned, in the
+
+ // - if the subobject is an array, each element is assigned, in the
// manner appropriate to the element type;
-
+
// Construct a loop over the array bounds, e.g.,
//
// for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
//
// that will copy each of the array elements.
QualType SizeType = S.Context.getSizeType();
-
+
// Create the iteration variable.
IdentifierInfo *IterationVarName = 0;
{
@@ -7556,8 +8275,8 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
IterationVarName, SizeType,
S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None, SC_None);
-
+ SC_None);
+
// Initialize the iteration variable to zero.
llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
IterationVar->setInit(IntegerLiteral::Create(S.Context, Zero, SizeType, Loc));
@@ -7572,7 +8291,26 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// Create the DeclStmt that holds the iteration variable.
Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
-
+
+ // Subscript the "from" and "to" expressions with the iteration variable.
+ From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc,
+ IterationVarRefRVal,
+ Loc));
+ To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
+ IterationVarRefRVal,
+ Loc));
+ if (!Copying) // Cast to rvalue
+ From = CastForMoving(S, From);
+
+ // Build the copy/move for an individual element of the array.
+ StmtResult Copy =
+ buildSingleCopyAssignRecursively(S, Loc, ArrayTy->getElementType(),
+ To, From, CopyingBaseSubobject,
+ Copying, Depth + 1);
+ // Bail out if copying fails or if we determined that we should use memcpy.
+ if (Copy.isInvalid() || !Copy.get())
+ return Copy;
+
// Create the comparison against the array bound.
llvm::APInt Upper
= ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType));
@@ -7581,104 +8319,38 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
VK_RValue, OK_Ordinary, Loc, false);
-
+
// Create the pre-increment of the iteration variable.
Expr *Increment
= new (S.Context) UnaryOperator(IterationVarRef, UO_PreInc, SizeType,
VK_LValue, OK_Ordinary, Loc);
-
- // Subscript the "from" and "to" expressions with the iteration variable.
- From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc,
- IterationVarRefRVal,
- Loc));
- To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
- IterationVarRefRVal,
- Loc));
- if (!Copying) // Cast to rvalue
- From = CastForMoving(S, From);
- // Build the copy/move for an individual element of the array.
- StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(),
- To, From, CopyingBaseSubobject,
- Copying, Depth + 1);
- if (Copy.isInvalid())
- return StmtError();
-
// Construct the loop that copies all elements of this array.
return S.ActOnForStmt(Loc, Loc, InitStmt,
S.MakeFullExpr(Comparison),
- 0, S.MakeFullExpr(Increment),
+ 0, S.MakeFullDiscardedValueExpr(Increment),
Loc, Copy.take());
}
-/// Determine whether an implicit copy assignment operator for ClassDecl has a
-/// const argument.
-/// FIXME: It ought to be possible to store this on the record.
-static bool isImplicitCopyAssignmentArgConst(Sema &S,
- CXXRecordDecl *ClassDecl) {
- if (ClassDecl->isInvalidDecl())
- return true;
+static StmtResult
+buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
+ Expr *To, Expr *From,
+ bool CopyingBaseSubobject, bool Copying) {
+ // Maybe we should use a memcpy?
+ if (T->isArrayType() && !T.isConstQualified() && !T.isVolatileQualified() &&
+ T.isTriviallyCopyableType(S.Context))
+ return buildMemcpyForAssignmentOp(S, Loc, T, To, From);
- // C++ [class.copy]p10:
- // If the class definition does not explicitly declare a copy
- // assignment operator, one is declared implicitly.
- // The implicitly-defined copy assignment operator for a class X
- // will have the form
- //
- // X& X::operator=(const X&)
- //
- // if
- // -- each direct base class B of X has a copy assignment operator
- // whose parameter is of type const B&, const volatile B& or B,
- // and
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- // We'll handle this below
- if (S.getLangOpts().CPlusPlus0x && Base->isVirtual())
- continue;
+ StmtResult Result(buildSingleCopyAssignRecursively(S, Loc, T, To, From,
+ CopyingBaseSubobject,
+ Copying, 0));
- assert(!Base->getType()->isDependentType() &&
- "Cannot generate implicit members for class with dependent bases.");
- CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
- if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0))
- return false;
- }
+ // If we ended up picking a trivial assignment operator for an array of a
+ // non-trivially-copyable class type, just emit a memcpy.
+ if (!Result.isInvalid() && !Result.get())
+ return buildMemcpyForAssignmentOp(S, Loc, T, To, From);
- // In C++11, the above citation has "or virtual" added
- if (S.getLangOpts().CPlusPlus0x) {
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- assert(!Base->getType()->isDependentType() &&
- "Cannot generate implicit members for class with dependent bases.");
- CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
- if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
- false, 0))
- return false;
- }
- }
-
- // -- for all the nonstatic data members of X that are of a class
- // type M (or array thereof), each such class type has a copy
- // assignment operator whose parameter is of type const M&,
- // const volatile M& or M.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = S.Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl())
- if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,
- false, 0))
- return false;
- }
-
- // Otherwise, the implicitly declared copy assignment operator will
- // have the form
- //
- // X& X::operator=(X&)
-
- return true;
+ return Result;
}
Sema::ImplicitExceptionSpecification
@@ -7748,10 +8420,15 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules. Note that virtual bases are not taken into account
// for determining the argument type of the operator. Note also that
// operators taking an object instead of a reference are allowed.
+ assert(ClassDecl->needsImplicitCopyAssignment());
+
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyAssignment);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
- if (isImplicitCopyAssignmentArgConst(*this, ClassDecl))
+ if (ClassDecl->implicitCopyAssignmentHasConstParam())
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
@@ -7762,45 +8439,49 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *CopyAssignment
= CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0, /*isStatic=*/false,
- /*StorageClassAsWritten=*/SC_None,
+ /*TInfo=*/0,
+ /*StorageClass=*/SC_None,
/*isInline=*/true, /*isConstexpr=*/false,
SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
- CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyAssignment;
- CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+ CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassLoc, ClassLoc, /*Id=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
CopyAssignment->setParams(FromParam);
-
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(CopyAssignment, S, false);
- ClassDecl->addDecl(CopyAssignment);
-
+ AddOverriddenMethods(ClassDecl, CopyAssignment);
+
+ CopyAssignment->setTrivial(
+ ClassDecl->needsOverloadResolutionForCopyAssignment()
+ ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
+ : ClassDecl->hasTrivialCopyAssignment());
+
// C++0x [class.copy]p19:
// .... If the class definition does not explicitly declare a copy
// assignment operator, there is no user-declared move constructor, and
// there is no user-declared move assignment operator, a copy assignment
// operator is implicitly declared as defaulted.
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
- CopyAssignment->setDeletedAsWritten();
+ SetDeclDeleted(CopyAssignment, ClassLoc);
+
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(CopyAssignment, S, false);
+ ClassDecl->addDecl(CopyAssignment);
- AddOverriddenMethods(ClassDecl, CopyAssignment);
return CopyAssignment;
}
@@ -7892,7 +8573,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
VK_LValue, &BasePath);
// Build the copy.
- StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
+ StmtResult Copy = buildSingleCopyAssign(*this, Loc, BaseType,
To.get(), From,
/*CopyingBaseSubobject=*/true,
/*Copying=*/true);
@@ -7907,11 +8588,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Statements.push_back(Copy.takeAs<Expr>());
}
- // \brief Reference to the __builtin_memcpy function.
- Expr *BuiltinMemCpyRef = 0;
- // \brief Reference to the __builtin_objc_memmove_collectable function.
- Expr *CollectableMemCpyRef = 0;
-
// Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
@@ -7969,99 +8645,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
MemberLookup, 0);
assert(!From.isInvalid() && "Implicit field reference cannot fail");
assert(!To.isInvalid() && "Implicit field reference cannot fail");
-
- // If the field should be copied with __builtin_memcpy rather than via
- // explicit assignments, do so. This optimization only applies for arrays
- // of scalars and arrays of class type with trivial copy-assignment
- // operators.
- if (FieldType->isArrayType() && !FieldType.isVolatileQualified()
- && BaseType.hasTrivialAssignment(Context, /*Copying=*/true)) {
- // Compute the size of the memory buffer to be copied.
- QualType SizeType = Context.getSizeType();
- llvm::APInt Size(Context.getTypeSize(SizeType),
- Context.getTypeSizeInChars(BaseType).getQuantity());
- for (const ConstantArrayType *Array
- = Context.getAsConstantArrayType(FieldType);
- Array;
- Array = Context.getAsConstantArrayType(Array->getElementType())) {
- llvm::APInt ArraySize
- = Array->getSize().zextOrTrunc(Size.getBitWidth());
- Size *= ArraySize;
- }
-
- // Take the address of the field references for "from" and "to".
- From = CreateBuiltinUnaryOp(Loc, UO_AddrOf, From.get());
- To = CreateBuiltinUnaryOp(Loc, UO_AddrOf, To.get());
-
- bool NeedsCollectableMemCpy =
- (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember());
-
- if (NeedsCollectableMemCpy) {
- if (!CollectableMemCpyRef) {
- // Create a reference to the __builtin_objc_memmove_collectable function.
- LookupResult R(*this,
- &Context.Idents.get("__builtin_objc_memmove_collectable"),
- Loc, LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>();
- if (!CollectableMemCpy) {
- // Something went horribly wrong earlier, and we will have
- // complained about it.
- Invalid = true;
- continue;
- }
-
- CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(CollectableMemCpyRef && "Builtin reference cannot fail");
- }
- }
- // Create a reference to the __builtin_memcpy builtin function.
- else if (!BuiltinMemCpyRef) {
- LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
- LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
- if (!BuiltinMemCpy) {
- // Something went horribly wrong earlier, and we will have complained
- // about it.
- Invalid = true;
- continue;
- }
- BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
- }
-
- SmallVector<Expr*, 8> CallArgs;
- CallArgs.push_back(To.takeAs<Expr>());
- CallArgs.push_back(From.takeAs<Expr>());
- CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
- ExprResult Call = ExprError();
- if (NeedsCollectableMemCpy)
- Call = ActOnCallExpr(/*Scope=*/0,
- CollectableMemCpyRef,
- Loc, CallArgs,
- Loc);
- else
- Call = ActOnCallExpr(/*Scope=*/0,
- BuiltinMemCpyRef,
- Loc, CallArgs,
- Loc);
-
- assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
- Statements.push_back(Call.takeAs<Expr>());
- continue;
- }
-
// Build the copy of this field.
- StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType,
+ StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType,
To.get(), From.get(),
/*CopyingBaseSubobject=*/false,
/*Copying=*/true);
@@ -8188,10 +8774,7 @@ hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl *ClassDecl) {
if (BaseClass->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(BaseClass);
- // If the class has both a trivial move assignment and a non-trivial move
- // assignment, hasTrivialMoveAssignment() is false.
- if (BaseClass->hasDeclaredMoveAssignment() &&
- !BaseClass->hasTrivialMoveAssignment())
+ if (BaseClass->hasNonTrivialMoveAssignment())
return true;
}
@@ -8215,14 +8798,18 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
return true;
if (IsConstructor) {
+ // FIXME: Need this because otherwise hasMoveConstructor isn't guaranteed to
+ // give the right answer.
if (ClassDecl->needsImplicitMoveConstructor())
S.DeclareImplicitMoveConstructor(ClassDecl);
- return ClassDecl->hasDeclaredMoveConstructor();
+ return ClassDecl->hasMoveConstructor();
}
+ // FIXME: Need this because otherwise hasMoveAssignment isn't guaranteed to
+ // give the right answer.
if (ClassDecl->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(ClassDecl);
- return ClassDecl->hasDeclaredMoveAssignment();
+ return ClassDecl->hasMoveAssignment();
}
/// Determine whether all non-static data members and direct or virtual bases
@@ -8266,6 +8853,10 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveAssignment());
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
+
// [Checked after we build the declaration]
// - the move assignment operator would not be implicitly defined as
// deleted,
@@ -8296,32 +8887,34 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *MoveAssignment
= CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0, /*isStatic=*/false,
- /*StorageClassAsWritten=*/SC_None,
+ /*TInfo=*/0,
+ /*StorageClass=*/SC_None,
/*isInline=*/true,
/*isConstexpr=*/false,
SourceLocation());
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
- MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveAssignment;
- MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+ MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
ClassLoc, ClassLoc, /*Id=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
MoveAssignment->setParams(FromParam);
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+ AddOverriddenMethods(ClassDecl, MoveAssignment);
+
+ MoveAssignment->setTrivial(
+ ClassDecl->needsOverloadResolutionForMoveAssignment()
+ ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
+ : ClassDecl->hasTrivialMoveAssignment());
// C++0x [class.copy]p9:
// If the definition of a class X does not explicitly declare a move
@@ -8337,11 +8930,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
return 0;
}
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(MoveAssignment, S, false);
ClassDecl->addDecl(MoveAssignment);
- AddOverriddenMethods(ClassDecl, MoveAssignment);
return MoveAssignment;
}
@@ -8431,7 +9026,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
VK_LValue, &BasePath);
// Build the move.
- StmtResult Move = BuildSingleCopyAssign(*this, Loc, BaseType,
+ StmtResult Move = buildSingleCopyAssign(*this, Loc, BaseType,
To.get(), From,
/*CopyingBaseSubobject=*/true,
/*Copying=*/false);
@@ -8446,11 +9041,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Statements.push_back(Move.takeAs<Expr>());
}
- // \brief Reference to the __builtin_memcpy function.
- Expr *BuiltinMemCpyRef = 0;
- // \brief Reference to the __builtin_objc_memmove_collectable function.
- Expr *CollectableMemCpyRef = 0;
-
// Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
@@ -8513,104 +9103,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
"Member reference with rvalue base must be rvalue except for reference "
"members, which aren't allowed for move assignment.");
- // If the field should be copied with __builtin_memcpy rather than via
- // explicit assignments, do so. This optimization only applies for arrays
- // of scalars and arrays of class type with trivial move-assignment
- // operators.
- if (FieldType->isArrayType() && !FieldType.isVolatileQualified()
- && BaseType.hasTrivialAssignment(Context, /*Copying=*/false)) {
- // Compute the size of the memory buffer to be copied.
- QualType SizeType = Context.getSizeType();
- llvm::APInt Size(Context.getTypeSize(SizeType),
- Context.getTypeSizeInChars(BaseType).getQuantity());
- for (const ConstantArrayType *Array
- = Context.getAsConstantArrayType(FieldType);
- Array;
- Array = Context.getAsConstantArrayType(Array->getElementType())) {
- llvm::APInt ArraySize
- = Array->getSize().zextOrTrunc(Size.getBitWidth());
- Size *= ArraySize;
- }
-
- // Take the address of the field references for "from" and "to". We
- // directly construct UnaryOperators here because semantic analysis
- // does not permit us to take the address of an xvalue.
- From = new (Context) UnaryOperator(From.get(), UO_AddrOf,
- Context.getPointerType(From.get()->getType()),
- VK_RValue, OK_Ordinary, Loc);
- To = new (Context) UnaryOperator(To.get(), UO_AddrOf,
- Context.getPointerType(To.get()->getType()),
- VK_RValue, OK_Ordinary, Loc);
-
- bool NeedsCollectableMemCpy =
- (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember());
-
- if (NeedsCollectableMemCpy) {
- if (!CollectableMemCpyRef) {
- // Create a reference to the __builtin_objc_memmove_collectable function.
- LookupResult R(*this,
- &Context.Idents.get("__builtin_objc_memmove_collectable"),
- Loc, LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>();
- if (!CollectableMemCpy) {
- // Something went horribly wrong earlier, and we will have
- // complained about it.
- Invalid = true;
- continue;
- }
-
- CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(CollectableMemCpyRef && "Builtin reference cannot fail");
- }
- }
- // Create a reference to the __builtin_memcpy builtin function.
- else if (!BuiltinMemCpyRef) {
- LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
- LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
- if (!BuiltinMemCpy) {
- // Something went horribly wrong earlier, and we will have complained
- // about it.
- Invalid = true;
- continue;
- }
-
- BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
- }
-
- SmallVector<Expr*, 8> CallArgs;
- CallArgs.push_back(To.takeAs<Expr>());
- CallArgs.push_back(From.takeAs<Expr>());
- CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
- ExprResult Call = ExprError();
- if (NeedsCollectableMemCpy)
- Call = ActOnCallExpr(/*Scope=*/0,
- CollectableMemCpyRef,
- Loc, CallArgs,
- Loc);
- else
- Call = ActOnCallExpr(/*Scope=*/0,
- BuiltinMemCpyRef,
- Loc, CallArgs,
- Loc);
-
- assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
- Statements.push_back(Call.takeAs<Expr>());
- continue;
- }
-
// Build the move of this field.
- StmtResult Move = BuildSingleCopyAssign(*this, Loc, FieldType,
+ StmtResult Move = buildSingleCopyAssign(*this, Loc, FieldType,
To.get(), From.get(),
/*CopyingBaseSubobject=*/false,
/*Copying=*/false);
@@ -8620,7 +9114,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MoveAssignOperator->setInvalidDecl();
return;
}
-
+
// Success! Record the copy.
Statements.push_back(Move.takeAs<Stmt>());
}
@@ -8662,70 +9156,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
}
-/// Determine whether an implicit copy constructor for ClassDecl has a const
-/// argument.
-/// FIXME: It ought to be possible to store this on the record.
-static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) {
- if (ClassDecl->isInvalidDecl())
- return true;
-
- // C++ [class.copy]p5:
- // The implicitly-declared copy constructor for a class X will
- // have the form
- //
- // X::X(const X&)
- //
- // if
- // -- each direct or virtual base class B of X has a copy
- // constructor whose first parameter is of type const B& or
- // const volatile B&, and
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- // Virtual bases are handled below.
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- // FIXME: This lookup is wrong. If the copy ctor for a member or base is
- // ambiguous, we should still produce a constructor with a const-qualified
- // parameter.
- if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
- return false;
- }
-
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
- return false;
- }
-
- // -- for all the nonstatic data members of X that are of a
- // class type M (or array thereof), each such class type
- // has a copy constructor whose first parameter is of type
- // const M& or const volatile M&.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = S.Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const))
- return false;
- }
- }
-
- // Otherwise, the implicitly declared copy constructor will have
- // the form
- //
- // X::X(X&)
-
- return true;
-}
-
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {
CXXRecordDecl *ClassDecl = MD->getParent();
@@ -8786,10 +9216,15 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// C++ [class.copy]p4:
// If the class definition does not explicitly declare a copy
// constructor, one is declared implicitly.
+ assert(ClassDecl->needsImplicitCopyConstructor());
+
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyConstructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
- bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl);
+ bool Const = ClassDecl->implicitCopyConstructorHasConstParam();
if (Const)
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
@@ -8812,30 +9247,26 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Constexpr);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
- CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyConstructor;
CopyConstructor->setType(
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ Context.getFunctionType(Context.VoidTy, ArgType, EPI));
- // Note that we have declared this constructor.
- ++ASTContext::NumImplicitCopyConstructorsDeclared;
-
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassLoc, ClassLoc,
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
CopyConstructor->setParams(FromParam);
- if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(CopyConstructor, S, false);
- ClassDecl->addDecl(CopyConstructor);
+ CopyConstructor->setTrivial(
+ ClassDecl->needsOverloadResolutionForCopyConstructor()
+ ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
+ : ClassDecl->hasTrivialCopyConstructor());
// C++11 [class.copy]p8:
// ... If the class definition does not explicitly declare a copy
@@ -8843,7 +9274,14 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// user-declared move assignment operator, a copy constructor is implicitly
// declared as defaulted.
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
- CopyConstructor->setDeletedAsWritten();
+ SetDeclDeleted(CopyConstructor, ClassLoc);
+
+ // Note that we have declared this constructor.
+ ++ASTContext::NumImplicitCopyConstructorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(CopyConstructor, S, false);
+ ClassDecl->addDecl(CopyConstructor);
return CopyConstructor;
}
@@ -8862,7 +9300,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
SynthesizedFunctionScope Scope(*this, CopyConstructor);
DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
+ if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
@@ -8957,6 +9395,10 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveConstructor());
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
+
// [Checked after we build the declaration]
// - the move assignment operator would not be implicitly defined as
// deleted,
@@ -8991,24 +9433,27 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
Constexpr);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
- MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveConstructor;
MoveConstructor->setType(
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ Context.getFunctionType(Context.VoidTy, ArgType, EPI));
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
ClassLoc, ClassLoc,
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
MoveConstructor->setParams(FromParam);
+ MoveConstructor->setTrivial(
+ ClassDecl->needsOverloadResolutionForMoveConstructor()
+ ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
+ : ClassDecl->hasTrivialMoveConstructor());
+
// C++0x [class.copy]p9:
// If the definition of a class X does not explicitly declare a move
// constructor, one will be implicitly declared as defaulted if and only if:
@@ -9045,7 +9490,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
SynthesizedFunctionScope Scope(*this, MoveConstructor);
DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) ||
+ if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
@@ -9077,8 +9522,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
CXXMethodDecl *CallOperator
= cast<CXXMethodDecl>(
- *Lambda->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ Lambda->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced();
CallOperator->setUsed();
}
@@ -9100,12 +9545,12 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// Return the address of the __invoke function.
DeclarationName InvokeName = &Context.Idents.get("__invoke");
CXXMethodDecl *Invoke
- = cast<CXXMethodDecl>(*Lambda->lookup(InvokeName).first);
+ = cast<CXXMethodDecl>(Lambda->lookup(InvokeName).front());
Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
VK_LValue, Conv->getLocation()).take();
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
- Conv->setBody(new (Context) CompoundStmt(Context, &Return, 1,
+ Conv->setBody(new (Context) CompoundStmt(Context, Return,
Conv->getLocation(),
Conv->getLocation()));
@@ -9164,7 +9609,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Set the body of the conversion function.
Stmt *ReturnS = Return.take();
- Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1,
+ Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
Conv->getLocation(),
Conv->getLocation()));
@@ -9198,6 +9643,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
+ bool IsListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@@ -9221,7 +9667,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
- RequiresZeroInit, ConstructKind, ParenRange);
+ IsListInitialization, RequiresZeroInit,
+ ConstructKind, ParenRange);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -9231,39 +9678,19 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
+ bool IsListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, ExprArgs,
- HadMultipleCandidates, /*FIXME*/false,
- RequiresZeroInit,
+ HadMultipleCandidates,
+ IsListInitialization, RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange));
}
-bool Sema::InitializeVarWithConstructor(VarDecl *VD,
- CXXConstructorDecl *Constructor,
- MultiExprArg Exprs,
- bool HadMultipleCandidates) {
- // FIXME: Provide the correct paren SourceRange when available.
- ExprResult TempResult =
- BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor,
- Exprs, HadMultipleCandidates, false,
- CXXConstructExpr::CK_Complete, SourceRange());
- if (TempResult.isInvalid())
- return true;
-
- Expr *Temp = TempResult.takeAs<Expr>();
- CheckImplicitConversions(Temp, VD->getLocation());
- MarkFunctionReferenced(VD->getLocation(), Constructor);
- Temp = MaybeCreateExprWithCleanups(Temp);
- VD->setInit(Temp);
-
- return false;
-}
-
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
@@ -9301,7 +9728,8 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
SmallVectorImpl<Expr*> &ConvertedArgs,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ bool IsListInitialization) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
unsigned NumArgs = ArgsPtr.size();
Expr **Args = ArgsPtr.data();
@@ -9322,12 +9750,15 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
Proto, 0, Args, NumArgs, AllArgs,
- CallType, AllowExplicit);
+ CallType, AllowExplicit,
+ IsListInitialization);
ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
- CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
+ CheckConstructorCall(Constructor,
+ llvm::makeArrayRef<const Expr *>(AllArgs.data(),
+ AllArgs.size()),
Proto, Loc);
return Invalid;
@@ -9766,6 +10197,19 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
return LinkageSpec;
}
+Decl *Sema::ActOnEmptyDeclaration(Scope *S,
+ AttributeList *AttrList,
+ SourceLocation SemiLoc) {
+ Decl *ED = EmptyDecl::Create(Context, CurContext, SemiLoc);
+ // Attribute declarations appertain to empty declaration so we handle
+ // them here.
+ if (AttrList)
+ ProcessDeclAttributeList(S, ED, AttrList);
+
+ CurContext->addDecl(ED);
+ return ED;
+}
+
/// \brief Perform semantic analysis for the variable declaration that
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
@@ -9833,7 +10277,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
}
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name,
- ExDeclType, TInfo, SC_None, SC_None);
+ ExDeclType, TInfo, SC_None);
ExDecl->setExceptionVariable(true);
// In ARC, infer 'retaining' for variables of retainable type.
@@ -9842,6 +10286,9 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
+ // Insulate this from anything else we might currently be parsing.
+ EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+
// C++ [except.handle]p16:
// The object declared in an exception-declaration or, if the
// exception-declaration does not specify a name, a temporary (12.2) is
@@ -9893,8 +10340,8 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
bool Invalid = D.isInvalidType();
// Check for unexpanded parameter packs.
- if (TInfo && DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
- UPPC_ExceptionType)) {
+ if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
+ UPPC_ExceptionType)) {
TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
D.getIdentifierLoc());
Invalid = true;
@@ -9970,7 +10417,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Failed = true;
if (!Failed && !Cond) {
- llvm::SmallString<256> MsgBuffer;
+ SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
AssertMessage->printPretty(Msg, 0, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
@@ -10007,47 +10454,49 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
// Do not complain about the form of friend template types during
// template instantiation; we will already have complained when the
// template was declared.
- } else if (!T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
+ } else {
+ if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
- std::string InsertionText = std::string(" ") + RD->getKindName();
+ std::string InsertionText = std::string(" ") + RD->getKindName();
- Diag(TypeRange.getBegin(),
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_unelaborated_friend_type :
- diag::ext_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
- << T
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
- InsertionText);
- } else {
+ Diag(TypeRange.getBegin(),
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_unelaborated_friend_type :
+ diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc,
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_nonclass_type_friend :
+ diag::ext_nonclass_type_friend)
+ << T
+ << TypeRange;
+ }
+ } else if (T->getAs<EnumType>()) {
Diag(FriendLoc,
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_nonclass_type_friend :
- diag::ext_nonclass_type_friend)
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_enum_friend :
+ diag::ext_enum_friend)
<< T
<< TypeRange;
}
- } else if (T->getAs<EnumType>()) {
- Diag(FriendLoc,
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_enum_friend :
- diag::ext_enum_friend)
- << T
- << TypeRange;
- }
- // C++11 [class.friend]p3:
- // A friend declaration that does not declare a function shall have one
- // of the following forms:
- // friend elaborated-type-specifier ;
- // friend simple-type-specifier ;
- // friend typename-specifier ;
- if (getLangOpts().CPlusPlus0x && LocStart != FriendLoc)
- Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T;
+ // C++11 [class.friend]p3:
+ // A friend declaration that does not declare a function shall have one
+ // of the following forms:
+ // friend elaborated-type-specifier ;
+ // friend simple-type-specifier ;
+ // friend typename-specifier ;
+ if (getLangOpts().CPlusPlus11 && LocStart != FriendLoc)
+ Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T;
+ }
// If the type specifier in a friend declaration designates a (possibly
// cv-qualified) class type, that class is declared as a friend; otherwise,
@@ -10060,7 +10509,8 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
AttributeList *Attr,
MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
@@ -10132,19 +10582,20 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
- DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ DependentNameTypeLoc TL =
+ TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(NameLoc);
} else {
- ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>();
TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(QualifierLoc);
- cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc);
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(NameLoc);
}
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
- TSI, FriendLoc);
+ TSI, FriendLoc, TempParamLists);
Friend->setAccess(AS_public);
CurContext->addDecl(Friend);
return Friend;
@@ -10160,13 +10611,13 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(SS.getWithLocInContext(Context));
TL.setNameLoc(NameLoc);
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
- TSI, FriendLoc);
+ TSI, FriendLoc, TempParamLists);
Friend->setAccess(AS_public);
Friend->setUnsupportedFriend(true);
CurContext->addDecl(Friend);
@@ -10260,8 +10711,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
return D;
}
-Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParams) {
+NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParams) {
const DeclSpec &DS = D.getDeclSpec();
assert(DS.isFriendSpecified());
@@ -10372,17 +10823,6 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
DC = DC->getParent();
}
- // C++ [class.friend]p1: A friend of a class is a function or
- // class that is not a member of the class . . .
- // C++11 changes this for both friend types and functions.
- // Most C++ 98 compilers do seem to give an error here, so
- // we do, too.
- if (!Previous.empty() && DC->Equals(CurContext))
- Diag(DS.getFriendSpecLoc(),
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_friend_is_member :
- diag::err_friend_is_member);
-
DCScope = getScopeForDeclContext(S, DC);
// C++ [class.friend]p6:
@@ -10427,7 +10867,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// class that is not a member of the class . . .
if (DC->Equals(CurContext))
Diag(DS.getFriendSpecLoc(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_is_member :
diag::err_friend_is_member);
@@ -10534,11 +10974,12 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
AdjustDeclIfTemplate(Dcl);
- FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl);
+ FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Dcl);
if (!Fn) {
Diag(DelLoc, diag::err_deleted_non_function);
return;
}
+
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
// Don't consider the implicit declaration we generate for explicit
// specializations. FIXME: Do not generate these implicit declarations.
@@ -10549,41 +10990,34 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
}
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
+ Fn = Fn->getCanonicalDecl();
}
- Fn->setDeletedAsWritten();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
- if (!MD)
+ if (Fn->isDeleted())
return;
- // A deleted special member function is trivial if the corresponding
- // implicitly-declared function would have been.
- switch (getSpecialMember(MD)) {
- case CXXInvalid:
- break;
- case CXXDefaultConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor());
- break;
- case CXXCopyConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor());
- break;
- case CXXMoveConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor());
- break;
- case CXXCopyAssignment:
- MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
- break;
- case CXXMoveAssignment:
- MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
- break;
- case CXXDestructor:
- MD->setTrivial(MD->getParent()->hasTrivialDestructor());
- break;
+ // See if we're deleting a function which is already known to override a
+ // non-deleted virtual function.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
+ bool IssuedDiagnostic = false;
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I) {
+ if (!(*MD->begin_overridden_methods())->isDeleted()) {
+ if (!IssuedDiagnostic) {
+ Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName();
+ IssuedDiagnostic = true;
+ }
+ Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+ }
+ }
}
+
+ Fn->setDeletedAsWritten();
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
+ CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Dcl);
if (MD) {
if (MD->getParent()->isDependentType()) {
@@ -10609,11 +11043,19 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// on it.
Pattern->isDefined(Primary);
+ // If the method was defaulted on its first declaration, we will have
+ // already performed the checking in CheckCompletedCXXClass. Such a
+ // declaration doesn't trigger an implicit definition.
if (Primary == Primary->getCanonicalDecl())
return;
CheckExplicitlyDefaultedSpecialMember(MD);
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(DefaultLoc,
+ MD->getType()->castAs<FunctionProtoType>());
+
switch (Member) {
case CXXDefaultConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
@@ -10683,6 +11125,40 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}
+bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old) {
+ const FunctionType *NewFT = New->getType()->getAs<FunctionType>();
+ const FunctionType *OldFT = Old->getType()->getAs<FunctionType>();
+
+ CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();
+
+ // If the calling conventions match, everything is fine
+ if (NewCC == OldCC)
+ return false;
+
+ // If either of the calling conventions are set to "default", we need to pick
+ // something more sensible based on the target. This supports code where the
+ // one method explicitly sets thiscall, and another has no explicit calling
+ // convention.
+ CallingConv Default =
+ Context.getTargetInfo().getDefaultCallingConv(TargetInfo::CCMT_Member);
+ if (NewCC == CC_Default)
+ NewCC = Default;
+ if (OldCC == CC_Default)
+ OldCC = Default;
+
+ // If the calling conventions still don't match, then report the error
+ if (NewCC != OldCC) {
+ Diag(New->getLocation(),
+ diag::err_conflicting_overriding_cc_attributes)
+ << New->getDeclName() << New->getType() << Old->getType();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
+ return false;
+}
+
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
@@ -10949,7 +11425,7 @@ bool Sema::DefineUsedVTables() {
// If this class has a key function, but that key function is
// defined in another translation unit, we don't need to emit the
// vtable even though we're using it.
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class);
+ const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(Class);
if (KeyFunction && !KeyFunction->hasBody()) {
switch (KeyFunction->getTemplateSpecializationKind()) {
case TSK_Undeclared:
@@ -11006,7 +11482,7 @@ bool Sema::DefineUsedVTables() {
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
// Optionally warn if we're emitting a weak vtable.
- if (Class->getLinkage() == ExternalLinkage &&
+ if (Class->hasExternalLinkage() &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
const FunctionDecl *KeyFunctionDef = 0;
if (!KeyFunction ||
@@ -11228,7 +11704,7 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
return false;
TypeLoc TL = TSInfo->getTypeLoc();
- FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
@@ -11239,12 +11715,12 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
// within a static member function as they are within a non-static member
// function). [ Note: this is because declaration matching does not occur
// until the complete declarator is known. - end note ]
- const FunctionProtoType *Proto = ProtoTL->getTypePtr();
+ const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
// If the return type came after the cv-qualifier-seq, check it now.
if (Proto->hasTrailingReturn() &&
- !Finder.TraverseTypeLoc(ProtoTL->getResultLoc()))
+ !Finder.TraverseTypeLoc(ProtoTL.getResultLoc()))
return true;
// Check the exception specification.
@@ -11260,11 +11736,11 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
return false;
TypeLoc TL = TSInfo->getTypeLoc();
- FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
- const FunctionProtoType *Proto = ProtoTL->getTypePtr();
+ const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
switch (Proto->getExceptionSpecType()) {
@@ -11354,7 +11830,7 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
ArrayRef<ParsedType> DynamicExceptions,
ArrayRef<SourceRange> DynamicExceptionRanges,
Expr *NoexceptExpr,
- llvm::SmallVectorImpl<QualType> &Exceptions,
+ SmallVectorImpl<QualType> &Exceptions,
FunctionProtoType::ExtProtoInfo &EPI) {
Exceptions.clear();
EPI.ExceptionSpecType = EST;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index c4e91e85015f..5c26d7ff8e03 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Sema/DeclSpec.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
@@ -109,8 +109,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
}
void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
- const ObjCMethodDecl *Overridden,
- bool IsImplementation) {
+ const ObjCMethodDecl *Overridden) {
if (Overridden->hasRelatedResultType() &&
!NewMethod->hasRelatedResultType()) {
// This can only happen when the method follows a naming convention that
@@ -152,7 +151,8 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
if (ObjCMethodFamily Family = Overridden->getMethodFamily())
Diag(Overridden->getLocation(),
- diag::note_related_result_type_overridden_family)
+ diag::note_related_result_type_family)
+ << /*overridden method*/ 0
<< Family;
else
Diag(Overridden->getLocation(),
@@ -193,7 +193,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
/// \brief Check a method declaration for compatibility with the Objective-C
/// ARC conventions.
-static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
ObjCMethodFamily family = method->getMethodFamily();
switch (family) {
case OMF_None:
@@ -207,17 +207,17 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
return false;
case OMF_dealloc:
- if (!S.Context.hasSameType(method->getResultType(), S.Context.VoidTy)) {
+ if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) {
SourceRange ResultTypeRange;
if (const TypeSourceInfo *ResultTypeInfo
= method->getResultTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
if (ResultTypeRange.isInvalid())
- S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getResultType()
<< FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)");
else
- S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getResultType()
<< FixItHint::CreateReplacement(ResultTypeRange, "void");
return true;
@@ -226,11 +226,11 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
case OMF_init:
// If the method doesn't obey the init rules, don't bother annotating it.
- if (S.checkInitMethod(method, QualType()))
+ if (checkInitMethod(method, QualType()))
return true;
- method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
- S.Context));
+ method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(),
+ Context));
// Don't add a second copy of this attribute, but otherwise don't
// let it be suppressed.
@@ -249,8 +249,8 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
break;
}
- method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
- S.Context));
+ method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(),
+ Context));
return false;
}
@@ -373,16 +373,29 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
ObjCMethodDecl *IMD =
IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod());
- if (IMD)
- DiagnoseObjCImplementedDeprecations(*this,
+ if (IMD) {
+ ObjCImplDecl *ImplDeclOfMethodDef =
+ dyn_cast<ObjCImplDecl>(MDecl->getDeclContext());
+ ObjCContainerDecl *ContDeclOfMethodDecl =
+ dyn_cast<ObjCContainerDecl>(IMD->getDeclContext());
+ ObjCImplDecl *ImplDeclOfMethodDecl = 0;
+ if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ContDeclOfMethodDecl))
+ ImplDeclOfMethodDecl = OID->getImplementation();
+ else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContDeclOfMethodDecl))
+ 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)
+ DiagnoseObjCImplementedDeprecations(*this,
dyn_cast<NamedDecl>(IMD),
MDecl->getLocation(), 0);
+ }
// 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.
// Only do this if the current class actually has a superclass.
- if (IC->getSuperClass()) {
+ if (const ObjCInterfaceDecl *SuperClass = IC->getSuperClass()) {
ObjCMethodFamily Family = MDecl->getMethodFamily();
if (Family == OMF_dealloc) {
if (!(getLangOpts().ObjCAutoRefCount ||
@@ -395,8 +408,8 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
} else {
const ObjCMethodDecl *SuperMethod =
- IC->getSuperClass()->lookupMethod(MDecl->getSelector(),
- MDecl->isInstanceMethod());
+ SuperClass->lookupMethod(MDecl->getSelector(),
+ MDecl->isInstanceMethod());
getCurFunction()->ObjCShouldCallSuper =
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
}
@@ -508,8 +521,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+ // This handles the following case:
+ // @interface NewI @end
+ // typedef NewI DeprI __attribute__((deprecated("blah")))
+ // @interface SI : DeprI /* warn here */ @end
+ (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc);
+ }
}
}
@@ -731,7 +750,9 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
// If this is a forward declaration and we are supposed to warn in this
// case, do it.
- if (WarnOnDeclarations && !PDecl->hasDefinition())
+ // FIXME: Recover nicely in the hidden case.
+ if (WarnOnDeclarations &&
+ (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()))
Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
<< ProtocolId[i].first;
Protocols.push_back(PDecl);
@@ -837,16 +858,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
if (CategoryName) {
/// Check for duplicate interface declaration for this category
- ObjCCategoryDecl *CDeclChain;
- for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
- CDeclChain = CDeclChain->getNextClassCategory()) {
- if (CDeclChain->getIdentifier() == CategoryName) {
- // Class extensions can be declared multiple times.
- Diag(CategoryLoc, diag::warn_dup_category_def)
- << ClassName << CategoryName;
- Diag(CDeclChain->getLocation(), diag::note_previous_definition);
- break;
- }
+ if (ObjCCategoryDecl *Previous
+ = IDecl->FindCategoryDeclaration(CategoryName)) {
+ // Class extensions can be declared multiple times, categories cannot.
+ Diag(CategoryLoc, diag::warn_dup_category_def)
+ << ClassName << CategoryName;
+ Diag(Previous->getLocation(), diag::note_previous_definition);
}
}
@@ -1155,16 +1172,29 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID) {
// No point warning no definition of method which is 'unavailable'.
- if (method->hasAttr<UnavailableAttr>())
+ switch (method->getAvailability()) {
+ case AR_Available:
+ case AR_Deprecated:
+ break;
+
+ // Don't warn about unavailable or not-yet-introduced methods.
+ case AR_NotYetIntroduced:
+ case AR_Unavailable:
return;
- if (!IncompleteImpl) {
- Diag(ImpLoc, diag::warn_incomplete_impl);
- IncompleteImpl = true;
}
- if (DiagID == diag::warn_unimplemented_protocol_method)
- Diag(ImpLoc, DiagID) << method->getDeclName();
- else
- Diag(method->getLocation(), DiagID) << method->getDeclName();
+
+ // FIXME: For now ignore 'IncompleteImpl'.
+ // Previously we grouped all unimplemented methods under a single
+ // 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();
+
+ // Issue a note to the original declaration.
+ SourceLocation MethodLoc = method->getLocStart();
+ if (MethodLoc.isValid())
+ Diag(MethodLoc, diag::note_method_declared_at) << method;
}
/// Determines if type B can be substituted for type A. Returns true if we can
@@ -1571,6 +1601,11 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy"));
}
+ // If this is a forward protocol declaration, get its definition.
+ if (!PDecl->isThisDeclarationADefinition() &&
+ PDecl->getDefinition())
+ PDecl = PDecl->getDefinition();
+
// If a method lookup fails locally we still need to look and see if
// the method was implemented by a base class or an inherited
// protocol. This lookup is slow, but occurs rarely in correct code
@@ -1603,8 +1638,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
!= DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at)
- << method->getDeclName();
Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
<< PDecl->getDeclName();
}
@@ -1626,8 +1659,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at)
- << method->getDeclName();
Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
PDecl->getDeclName();
}
@@ -1662,7 +1693,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
- diag::note_undef_method_impl);
+ diag::warn_undef_method_impl);
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
@@ -1692,7 +1723,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
- diag::note_undef_method_impl);
+ diag::warn_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
@@ -1712,24 +1743,27 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// when checking that methods in implementation match their declaration,
// i.e. when WarnCategoryMethodImpl is false, check declarations in class
// extension; as well as those in categories.
- if (!WarnCategoryMethodImpl)
- for (const ObjCCategoryDecl *CDeclChain = I->getCategoryList();
- CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
+ if (!WarnCategoryMethodImpl) {
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = I->visible_categories_begin(),
+ CatEnd = I->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(CDeclChain),
- IncompleteImpl, false,
+ IMPDecl, *Cat, IncompleteImpl, false,
WarnCategoryMethodImpl);
- else
+ }
+ } else {
// Also methods in class extensions need be looked at next.
- for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = I->visible_extensions_begin(),
+ ExtEnd = I->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- 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(),
@@ -1832,11 +1866,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, I);
// Check class extensions (unnamed categories)
- for (const ObjCCategoryDecl *Categories = I->getFirstClassExtension();
- Categories; Categories = Categories->getNextClassExtension())
- ImplMethodsVsClassMethods(S, IMPDecl,
- const_cast<ObjCCategoryDecl*>(Categories),
- IncompleteImpl);
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = I->visible_extensions_begin(),
+ ExtEnd = I->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ 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.
@@ -2017,6 +2052,10 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
left->getResultType(), right->getResultType()))
return false;
+ // If either is hidden, it is not considered to match.
+ if (left->isHidden() || right->isHidden())
+ return false;
+
if (getLangOpts().ObjCAutoRefCount &&
(left->hasAttr<NSReturnsRetainedAttr>()
!= right->hasAttr<NSReturnsRetainedAttr>() ||
@@ -2141,61 +2180,79 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
if (Pos == MethodPool.end())
return 0;
+ // Gather the non-hidden methods.
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
+ for (ObjCMethodList *M = &MethList; M; M = M->Next) {
+ if (M->Method && !M->Method->isHidden()) {
+ // If we're not supposed to warn about mismatches, we're done.
+ if (!warn)
+ return M->Method;
+
+ Methods.push_back(M->Method);
+ }
+ }
- if (warn && MethList.Method && MethList.Next) {
- bool issueDiagnostic = false, issueError = false;
-
- // We support a warning which complains about *any* difference in
- // method signature.
- bool strictSelectorMatch =
- (receiverIdOrClass && warn &&
- (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
- R.getBegin()) !=
- DiagnosticsEngine::Ignored));
- if (strictSelectorMatch)
- for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
- MMS_strict)) {
- issueDiagnostic = true;
- break;
- }
+ // 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;
+
+ if (Methods.size() == 1)
+ return Methods[0];
+
+ // We found multiple methods, so we may have to complain.
+ bool issueDiagnostic = false, issueError = false;
+
+ // We support a warning which complains about *any* difference in
+ // method signature.
+ bool strictSelectorMatch =
+ (receiverIdOrClass && warn &&
+ (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+ R.getBegin())
+ != DiagnosticsEngine::Ignored));
+ if (strictSelectorMatch) {
+ for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+ if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) {
+ issueDiagnostic = true;
+ break;
}
+ }
+ }
- // If we didn't see any strict differences, we won't see any loose
- // differences. In ARC, however, we also need to check for loose
- // mismatches, because most of them are errors.
- if (!strictSelectorMatch ||
- (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
- for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ in type mismatch.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
- MMS_loose) &&
- !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
- issueDiagnostic = true;
- if (getLangOpts().ObjCAutoRefCount)
- issueError = true;
- break;
- }
+ // If we didn't see any strict differences, we won't see any loose
+ // differences. In ARC, however, we also need to check for loose
+ // mismatches, because most of them are errors.
+ if (!strictSelectorMatch ||
+ (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
+ for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+ // This checks if the methods differ in type mismatch.
+ if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_loose) &&
+ !isAcceptableMethodMismatch(Methods[0], Methods[I])) {
+ issueDiagnostic = true;
+ if (getLangOpts().ObjCAutoRefCount)
+ issueError = true;
+ break;
}
+ }
- if (issueDiagnostic) {
- if (issueError)
- Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
- else if (strictSelectorMatch)
- Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
- else
- Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+ if (issueDiagnostic) {
+ if (issueError)
+ Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+ else if (strictSelectorMatch)
+ Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
+ else
+ Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(),
- issueError ? diag::note_possibility : diag::note_using)
- << MethList.Method->getSourceRange();
- for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
- Diag(Next->Method->getLocStart(), diag::note_also_found)
- << Next->Method->getSourceRange();
- }
+ Diag(Methods[0]->getLocStart(),
+ issueError ? diag::note_possibility : diag::note_using)
+ << Methods[0]->getSourceRange();
+ for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+ Diag(Methods[I]->getLocStart(), diag::note_also_found)
+ << Methods[I]->getSourceRange();
}
- return MethList.Method;
+ }
+ return Methods[0];
}
ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
@@ -2334,18 +2391,13 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
}
}
- if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- // Compares properties declared in this class to those of its
- // super class.
- ComparePropertiesInBaseAndSuper(I);
- CompareProperties(I, I);
+ if (isa<ObjCInterfaceDecl>(ClassDecl)) {
+ // Nothing to do here.
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
// Categories are used to extend the class by declaring new methods.
// By the same token, they are also used to add new properties. No
// need to compare the added property to those in the class.
- // Compare protocol properties with those in category
- CompareProperties(C, C);
if (C->IsClassExtension()) {
ObjCInterfaceDecl *CCPrimary = C->getClassInterface();
DiagnoseClassExtensionDupMethods(C, CCPrimary);
@@ -2370,11 +2422,12 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
// 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 (const ObjCCategoryDecl *ClsExtDecl =
- IDecl->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- for (ObjCContainerDecl::prop_iterator I = ClsExtDecl->prop_begin(),
- E = ClsExtDecl->prop_end(); I != E; ++I) {
+ 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;
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
@@ -2382,18 +2435,19 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
if (PIDecl->getPropertyImplementation()
== ObjCPropertyImplDecl::Dynamic)
continue;
-
- for (const ObjCCategoryDecl *CExtDecl =
- IDecl->getFirstClassExtension();
- CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) {
- if (ObjCMethodDecl *GetterMethod =
- CExtDecl->getInstanceMethod(Property->getGetterName()))
+
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = IDecl->visible_extensions_begin(),
+ ExtEnd = IDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCMethodDecl *GetterMethod
+ = Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
- if (ObjCMethodDecl *SetterMethod =
- CExtDecl->getInstanceMethod(Property->getSetterName()))
+ if (ObjCMethodDecl *SetterMethod
+ = Ext->getInstanceMethod(Property->getSetterName()))
SetterMethod->setPropertyAccessor(true);
- }
+ }
}
}
ImplMethodsVsClassMethods(S, IC, IDecl);
@@ -2442,12 +2496,9 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
// Find category interface decl and then check that all methods declared
// in this interface are implemented in the category @implementation.
if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) {
- for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
- Categories; Categories = Categories->getNextClassCategory()) {
- if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
- ImplMethodsVsClassMethods(S, CatImplClass, Categories);
- break;
- }
+ if (ObjCCategoryDecl *Cat
+ = IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier())) {
+ ImplMethodsVsClassMethods(S, CatImplClass, Cat);
}
}
}
@@ -2682,9 +2733,12 @@ private:
return;
// - categories,
- for (ObjCCategoryDecl *category = iface->getCategoryList();
- category; category = category->getNextClassCategory())
- search(category);
+ for (ObjCInterfaceDecl::known_categories_iterator
+ cat = iface->known_categories_begin(),
+ catEnd = iface->known_categories_end();
+ cat != catEnd; ++cat) {
+ search(*cat);
+ }
// - the super class, and
if (ObjCInterfaceDecl *super = iface->getSuperClass())
@@ -2711,7 +2765,8 @@ private:
void search(ObjCContainerDecl *container) {
// Check for a method in this container which matches this selector.
ObjCMethodDecl *meth = container->getMethod(Method->getSelector(),
- Method->isInstanceMethod());
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true);
// If we find one, record it and bail out.
if (meth) {
@@ -2858,8 +2913,6 @@ Decl *Sema::ActOnMethodDeclaration(
DI = 0;
} else {
ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI);
- // Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = Context.getAdjustedParameterType(ArgType);
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
@@ -2883,7 +2936,7 @@ Decl *Sema::ActOnMethodDeclaration(
ParmVarDecl* Param = CheckParameter(ObjCMethod, StartLoc,
ArgInfo[i].NameLoc, ArgInfo[i].Name,
- ArgType, DI, SC_None, SC_None);
+ ArgType, DI, SC_None);
Param->setObjCMethodScopeInfo(i);
@@ -2985,7 +3038,7 @@ Decl *Sema::ActOnMethodDeclaration(
bool ARCError = false;
if (getLangOpts().ObjCAutoRefCount)
- ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+ ARCError = CheckARCMethodDecl(ObjCMethod);
// Infer the related result type when possible.
if (!ARCError && RTC == Sema::RTC_Compatible &&
@@ -3114,7 +3167,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
}
VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id,
- T, TInfo, SC_None, SC_None);
+ T, TInfo, SC_None);
New->setExceptionVariable(true);
// In ARC, infer 'retaining' for variables of retainable type.
@@ -3142,7 +3195,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
D.getMutableDeclSpec().ClearStorageClassSpecs();
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
// Check that there are no default arguments inside the type of this
// exception object (C++ only).
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index e1f4888d632f..26c3d354c7af 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -16,9 +16,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.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"
@@ -38,43 +38,55 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T)
/// CheckSpecifiedExceptionType - Check if the given type is valid in an
/// exception specification. Incomplete types, or pointers to incomplete types
/// other than void are not allowed.
-bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
-
- // This check (and the similar one below) deals with issue 437, that changes
- // C++ 9.2p2 this way:
- // Within the class member-specification, the class is regarded as complete
- // within function bodies, default arguments, exception-specifications, and
- // constructor ctor-initializers (including such things in nested classes).
- if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
- return false;
-
- // C++ 15.4p2: A type denoted in an exception-specification shall not denote
- // an incomplete type.
- if (RequireCompleteType(Range.getBegin(), T,
- diag::err_incomplete_in_exception_spec,
- /*direct*/0, Range))
- return true;
-
- // C++ 15.4p2: A type denoted in an exception-specification shall not denote
- // an incomplete type a pointer or reference to an incomplete type, other
- // than (cv) void*.
- int kind;
- if (const PointerType* IT = T->getAs<PointerType>()) {
- T = IT->getPointeeType();
- kind = 1;
- } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
- T = IT->getPointeeType();
- kind = 2;
- } else
- return false;
+///
+/// \param[in,out] T The exception type. This will be decayed to a pointer type
+/// when the input is an array or a function type.
+bool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) {
+ // C++11 [except.spec]p2:
+ // A type cv T, "array of T", or "function returning T" denoted
+ // in an exception-specification is adjusted to type T, "pointer to T", or
+ // "pointer to function returning T", respectively.
+ //
+ // We also apply this rule in C++98.
+ if (T->isArrayType())
+ T = Context.getArrayDecayedType(T);
+ else if (T->isFunctionType())
+ T = Context.getPointerType(T);
+
+ int Kind = 0;
+ QualType PointeeT = T;
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ PointeeT = PT->getPointeeType();
+ Kind = 1;
+
+ // cv void* is explicitly permitted, despite being a pointer to an
+ // incomplete type.
+ if (PointeeT->isVoidType())
+ return false;
+ } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ PointeeT = RT->getPointeeType();
+ Kind = 2;
+
+ if (RT->isRValueReferenceType()) {
+ // C++11 [except.spec]p2:
+ // A type denoted in an exception-specification shall not denote [...]
+ // an rvalue reference type.
+ Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
+ << T << Range;
+ return true;
+ }
+ }
- // Again as before
- if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
- return false;
-
- if (!T->isVoidType() &&
- RequireCompleteType(Range.getBegin(), T,
- diag::err_incomplete_in_exception_spec, kind, Range))
+ // C++11 [except.spec]p2:
+ // A type denoted in an exception-specification shall not denote an
+ // incomplete type other than a class currently being defined [...].
+ // A type denoted in an exception-specification shall not denote a
+ // pointer or reference to an incomplete type, other than (cv) void* or a
+ // pointer or reference to a class currently being defined.
+ if (!(PointeeT->isRecordType() &&
+ PointeeT->getAs<RecordType>()->isBeingDefined()) &&
+ RequireCompleteType(Range.getBegin(), PointeeT,
+ diag::err_incomplete_in_exception_spec, Kind, Range))
return true;
return false;
@@ -112,7 +124,7 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceFPT;
// Compute or instantiate the exception specification now.
- if (FPT->getExceptionSpecType() == EST_Unevaluated)
+ if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
else
InstantiateExceptionSpec(Loc, SourceDecl);
@@ -159,7 +171,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// If a declaration of a function has an implicit
// exception-specification, other declarations of the function shall
// not specify an exception-specification.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
<< hasImplicitExceptionSpec(Old);
@@ -191,10 +203,11 @@ 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->arg_type_begin(),
- NewProto->getNumArgs(),
- EPI);
+ QualType NewType =
+ Context.getFunctionType(NewProto->getResultType(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
+ EPI);
New->setType(NewType);
return false;
}
@@ -215,10 +228,11 @@ 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->arg_type_begin(),
- NewProto->getNumArgs(),
- EPI);
+ QualType NewType =
+ Context.getFunctionType(NewProto->getResultType(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
+ EPI);
New->setType(NewType);
// If exceptions are disabled, suppress the warning about missing
@@ -282,8 +296,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
SourceLocation FixItLoc;
if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
- if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL))
- FixItLoc = PP.getLocForEndOfToken(FTLoc->getLocalRangeEnd());
+ if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
+ FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
}
if (FixItLoc.isInvalid())
@@ -442,7 +456,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// As a special compatibility feature, under C++0x we accept no spec and
// 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().CPlusPlus0x && IsOperatorNew) {
+ if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
const FunctionProtoType *WithExceptions = 0;
if (OldEST == EST_None && NewEST == EST_Dynamic)
WithExceptions = New;
@@ -773,7 +787,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- if (getLangOpts().CPlusPlus0x && isa<CXXDestructorDecl>(New)) {
+ if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
// Don't check uninstantiated template destructors at all. We can only
// synthesize correct specs after the template is instantiated.
if (New->getParent()->isDependentType())
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bf4abfcb7460..76330f5cdbdd 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -12,13 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DelayedDiagnostic.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/AnalysisBasedWarnings.h"
-#include "clang/AST/ASTContext.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -34,14 +30,17 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Designator.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/Template.h"
-#include "TreeTransform.h"
using namespace clang;
using namespace sema;
@@ -163,7 +162,7 @@ static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
for (FunctionDecl::redecl_iterator I = D->redecls_begin(),
E = D->redecls_end();
I != E; ++I) {
- if (I->getStorageClassAsWritten() != SC_None)
+ if (I->getStorageClass() != SC_None)
return true;
}
return false;
@@ -215,19 +214,24 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
: diag::warn_internal_in_extern_inline)
<< /*IsVar=*/!UsedFn << D;
- // Suggest "static" on the inline function, if possible.
- if (!hasAnyExplicitStorageClass(Current)) {
- const FunctionDecl *FirstDecl = Current->getCanonicalDecl();
- SourceLocation DeclBegin = FirstDecl->getSourceRange().getBegin();
- S.Diag(DeclBegin, diag::note_convert_inline_to_static)
- << Current << FixItHint::CreateInsertion(DeclBegin, "static ");
- }
+ S.MaybeSuggestAddingStaticToDecl(Current);
S.Diag(D->getCanonicalDecl()->getLocation(),
diag::note_internal_decl_declared_here)
<< D;
}
+void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
+ const FunctionDecl *First = Cur->getFirstDeclaration();
+
+ // Suggest "static" on the function, if possible.
+ if (!hasAnyExplicitStorageClass(First)) {
+ SourceLocation DeclBegin = First->getSourceRange().getBegin();
+ Diag(DeclBegin, diag::note_convert_inline_to_static)
+ << Cur << FixItHint::CreateInsertion(DeclBegin, "static ");
+ }
+}
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -288,12 +292,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
/// diagnostic complaining about the given function being deleted or
/// unavailable.
std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
- // FIXME: C++0x implicitly-deleted special member functions could be
- // detected here so that we could improve diagnostics to say, e.g.,
- // "base class 'A' had a deleted copy constructor".
- if (FD->isDeleted())
- return std::string();
-
std::string Message;
if (FD->getAvailability(&Message))
return ": " + Message;
@@ -457,6 +455,62 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) {
}
}
+static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
+ SourceLocation AssignLoc,
+ const Expr* RHS) {
+ const ObjCIvarDecl *IV = OIRE->getDecl();
+ if (!IV)
+ return;
+
+ DeclarationName MemberName = IV->getDeclName();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ if (!Member || !Member->isStr("isa"))
+ return;
+
+ const Expr *Base = OIRE->getBase();
+ QualType BaseType = Base->getType();
+ if (OIRE->isArrow())
+ BaseType = BaseType->getPointeeType();
+ if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>())
+ if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) {
+ ObjCInterfaceDecl *ClassDeclared = 0;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+ if (!ClassDeclared->getSuperClass()
+ && (*ClassDeclared->ivar_begin()) == IV) {
+ if (RHS) {
+ NamedDecl *ObjectSetClass =
+ S.LookupSingleName(S.TUScope,
+ &S.Context.Idents.get("object_setClass"),
+ SourceLocation(), S.LookupOrdinaryName);
+ if (ObjectSetClass) {
+ SourceLocation RHSLocEnd = S.PP.getLocForEndOfToken(RHS->getLocEnd());
+ S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign) <<
+ FixItHint::CreateInsertion(OIRE->getLocStart(), "object_setClass(") <<
+ FixItHint::CreateReplacement(SourceRange(OIRE->getOpLoc(),
+ AssignLoc), ",") <<
+ FixItHint::CreateInsertion(RHSLocEnd, ")");
+ }
+ else
+ S.Diag(OIRE->getLocation(), diag::warn_objc_isa_assign);
+ } else {
+ NamedDecl *ObjectGetClass =
+ S.LookupSingleName(S.TUScope,
+ &S.Context.Idents.get("object_getClass"),
+ SourceLocation(), S.LookupOrdinaryName);
+ if (ObjectGetClass)
+ S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_use) <<
+ FixItHint::CreateInsertion(OIRE->getLocStart(), "object_getClass(") <<
+ FixItHint::CreateReplacement(
+ SourceRange(OIRE->getOpLoc(),
+ OIRE->getLocEnd()), ")");
+ else
+ S.Diag(OIRE->getLocation(), diag::warn_objc_isa_use);
+ }
+ S.Diag(IV->getLocation(), diag::note_ivar_decl);
+ }
+ }
+}
+
ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// Handle any placeholder expressions which made it here.
if (E->getType()->isPlaceholderType()) {
@@ -489,8 +543,31 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (T->isVoidType())
return Owned(E);
- CheckForNullPointerDereference(*this, E);
+ // OpenCL usually rejects direct accesses to values of 'half' type.
+ if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16 &&
+ T->isHalfType()) {
+ Diag(E->getExprLoc(), diag::err_opencl_half_load_store)
+ << 0 << T;
+ return ExprError();
+ }
+ CheckForNullPointerDereference(*this, E);
+ if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(E->IgnoreParenCasts())) {
+ NamedDecl *ObjectGetClass = LookupSingleName(TUScope,
+ &Context.Idents.get("object_getClass"),
+ SourceLocation(), LookupOrdinaryName);
+ if (ObjectGetClass)
+ Diag(E->getExprLoc(), diag::warn_objc_isa_use) <<
+ FixItHint::CreateInsertion(OISA->getLocStart(), "object_getClass(") <<
+ FixItHint::CreateReplacement(
+ SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")");
+ else
+ Diag(E->getExprLoc(), diag::warn_objc_isa_use);
+ }
+ else if (const ObjCIvarRefExpr *OIRE =
+ dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts()))
+ DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/0);
+
// 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
@@ -504,6 +581,12 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
T = T.getUnqualifiedType();
UpdateMarkingForLValueToRValue(E);
+
+ // Loading a __weak object implicitly retains the value, so we need a cleanup to
+ // balance that.
+ if (getLangOpts().ObjCAutoRefCount &&
+ E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ ExprNeedsCleanups = true;
ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
E, 0, VK_RValue));
@@ -540,15 +623,14 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
// First, convert to an r-value.
ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
- return Owned(E);
+ return ExprError();
E = Res.take();
QualType Ty = E->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
- // Half FP is a bit different: it's a storage-only type, meaning that any
- // "use" of it should be promoted to float.
- if (Ty->isHalfType())
+ // 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);
// Try to perform integral promotions if the object has a theoretically
@@ -583,19 +665,23 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
}
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
-/// do not have a prototype. Arguments that have type float are promoted to
-/// double. All other argument types are converted by UsualUnaryConversions().
+/// do not have a prototype. Arguments that have type float or __fp16
+/// are promoted to double. All other argument types are converted by
+/// UsualUnaryConversions().
ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
ExprResult Res = UsualUnaryConversions(E);
if (Res.isInvalid())
- return Owned(E);
+ return ExprError();
E = Res.take();
- // If this is a 'float' (CVR qualified or typedef) promote to double.
- if (Ty->isSpecificBuiltinType(BuiltinType::Float))
+ // 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();
// C++ performs lvalue-to-rvalue conversion as a default argument
@@ -635,16 +721,16 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty.isCXX98PODType(Context))
return VAK_Valid;
- // C++0x [expr.call]p7:
- // Passing a potentially-evaluated argument of class type (Clause 9)
+ // C++11 [expr.call]p7:
+ // Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
- // or a non-trivial destructor, with no corresponding parameter,
+ // or a non-trivial destructor, with no corresponding parameter,
// is conditionally-supported with implementation-defined semantics.
- if (getLangOpts().CPlusPlus0x && !Ty->isDependentType())
+ if (getLangOpts().CPlusPlus11 && !Ty->isDependentType())
if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl())
- if (Record->hasTrivialCopyConstructor() &&
- Record->hasTrivialMoveConstructor() &&
- Record->hasTrivialDestructor())
+ if (!Record->hasNonTrivialCopyConstructor() &&
+ !Record->hasNonTrivialMoveConstructor() &&
+ !Record->hasNonTrivialDestructor())
return VAK_ValidInCXX11;
if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType())
@@ -673,7 +759,7 @@ bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) {
return DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << getLangOpts().CPlusPlus0x << Ty << CT);
+ << getLangOpts().CPlusPlus11 << Ty << CT);
}
}
// c++ rules are enforced elsewhere.
@@ -938,54 +1024,24 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
/*convertFloat=*/!IsCompAssign);
}
-/// \brief Handle conversions with GCC complex int extension. Helper function
-/// of UsualArithmeticConversions()
-// FIXME: if the operands are (int, _Complex long), we currently
-// don't promote the complex. Also, signedness?
-static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
- ExprResult &RHS, QualType LHSType,
- QualType RHSType,
- bool IsCompAssign) {
- const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType();
- const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType();
+typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType);
- if (LHSComplexInt && RHSComplexInt) {
- int order = S.Context.getIntegerTypeOrder(LHSComplexInt->getElementType(),
- RHSComplexInt->getElementType());
- assert(order && "inequal types with equal element ordering");
- if (order > 0) {
- // _Complex int -> _Complex long
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralComplexCast);
- return LHSType;
- }
-
- if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralComplexCast);
- return RHSType;
- }
-
- if (LHSComplexInt) {
- // int -> _Complex int
- // FIXME: This needs to take integer ranks into account
- RHS = S.ImpCastExprToType(RHS.take(), LHSComplexInt->getElementType(),
- CK_IntegralCast);
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralRealToComplex);
- return LHSType;
- }
+namespace {
+/// These helper callbacks are placed in an anonymous namespace to
+/// permit their use as function template parameters.
+ExprResult doIntegralCast(Sema &S, Expr *op, QualType toType) {
+ return S.ImpCastExprToType(op, toType, CK_IntegralCast);
+}
- assert(RHSComplexInt);
- // int -> _Complex int
- // FIXME: This needs to take integer ranks into account
- if (!IsCompAssign) {
- LHS = S.ImpCastExprToType(LHS.take(), RHSComplexInt->getElementType(),
- CK_IntegralCast);
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralRealToComplex);
- }
- return RHSType;
+ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) {
+ return S.ImpCastExprToType(op, S.Context.getComplexType(toType),
+ CK_IntegralComplexCast);
+}
}
/// \brief Handle integer arithmetic conversions. Helper function of
/// UsualArithmeticConversions()
+template <PerformCastFn doLHSCast, PerformCastFn doRHSCast>
static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
QualType RHSType, bool IsCompAssign) {
@@ -996,29 +1052,29 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
if (LHSSigned == RHSSigned) {
// Same signedness; use the higher-ranked type
if (order >= 0) {
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), 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 = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), 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 = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), RHSType);
return RHSType;
} else {
// The signed type is higher-ranked than the unsigned type,
@@ -1027,19 +1083,62 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
// to the signed type.
QualType result =
S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType);
- RHS = S.ImpCastExprToType(RHS.take(), result, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), result);
if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), result, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), result);
return result;
}
}
+/// \brief Handle conversions with GCC complex int extension. Helper function
+/// of UsualArithmeticConversions()
+static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType,
+ bool IsCompAssign) {
+ const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType();
+ const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType();
+
+ if (LHSComplexInt && RHSComplexInt) {
+ QualType LHSEltType = LHSComplexInt->getElementType();
+ QualType RHSEltType = RHSComplexInt->getElementType();
+ QualType ScalarType =
+ handleIntegerConversion<doComplexIntegralCast, doComplexIntegralCast>
+ (S, LHS, RHS, LHSEltType, RHSEltType, IsCompAssign);
+
+ return S.Context.getComplexType(ScalarType);
+ }
+
+ if (LHSComplexInt) {
+ QualType LHSEltType = LHSComplexInt->getElementType();
+ QualType ScalarType =
+ handleIntegerConversion<doComplexIntegralCast, doIntegralCast>
+ (S, LHS, RHS, LHSEltType, RHSType, IsCompAssign);
+ QualType ComplexType = S.Context.getComplexType(ScalarType);
+ RHS = S.ImpCastExprToType(RHS.take(), ComplexType,
+ CK_IntegralRealToComplex);
+
+ return ComplexType;
+ }
+
+ assert(RHSComplexInt);
+
+ QualType RHSEltType = RHSComplexInt->getElementType();
+ QualType ScalarType =
+ handleIntegerConversion<doIntegralCast, doComplexIntegralCast>
+ (S, LHS, RHS, LHSType, RHSEltType, IsCompAssign);
+ QualType ComplexType = S.Context.getComplexType(ScalarType);
+
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), ComplexType,
+ CK_IntegralRealToComplex);
+ return ComplexType;
+}
+
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
/// routine returns the first non-arithmetic type found. The client is
/// responsible for emitting appropriate error diagnostics.
-/// FIXME: verify the conversion rules for "complex int" are consistent with
-/// GCC.
QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
bool IsCompAssign) {
if (!IsCompAssign) {
@@ -1104,10 +1203,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
IsCompAssign);
// Finally, we have two differing integer types.
- return handleIntegerConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ return handleIntegerConversion<doIntegralCast, doIntegralCast>
+ (*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
}
+
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -1149,6 +1249,12 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
TypeSourceInfo **Types,
Expr **Exprs,
unsigned NumAssocs) {
+ if (ControllingExpr->getType()->isPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(ControllingExpr);
+ if (result.isInvalid()) return ExprError();
+ ControllingExpr = result.take();
+ }
+
bool TypeErrorFound = false,
IsResultDependent = ControllingExpr->isTypeDependent(),
ContainsUnexpandedParameterPack
@@ -1401,7 +1507,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS) {
+ const CXXScopeSpec *SS, NamedDecl *FoundD) {
if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
@@ -1425,7 +1531,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
: NestedNameSpecifierLoc(),
SourceLocation(),
D, refersToEnclosingScope,
- NameInfo, Ty, VK);
+ NameInfo, Ty, VK, FoundD);
MarkDeclRefReferenced(E);
@@ -1533,9 +1639,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(
CallsUndergoingInstantiation.back()->getCallee());
-
CXXMethodDecl *DepMethod;
- if (CurMethod->getTemplatedKind() ==
+ if (CurMethod->isDependentContext())
+ DepMethod = CurMethod;
+ else if (CurMethod->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization)
DepMethod = cast<CXXMethodDecl>(CurMethod->getPrimaryTemplate()->
getInstantiatedFromMemberTemplate()->getTemplatedDecl());
@@ -1642,9 +1749,13 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
<< SS.getRange()
<< FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
CorrectedStr);
- if (ND)
- Diag(ND->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
+
+ unsigned diag = isa<ImplicitParamDecl>(ND)
+ ? diag::note_implicit_param_decl
+ : diag::note_previous_decl;
+
+ Diag(ND->getLocation(), diag)
+ << CorrectedQuotedStr;
// Tell the callee to try to recover.
return false;
@@ -1946,6 +2057,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo *II, bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
ObjCMethodDecl *CurMethod = getCurMethodDecl();
+
+ // Check for error condition which is already reported.
+ if (!CurMethod)
+ return ExprError();
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -2009,14 +2124,15 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (SelfExpr.isInvalid())
return ExprError();
- MarkAnyDeclReferenced(Loc, IV);
+ MarkAnyDeclReferenced(Loc, IV, true);
ObjCMethodFamily MF = CurMethod->getMethodFamily();
- if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize)
+ if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- Loc,
+ Loc, IV->getLocation(),
SelfExpr.take(),
true, true);
@@ -2321,8 +2437,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(),
- R.getFoundDecl());
+ return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
+ R.getRepresentativeDecl());
// We only need to check the declaration if there's exactly one
// result, because in the overloaded case the results can only be
@@ -2350,7 +2466,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
ExprResult
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
- NamedDecl *D) {
+ NamedDecl *D, NamedDecl *FoundD) {
assert(D && "Cannot refer to a NULL declaration");
assert(!isa<FunctionTemplateDecl>(D) &&
"Cannot refer unambiguously to a function template");
@@ -2546,7 +2662,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
break;
}
- return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
+ return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD);
}
}
@@ -2565,8 +2681,14 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
// string.
Decl *currentDecl = getCurFunctionOrMethodDecl();
- if (!currentDecl && getCurBlock())
- currentDecl = getCurBlock()->TheDecl;
+ // Blocks and lambdas can occur at global scope. Don't emit a warning.
+ if (!currentDecl) {
+ if (const BlockScopeInfo *BSI = getCurBlock())
+ currentDecl = BSI->TheDecl;
+ else if (const LambdaScopeInfo *LSI = getCurLambda())
+ currentDecl = LSI->CallOperator;
+ }
+
if (!currentDecl) {
Diag(Loc, diag::ext_predef_outside_function);
currentDecl = Context.getTranslationUnitDecl();
@@ -2764,7 +2886,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
SourceLocation TokLoc = Tok.getLocation();
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
- Context.CharTy, llvm::APInt(32, Length + 1),
+ Context.CharTy.withConst(), llvm::APInt(32, Length + 1),
ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
@@ -2825,7 +2947,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
if (!getLangOpts().C99 && Literal.isLongLong) {
if (getLangOpts().CPlusPlus)
Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
Diag(Tok.getLocation(), diag::ext_c99_longlong);
@@ -2835,7 +2957,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
// The microsoft literal suffix extensions support 128-bit literals, which
// may be wider than [u]intmax_t.
- if (Literal.isMicrosoftInteger && MaxWidth < 128)
+ // FIXME: Actually, they don't. We seem to have accidentally invented the
+ // i128 suffix.
+ if (Literal.isMicrosoftInteger && MaxWidth < 128 &&
+ PP.getTargetInfo().hasInt128Type())
MaxWidth = 128;
llvm::APInt ResultVal(MaxWidth, 0);
@@ -2905,7 +3030,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// 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) {
+ if (Ty.isNull() && Literal.isMicrosoftInteger &&
+ PP.getTargetInfo().hasInt128Type()) {
if (Literal.isUnsigned)
Ty = Context.UnsignedInt128Ty;
else
@@ -2963,16 +3089,17 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
SourceRange ArgRange,
UnaryExprOrTypeTrait TraitKind) {
// C99 6.5.3.4p1:
- if (T->isFunctionType()) {
- // alignof(function) is allowed as an extension.
- if (TraitKind == UETT_SizeOf)
- S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange;
+ if (T->isFunctionType() &&
+ (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf)) {
+ // sizeof(function)/alignof(function) is allowed as an extension.
+ S.Diag(Loc, diag::ext_sizeof_alignof_function_type)
+ << TraitKind << ArgRange;
return false;
}
// Allow sizeof(void)/alignof(void) as an extension.
if (T->isVoidType()) {
- S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange;
+ S.Diag(Loc, diag::ext_sizeof_alignof_void_type) << TraitKind << ArgRange;
return false;
}
@@ -2995,6 +3122,24 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
return false;
}
+/// \brief Check whether E is a pointer from a decayed array type (the decayed
+/// pointer type is equal to T) and emit a warning if it is.
+static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T,
+ Expr *E) {
+ // Don't warn if the operation changed the type.
+ if (T != E->getType())
+ return;
+
+ // Now look for array decays.
+ ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E);
+ if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay)
+ return;
+
+ S.Diag(Loc, diag::warn_sizeof_array_decay) << ICE->getSourceRange()
+ << ICE->getType()
+ << ICE->getSubExpr()->getType();
+}
+
/// \brief Check the constrains on expression operands to unary type expression
/// and type traits.
///
@@ -3048,6 +3193,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
}
}
}
+
+ // Warn on "sizeof(array op x)" and "sizeof(x op array)", where the array
+ // decays into a pointer and returns an unintended result. This is most
+ // likely a typo for "sizeof(array) op x".
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) {
+ warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(),
+ BO->getLHS());
+ warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(),
+ BO->getRHS());
+ }
}
return false;
@@ -3189,7 +3344,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
return ExprError();
if (ExprKind == UETT_SizeOf && E->getType()->isVariableArrayType()) {
- PE = TranformToPotentiallyEvaluated(E);
+ PE = TransformToPotentiallyEvaluated(E);
if (PE.isInvalid()) return ExprError();
E = PE.take();
}
@@ -3292,33 +3447,56 @@ static bool checkArithmeticOnObjCPointer(Sema &S,
}
ExprResult
-Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
- Expr *Idx, SourceLocation RLoc) {
+Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
+ Expr *idx, SourceLocation rbLoc) {
// Since this might be a postfix expression, get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
+ if (isa<ParenListExpr>(base)) {
+ ExprResult result = MaybeConvertParenListExprToParenExpr(S, base);
+ if (result.isInvalid()) return ExprError();
+ base = result.take();
+ }
- Expr *LHSExp = Base, *RHSExp = Idx;
+ // Handle any non-overload placeholder types in the base and index
+ // expressions. We can't handle overloads here because the other
+ // operand might be an overloadable type, in which case the overload
+ // resolution for the operator overload should get the first crack
+ // at the overload.
+ if (base->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(base);
+ if (result.isInvalid()) return ExprError();
+ base = result.take();
+ }
+ if (idx->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(idx);
+ if (result.isInvalid()) return ExprError();
+ idx = result.take();
+ }
+ // Build an unanalyzed expression if either operand is type-dependent.
if (getLangOpts().CPlusPlus &&
- (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
- return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
+ (base->isTypeDependent() || idx->isTypeDependent())) {
+ return Owned(new (Context) ArraySubscriptExpr(base, idx,
Context.DependentTy,
VK_LValue, OK_Ordinary,
- RLoc));
+ rbLoc));
}
+ // Use C++ overloaded-operator rules if either operand has record
+ // type. The spec says to do this if either type is *overloadable*,
+ // but enum types can't declare subscript operators or conversion
+ // operators, so there's nothing interesting for overload resolution
+ // to do if there aren't any record types involved.
+ //
+ // ObjC pointers have their own subscripting logic that is not tied
+ // to overload resolution and so should not take this path.
if (getLangOpts().CPlusPlus &&
- (LHSExp->getType()->isRecordType() ||
- LHSExp->getType()->isEnumeralType() ||
- RHSExp->getType()->isRecordType() ||
- RHSExp->getType()->isEnumeralType()) &&
- !LHSExp->getType()->isObjCObjectPointerType()) {
- return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, Base, Idx);
+ (base->getType()->isRecordType() ||
+ (!base->getType()->isObjCObjectPointerType() &&
+ idx->getType()->isRecordType()))) {
+ return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx);
}
- return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc);
+ return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
}
ExprResult
@@ -3525,7 +3703,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
return ExprError();
Expr *Arg = Result.takeAs<Expr>();
- CheckImplicitConversions(Arg, Param->getOuterLocStart());
+ CheckCompletedExpr(Arg, Param->getOuterLocStart());
// Build the default argument expression.
return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg));
}
@@ -3687,7 +3865,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
Expr **Args, unsigned NumArgs,
SmallVector<Expr *, 8> &AllArgs,
VariadicCallType CallType,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ bool IsListInitialization) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
bool Invalid = false;
@@ -3720,20 +3899,21 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
(!Param || !Param->hasAttr<CFConsumedAttr>()))
Arg = stripARCUnbridgedCast(Arg);
- InitializedEntity Entity =
- Param? InitializedEntity::InitializeParameter(Context, Param)
- : InitializedEntity::InitializeParameter(Context, ProtoArgType,
- Proto->isArgConsumed(i));
+ InitializedEntity Entity = Param ?
+ InitializedEntity::InitializeParameter(Context, Param, ProtoArgType)
+ : InitializedEntity::InitializeParameter(Context, ProtoArgType,
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg),
- /*TopLevelOfInitList=*/false,
+ IsListInitialization,
AllowExplicit);
if (ArgE.isInvalid())
return true;
Arg = ArgE.takeAs<Expr>();
} else {
+ assert(FDecl && "can't use default arguments without a known callee");
Param = FDecl->getParamDecl(i);
ExprResult ArgExpr =
@@ -3762,11 +3942,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
if (Proto->getResultType() == Context.UnknownAnyTy &&
FDecl && FDecl->isExternC()) {
for (unsigned i = ArgIx; i != NumArgs; ++i) {
- ExprResult arg;
- if (isa<ExplicitCastExpr>(Args[i]->IgnoreParens()))
- arg = DefaultFunctionArrayLvalueConversion(Args[i]);
- else
- arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
+ QualType paramType; // ignored
+ ExprResult arg = checkUnknownAnyArg(CallLoc, Args[i], paramType);
Invalid |= arg.isInvalid();
AllArgs.push_back(arg.take());
}
@@ -3790,9 +3967,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) {
TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc();
- if (ArrayTypeLoc *ATL = dyn_cast<ArrayTypeLoc>(&TL))
+ if (ArrayTypeLoc ATL = TL.getAs<ArrayTypeLoc>())
S.Diag(PVD->getLocation(), diag::note_callee_static_array)
- << ATL->getLocalSourceRange();
+ << ATL.getLocalSourceRange();
}
/// CheckStaticArrayArgument - If the given argument corresponds to a static
@@ -4593,10 +4770,15 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
Expr **exprs;
unsigned numExprs;
Expr *subExpr;
+ SourceLocation LiteralLParenLoc, LiteralRParenLoc;
if (ParenListExpr *PE = dyn_cast<ParenListExpr>(E)) {
+ LiteralLParenLoc = PE->getLParenLoc();
+ LiteralRParenLoc = PE->getRParenLoc();
exprs = PE->getExprs();
numExprs = PE->getNumExprs();
- } else {
+ } else { // isa<ParenExpr> by assertion at function entrance
+ LiteralLParenLoc = cast<ParenExpr>(E)->getLParen();
+ LiteralRParenLoc = cast<ParenExpr>(E)->getRParen();
subExpr = cast<ParenExpr>(E)->getSubExpr();
exprs = &subExpr;
numExprs = 1;
@@ -4653,8 +4835,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
}
// FIXME: This means that pretty-printing the final AST will produce curly
// braces instead of the original commas.
- InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc,
- initExprs, RParenLoc);
+ InitListExpr *initE = new (Context) InitListExpr(Context, LiteralLParenLoc,
+ initExprs, LiteralRParenLoc);
initE->setType(Ty);
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
}
@@ -4681,7 +4863,6 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ExprResult Sema::ActOnParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val) {
- assert(Val.data() != 0 && "ActOnParenOrParenListExpr() missing expr list");
Expr *expr = new (Context) ParenListExpr(Context, L, Val, R);
return Owned(expr);
}
@@ -4720,7 +4901,7 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
return false;
}
- int DiagType = (NullKind == Expr::NPCK_CXX0X_nullptr);
+ int DiagType = (NullKind == Expr::NPCK_CXX11_nullptr);
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands_null)
<< NonPointerExpr->getType() << DiagType
<< NonPointerExpr->getSourceRange();
@@ -4734,7 +4915,7 @@ static bool checkCondition(Sema &S, Expr *Cond) {
// C99 6.5.15p2
if (CondTy->isScalarType()) return false;
- // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar.
+ // OpenCL v1.1 s6.3.i says the condition is allowed to be a vector or scalar.
if (S.getLangOpts().OpenCL && CondTy->isVectorType())
return false;
@@ -4995,9 +5176,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHSTy->isVectorType() || RHSTy->isVectorType())
return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
- // OpenCL: If the condition is a vector, and both operands are scalar,
+ // If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
- // built in select.
+ // built in select. (OpenCL v1.1 s6.3.i)
if (getLangOpts().OpenCL && CondTy->isVectorType())
if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy))
return QualType();
@@ -5264,7 +5445,8 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
// Make sure this is really a binary operator that is safe to pass into
// BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op.
OverloadedOperatorKind OO = Call->getOperator();
- if (OO < OO_Plus || OO > OO_Arrow)
+ if (OO < OO_Plus || OO > OO_Arrow ||
+ OO == OO_PlusPlus || OO == OO_MinusMinus)
return false;
BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO);
@@ -5625,7 +5807,6 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
-
// Common case: no conversion required.
if (LHSType == RHSType) {
Kind = CK_NoOp;
@@ -6570,6 +6751,11 @@ static bool isScopedEnumerationType(QualType T) {
static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned Opc,
QualType LHSType) {
+ // OpenCL 6.3j: shift values are effectively % word size of LHS (more defined),
+ // so skip remaining warnings as we don't want to modify values within Sema.
+ if (S.getLangOpts().OpenCL)
+ return;
+
llvm::APSInt Right;
// Check right/shifter operand
if (RHS.get()->isValueDependent() ||
@@ -6689,10 +6875,10 @@ static bool IsWithinTemplateSpecialization(Decl *D) {
}
/// If two different enums are compared, raise a warning.
-static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS,
- ExprResult &RHS) {
- QualType LHSStrippedType = LHS.get()->IgnoreParenImpCasts()->getType();
- QualType RHSStrippedType = RHS.get()->IgnoreParenImpCasts()->getType();
+static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
+ Expr *RHS) {
+ QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
+ QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>();
if (!LHSEnumType)
@@ -6712,7 +6898,7 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS,
S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
<< LHSStrippedType << RHSStrippedType
- << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
/// \brief Diagnose bad pointer comparisons.
@@ -6796,18 +6982,18 @@ static bool isObjCObjectLiteral(ExprResult &E) {
}
static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
- // Get the LHS object's interface type.
- QualType Type = LHS->getType();
- QualType InterfaceType;
- if (const ObjCObjectPointerType *PTy = Type->getAs<ObjCObjectPointerType>()) {
- InterfaceType = PTy->getPointeeType();
- if (const ObjCObjectType *iQFaceTy =
- InterfaceType->getAsObjCQualifiedInterfaceType())
- InterfaceType = iQFaceTy->getBaseType();
- } else {
- // If this is not actually an Objective-C object, bail out.
+ const ObjCObjectPointerType *Type =
+ LHS->getType()->getAs<ObjCObjectPointerType>();
+
+ // If this is not actually an Objective-C object, bail out.
+ if (!Type)
return false;
- }
+
+ // Get the LHS object's interface type.
+ QualType InterfaceType = Type->getPointeeType();
+ if (const ObjCObjectType *iQFaceTy =
+ InterfaceType->getAsObjCQualifiedInterfaceType())
+ InterfaceType = iQFaceTy->getBaseType();
// If the RHS isn't an Objective-C object, bail out.
if (!RHS->getType()->isObjCObjectPointerType())
@@ -6826,8 +7012,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
/*warn=*/false);
} else {
// Check protocols.
- Method = S.LookupMethodInQualifiedType(IsEqualSel,
- cast<ObjCObjectPointerType>(Type),
+ Method = S.LookupMethodInQualifiedType(IsEqualSel, Type,
/*instance=*/true);
}
}
@@ -6846,6 +7031,48 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
return true;
}
+Sema::ObjCLiteralKind Sema::CheckLiteralKind(Expr *FromE) {
+ FromE = FromE->IgnoreParenImpCasts();
+ switch (FromE->getStmtClass()) {
+ default:
+ break;
+ case Stmt::ObjCStringLiteralClass:
+ // "string literal"
+ return LK_String;
+ case Stmt::ObjCArrayLiteralClass:
+ // "array literal"
+ return LK_Array;
+ case Stmt::ObjCDictionaryLiteralClass:
+ // "dictionary literal"
+ return LK_Dictionary;
+ case Stmt::BlockExprClass:
+ return LK_Block;
+ case Stmt::ObjCBoxedExprClass: {
+ Expr *Inner = cast<ObjCBoxedExpr>(FromE)->getSubExpr()->IgnoreParens();
+ switch (Inner->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::ObjCBoolLiteralExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ // "numeric literal"
+ return LK_Numeric;
+ case Stmt::ImplicitCastExprClass: {
+ CastKind CK = cast<CastExpr>(Inner)->getCastKind();
+ // Boolean literals can be represented by implicit casts.
+ if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast)
+ return LK_Numeric;
+ break;
+ }
+ default:
+ break;
+ }
+ return LK_Boxed;
+ }
+ }
+ return LK_None;
+}
+
static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS,
BinaryOperator::Opcode Opc){
@@ -6866,61 +7093,15 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
return;
// This should be kept in sync with warn_objc_literal_comparison.
- // LK_String should always be last, since it has its own warning flag.
- enum {
- LK_Array,
- LK_Dictionary,
- LK_Numeric,
- LK_Boxed,
- LK_String
- } LiteralKind;
-
- Literal = Literal->IgnoreParenImpCasts();
- switch (Literal->getStmtClass()) {
- case Stmt::ObjCStringLiteralClass:
- // "string literal"
- LiteralKind = LK_String;
- break;
- case Stmt::ObjCArrayLiteralClass:
- // "array literal"
- LiteralKind = LK_Array;
- break;
- case Stmt::ObjCDictionaryLiteralClass:
- // "dictionary literal"
- LiteralKind = LK_Dictionary;
- break;
- case Stmt::ObjCBoxedExprClass: {
- Expr *Inner = cast<ObjCBoxedExpr>(Literal)->getSubExpr();
- switch (Inner->getStmtClass()) {
- case Stmt::IntegerLiteralClass:
- case Stmt::FloatingLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::ObjCBoolLiteralExprClass:
- case Stmt::CXXBoolLiteralExprClass:
- // "numeric literal"
- LiteralKind = LK_Numeric;
- break;
- case Stmt::ImplicitCastExprClass: {
- CastKind CK = cast<CastExpr>(Inner)->getCastKind();
- // Boolean literals can be represented by implicit casts.
- if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast) {
- LiteralKind = LK_Numeric;
- break;
- }
- // FALLTHROUGH
- }
- default:
- // "boxed expression"
- LiteralKind = LK_Boxed;
- break;
- }
- break;
- }
- default:
+ // LK_String should always be after the other literals, since it has its own
+ // warning flag.
+ Sema::ObjCLiteralKind LiteralKind = S.CheckLiteralKind(Literal);
+ assert(LiteralKind != Sema::LK_Block);
+ if (LiteralKind == Sema::LK_None) {
llvm_unreachable("Unknown Objective-C object literal kind");
}
- if (LiteralKind == LK_String)
+ if (LiteralKind == Sema::LK_String)
S.Diag(Loc, diag::warn_objc_string_literal_comparison)
<< Literal->getSourceRange();
else
@@ -6931,11 +7112,12 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
hasIsEqualMethod(S, LHS.get(), RHS.get())) {
SourceLocation Start = LHS.get()->getLocStart();
SourceLocation End = S.PP.getLocForEndOfToken(RHS.get()->getLocEnd());
- SourceRange OpRange(Loc, S.PP.getLocForEndOfToken(Loc));
+ CharSourceRange OpRange =
+ CharSourceRange::getCharRange(Loc, S.PP.getLocForEndOfToken(Loc));
S.Diag(Loc, diag::note_objc_literal_comparison_isequal)
<< FixItHint::CreateInsertion(Start, Opc == BO_EQ ? "[" : "![")
- << FixItHint::CreateReplacement(OpRange, "isEqual:")
+ << FixItHint::CreateReplacement(OpRange, " isEqual:")
<< FixItHint::CreateInsertion(End, "]");
}
}
@@ -6959,7 +7141,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts();
Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
- checkEnumComparison(*this, Loc, LHS, RHS);
+ checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
if (!LHSType->hasFloatingRepresentation() &&
!(LHSType->isBlockPointerType() && IsRelational) &&
@@ -7109,7 +7291,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
&& !LHSIsNull && !RHSIsNull) {
diagnoseFunctionPointerToVoidComparison(
- *this, Loc, LHS, RHS, /*isError*/ isSFINAEContext());
+ *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
if (isSFINAEContext())
return QualType();
@@ -7396,7 +7578,10 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
// Ensure that either both operands are of the same vector type, or
// one operand is of a vector type and the other is of its element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, false);
- if (vType.isNull() || vType->isFloatingType())
+ if (vType.isNull())
+ return InvalidOperands(Loc, LHS, RHS);
+ if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
+ vType->hasFloatingRepresentation())
return InvalidOperands(Loc, LHS, RHS);
return GetSignedVectorType(LHS.get()->getType());
@@ -7472,8 +7657,17 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
RHS.get()->getLocEnd()));
}
}
-
+
if (!Context.getLangOpts().CPlusPlus) {
+ // OpenCL v1.1 s6.3.g: The logical operators and (&&), or (||) do
+ // not operate on the built-in scalar and vector float types.
+ if (Context.getLangOpts().OpenCL &&
+ Context.getLangOpts().OpenCLVersion < 120) {
+ if (LHS.get()->getType()->isFloatingType() ||
+ RHS.get()->getType()->isFloatingType())
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+
LHS = UsualUnaryConversions(LHS.take());
if (LHS.isInvalid())
return QualType();
@@ -7999,7 +8193,9 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
if (PTy->getKind() == BuiltinType::Overload) {
if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ assert(cast<UnaryOperator>(OrigOp.get()->IgnoreParens())->getOpcode()
+ == UO_AddrOf);
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof_addrof_function)
<< OrigOp.get()->getSourceRange();
return QualType();
}
@@ -8043,10 +8239,10 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
Expr::LValueClassification lval = op->ClassifyLValue(S.Context);
unsigned AddressOfError = AO_No_Error;
- if (lval == Expr::LV_ClassTemporary) {
- bool sfinae = S.isSFINAEContext();
- S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary
- : diag::ext_typecheck_addrof_class_temporary)
+ if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) {
+ bool sfinae = (bool)S.isSFINAEContext();
+ S.Diag(OpLoc, S.isSFINAEContext() ? diag::err_typecheck_addrof_temporary
+ : diag::ext_typecheck_addrof_temporary)
<< op->getType() << op->getSourceRange();
if (sfinae)
return QualType();
@@ -8094,9 +8290,8 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
if (isa<PseudoObjectExpr>(op)) {
AddressOfError = AO_Property_Expansion;
} else {
- // FIXME: emit more specific diag...
S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << op->getSourceRange();
+ << op->getType() << op->getSourceRange();
return QualType();
}
}
@@ -8312,7 +8507,7 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
- if (getLangOpts().CPlusPlus0x && isa<InitListExpr>(RHSExpr)) {
+ if (getLangOpts().CPlusPlus11 && isa<InitListExpr>(RHSExpr)) {
// The syntax only allows initializer lists on the RHS of assignment,
// so we don't need to worry about accepting invalid code for
// non-assignment operators.
@@ -8445,6 +8640,24 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CheckArrayAccess(LHS.get());
CheckArrayAccess(RHS.get());
+ if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(LHS.get()->IgnoreParenCasts())) {
+ NamedDecl *ObjectSetClass = LookupSingleName(TUScope,
+ &Context.Idents.get("object_setClass"),
+ SourceLocation(), LookupOrdinaryName);
+ if (ObjectSetClass && isa<ObjCIsaExpr>(LHS.get())) {
+ SourceLocation RHSLocEnd = PP.getLocForEndOfToken(RHS.get()->getLocEnd());
+ Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign) <<
+ FixItHint::CreateInsertion(LHS.get()->getLocStart(), "object_setClass(") <<
+ FixItHint::CreateReplacement(SourceRange(OISA->getOpLoc(), OpLoc), ",") <<
+ FixItHint::CreateInsertion(RHSLocEnd, ")");
+ }
+ else
+ Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign);
+ }
+ else if (const ObjCIvarRefExpr *OIRE =
+ dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts()))
+ DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
+
if (CompResultTy.isNull())
return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, OpLoc,
@@ -8467,46 +8680,38 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceLocation OpLoc, Expr *LHSExpr,
Expr *RHSExpr) {
- typedef BinaryOperator BinOp;
- BinOp::Opcode LHSopc = static_cast<BinOp::Opcode>(-1),
- RHSopc = static_cast<BinOp::Opcode>(-1);
- if (BinOp *BO = dyn_cast<BinOp>(LHSExpr))
- LHSopc = BO->getOpcode();
- if (BinOp *BO = dyn_cast<BinOp>(RHSExpr))
- RHSopc = BO->getOpcode();
-
- // Subs are not binary operators.
- if (LHSopc == -1 && RHSopc == -1)
+ BinaryOperator *LHSBO = dyn_cast<BinaryOperator>(LHSExpr);
+ BinaryOperator *RHSBO = dyn_cast<BinaryOperator>(RHSExpr);
+
+ // Check that one of the sides is a comparison operator.
+ bool isLeftComp = LHSBO && LHSBO->isComparisonOp();
+ bool isRightComp = RHSBO && RHSBO->isComparisonOp();
+ if (!isLeftComp && !isRightComp)
return;
// Bitwise operations are sometimes used as eager logical ops.
// Don't diagnose this.
- if ((BinOp::isComparisonOp(LHSopc) || BinOp::isBitwiseOp(LHSopc)) &&
- (BinOp::isComparisonOp(RHSopc) || BinOp::isBitwiseOp(RHSopc)))
+ bool isLeftBitwise = LHSBO && LHSBO->isBitwiseOp();
+ bool isRightBitwise = RHSBO && RHSBO->isBitwiseOp();
+ if ((isLeftComp || isLeftBitwise) && (isRightComp || isRightBitwise))
return;
- bool isLeftComp = BinOp::isComparisonOp(LHSopc);
- bool isRightComp = BinOp::isComparisonOp(RHSopc);
- if (!isLeftComp && !isRightComp) return;
-
SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(),
OpLoc)
: SourceRange(OpLoc, RHSExpr->getLocEnd());
- StringRef OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
- : BinOp::getOpcodeStr(RHSopc);
+ StringRef OpStr = isLeftComp ? LHSBO->getOpcodeStr() : RHSBO->getOpcodeStr();
SourceRange ParensRange = isLeftComp ?
- SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(),
- RHSExpr->getLocEnd())
- : SourceRange(LHSExpr->getLocStart(),
- cast<BinOp>(RHSExpr)->getLHS()->getLocStart());
+ SourceRange(LHSBO->getRHS()->getLocStart(), RHSExpr->getLocEnd())
+ : SourceRange(LHSExpr->getLocStart(), RHSBO->getLHS()->getLocStart());
Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
- << DiagRange << BinOp::getOpcodeStr(Opc) << OpStr;
+ << DiagRange << BinaryOperator::getOpcodeStr(Opc) << OpStr;
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_silence) << OpStr,
(isLeftComp ? LHSExpr : RHSExpr)->getSourceRange());
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc),
+ Self.PDiag(diag::note_precedence_bitwise_first)
+ << BinaryOperator::getOpcodeStr(Opc),
ParensRange);
}
@@ -8806,7 +9011,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Not: // bitwise complement
Input = UsualUnaryConversions(Input.take());
- if (Input.isInvalid()) return ExprError();
+ if (Input.isInvalid())
+ return ExprError();
resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
@@ -8814,12 +9020,22 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (resultType->isComplexType() || resultType->isComplexIntegerType())
// C99 does not support '~' for complex conjugation.
Diag(OpLoc, diag::ext_integer_complement_complex)
- << resultType << Input.get()->getSourceRange();
+ << resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else {
+ else if (resultType->isExtVectorType()) {
+ if (Context.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+ // on vector float types.
+ QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ if (!T->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
+ }
+ break;
+ } else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input.get()->getSourceRange());
+ << resultType << Input.get()->getSourceRange());
}
break;
@@ -8830,7 +9046,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = Input.get()->getType();
// Though we still have to promote half FP to float...
- if (resultType->isHalfType()) {
+ if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) {
Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take();
resultType = Context.FloatTy;
}
@@ -8844,8 +9060,24 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
// operand contextually converted to bool.
Input = ImpCastExprToType(Input.take(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
+ } else if (Context.getLangOpts().OpenCL &&
+ Context.getLangOpts().OpenCLVersion < 120) {
+ // OpenCL v1.1 6.3.h: The logical operator not (!) does not
+ // operate on scalar float types.
+ if (!resultType->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
}
} else if (resultType->isExtVectorType()) {
+ if (Context.getLangOpts().OpenCL &&
+ Context.getLangOpts().OpenCLVersion < 120) {
+ // OpenCL v1.1 6.3.h: The logical operator not (!) does not
+ // operate on vector float types.
+ QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ if (!T->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
+ }
// Vector logical not returns the signed variant of the operand type.
resultType = GetSignedVectorType(resultType);
break;
@@ -9210,9 +9442,9 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// If type is not a standard-layout class (Clause 9), the results are
// undefined.
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- bool IsSafe = LangOpts.CPlusPlus0x? CRD->isStandardLayout() : CRD->isPOD();
+ bool IsSafe = LangOpts.CPlusPlus11? CRD->isStandardLayout() : CRD->isPOD();
unsigned DiagID =
- LangOpts.CPlusPlus0x? diag::warn_offsetof_non_standardlayout_type
+ LangOpts.CPlusPlus11? diag::warn_offsetof_non_standardlayout_type
: diag::warn_offsetof_non_pod_type;
if (!IsSafe && !DidWarnAboutNonPOD &&
@@ -9379,8 +9611,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals |= DeclSpec::TQ_const;
- T = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0,
- EPI);
+ T = Context.getFunctionType(Context.DependentTy, ArrayRef<QualType>(), EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
@@ -9394,8 +9625,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoTypeLoc ExplicitSignature;
TypeLoc tmp = Sig->getTypeLoc().IgnoreParens();
- if (isa<FunctionProtoTypeLoc>(tmp)) {
- ExplicitSignature = cast<FunctionProtoTypeLoc>(tmp);
+ if ((ExplicitSignature = tmp.getAs<FunctionProtoTypeLoc>())) {
// Check whether that explicit signature was synthesized by
// GetTypeForDeclarator. If so, don't save that as part of the
@@ -9560,7 +9790,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (isa<FunctionNoProtoType>(FTy)) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
+ BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI);
// Otherwise, if we don't need to change anything about the function type,
// preserve its sugar structure.
@@ -9574,17 +9804,18 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals = 0; // FIXME: silently?
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy,
- FPT->arg_type_begin(),
- FPT->getNumArgs(),
- EPI);
+ BlockTy =
+ Context.getFunctionType(RetTy,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
- BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
+ BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI);
}
DiagnoseUnusedParameters(BSI->TheDecl->param_begin(),
@@ -9715,11 +9946,11 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float))
PromoteType = Context.DoubleTy;
if (!PromoteType.isNull())
- Diag(TInfo->getTypeLoc().getBeginLoc(),
- diag::warn_second_parameter_to_va_arg_never_compatible)
- << TInfo->getType()
- << PromoteType
- << TInfo->getTypeLoc().getSourceRange();
+ DiagRuntimeBehavior(TInfo->getTypeLoc().getBeginLoc(), E,
+ PDiag(diag::warn_second_parameter_to_va_arg_never_compatible)
+ << TInfo->getType()
+ << PromoteType
+ << TInfo->getTypeLoc().getSourceRange());
}
QualType T = TInfo->getType().getNonLValueExprType(Context);
@@ -9932,6 +10163,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (CheckInferredResultType)
EmitRelatedResultTypeNote(SrcExpr);
+
+ if (Action == AA_Returning && ConvTy == IncompatiblePointer)
+ EmitRelatedResultTypeNoteForReturn(DstType);
if (Complained)
*Complained = true;
@@ -9980,7 +10214,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
bool AllowFold) {
SourceLocation DiagLoc = E->getLocStart();
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++11 [expr.const]p5:
// If an expression of literal class type is used in a context where an
// integral constant expression is required, then that class type shall
@@ -10107,14 +10341,14 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// Circumvent ICE checking in C++11 to avoid evaluating the expression twice
// in the non-ICE case.
- if (!getLangOpts().CPlusPlus0x && E->isIntegerConstantExpr(Context)) {
+ if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) {
if (Result)
*Result = E->EvaluateKnownConstInt(Context);
return Owned(E);
}
Expr::EvalResult EvalResult;
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
EvalResult.Diag = &Notes;
// Try to evaluate the expression, and produce diagnostics explaining why it's
@@ -10125,7 +10359,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// In C++11, we can rely on diagnostics being produced for any expression
// which is not a constant expression. If no diagnostics were produced, then
// this is a constant expression.
- if (Folded && getLangOpts().CPlusPlus0x && Notes.empty()) {
+ if (Folded && getLangOpts().CPlusPlus11 && Notes.empty()) {
if (Result)
*Result = EvalResult.Val.getInt();
return Owned(E);
@@ -10211,7 +10445,7 @@ namespace {
};
}
-ExprResult Sema::TranformToPotentiallyEvaluated(Expr *E) {
+ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) {
assert(ExprEvalContexts.back().Context == Unevaluated &&
"Should only transform unevaluated expressions");
ExprEvalContexts.back().Context =
@@ -10302,7 +10536,7 @@ void Sema::DiscardCleanupsInEvaluationContext() {
ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
if (!E->getType()->isVariablyModifiedType())
return E;
- return TranformToPotentiallyEvaluated(E);
+ return TransformToPotentiallyEvaluated(E);
}
static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
@@ -10395,6 +10629,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
if (!Constructor->isUsed(false))
DefineImplicitMoveConstructor(Loc, Constructor);
}
+ } else if (Constructor->getInheritedConstructor()) {
+ if (!Constructor->isUsed(false))
+ DefineInheritingConstructor(Loc, Constructor);
}
MarkVTableUsed(Loc, Constructor->getParent());
@@ -10488,13 +10725,26 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
}
// Keep track of used but undefined functions.
- if (!Func->isPure() && !Func->hasBody() &&
- Func->getLinkage() != ExternalLinkage) {
- SourceLocation &old = UndefinedInternals[Func->getCanonicalDecl()];
- if (old.isInvalid()) old = Loc;
+ if (!Func->isDefined()) {
+ if (mightHaveNonExternalLinkage(Func))
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ else if (Func->getMostRecentDecl()->isInlined() &&
+ (LangOpts.CPlusPlus || !LangOpts.GNUInline) &&
+ !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>())
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ }
+
+ // Normally the must current decl is marked used while processing the use and
+ // any subsequent decls are marked used by decl merging. This fails with
+ // template instantiation since marking can happen at the end of the file
+ // and, because of the two phase lookup, this function is called with at
+ // decl in the middle of a decl chain. We loop to maintain the invariant
+ // that once a decl is used, all decls after it are also used.
+ for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) {
+ F->setUsed(true);
+ if (F == Func)
+ break;
}
-
- Func->setUsed(true);
}
static void
@@ -10572,7 +10822,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
// Introduce a new evaluation context for the initialization, so
// that temporaries introduced as part of the capture are retained
// to be re-"exported" from the lambda expression itself.
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated);
// C++ [expr.prim.labda]p12:
// An entity captured by a lambda-expression is odr-used (3.2) in
@@ -10604,7 +10854,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
= VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
IterationVarName, SizeType,
S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None, SC_None);
+ SC_None);
IndexVariables.push_back(IterationVar);
LSI->ArrayIndexVars.push_back(IterationVar);
@@ -10623,7 +10873,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
if (Subscript.isInvalid()) {
S.CleanupVarDeclMarking();
S.DiscardCleanupsInEvaluationContext();
- S.PopExpressionEvaluationContext();
return ExprError();
}
@@ -10659,7 +10908,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
// Exit the expression evaluation context used for the capture.
S.CleanupVarDeclMarking();
S.DiscardCleanupsInEvaluationContext();
- S.PopExpressionEvaluationContext();
return Result;
}
@@ -10748,7 +10996,22 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
}
return true;
}
-
+ // Prohibit structs with flexible array members too.
+ // We cannot capture what is in the tail end of the struct.
+ if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) {
+ if (VTTy->getDecl()->hasFlexibleArrayMember()) {
+ if (BuildAndDiagnose) {
+ if (IsBlock)
+ Diag(Loc, diag::err_ref_flexarray_type);
+ else
+ Diag(Loc, diag::err_lambda_capture_flexarray_type)
+ << Var->getDeclName();
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
+ }
// Lambdas are not allowed to capture __block variables; they don't
// support the expected semantics.
if (IsLambda && HasBlocksAttr) {
@@ -10830,13 +11093,18 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
// actually requires the destructor.
if (isa<ParmVarDecl>(Var))
FinalizeVarWithDestructor(Var, Record);
-
+
+ // Enter a new evaluation context to insulate the copy
+ // full-expression.
+ EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+
// According to the blocks spec, the capture of a variable from
// the stack requires a const copy constructor. This is not true
// of the copy/move done to move a __block variable to the heap.
- Expr *DeclRef = new (Context) DeclRefExpr(Var, false,
+ Expr *DeclRef = new (Context) DeclRefExpr(Var, Nested,
DeclRefType.withConst(),
VK_LValue, Loc);
+
ExprResult Result
= PerformCopyInitialization(
InitializedEntity::InitializeBlock(Var->getLocation(),
@@ -10921,7 +11189,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
if (BuildAndDiagnose) {
ExprResult Result = captureInLambda(*this, LSI, Var, CaptureType,
DeclRefType, Loc,
- I == N-1);
+ Nested);
if (!Result.isInvalid())
CopyExpr = Result.take();
}
@@ -10978,7 +11246,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
Var->getLinkage() != ExternalLinkage &&
!(Var->isStaticDataMember() && Var->hasInit())) {
- SourceLocation &old = SemaRef.UndefinedInternals[Var->getCanonicalDecl()];
+ SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
}
@@ -11090,13 +11358,13 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
}
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
- Decl *D, Expr *E) {
+ Decl *D, Expr *E, bool OdrUse) {
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
return;
}
- SemaRef.MarkAnyDeclReferenced(Loc, D);
+ SemaRef.MarkAnyDeclReferenced(Loc, D, OdrUse);
// If this is a call to a method via a cast, also mark the method in the
// derived class used in case codegen can devirtualize the call.
@@ -11111,32 +11379,58 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
if (!MostDerivedClassDecl)
return;
CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
- if (!DM)
+ if (!DM || DM->isPure())
return;
- SemaRef.MarkAnyDeclReferenced(Loc, DM);
+ SemaRef.MarkAnyDeclReferenced(Loc, DM, OdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
- MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
+ // TODO: update this with DR# once a defect report is filed.
+ // C++11 defect. The address of a pure member should not be an ODR use, even
+ // if it's a qualified reference.
+ bool OdrUse = true;
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
+ if (Method->isVirtual())
+ OdrUse = false;
+ MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a MemberExpr.
void Sema::MarkMemberReferenced(MemberExpr *E) {
- MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E);
+ // C++11 [basic.def.odr]p2:
+ // A non-overloaded function whose name appears as a potentially-evaluated
+ // expression or a member of a set of candidate functions, if selected by
+ // overload resolution when referred to from a potentially-evaluated
+ // expression, is odr-used, unless it is a pure virtual function and its
+ // name is not explicitly qualified.
+ bool OdrUse = true;
+ if (!E->hasQualifier()) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getMemberDecl()))
+ if (Method->isPure())
+ OdrUse = false;
+ }
+ SourceLocation Loc = E->getMemberLoc().isValid() ?
+ E->getMemberLoc() : E->getLocStart();
+ MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, OdrUse);
}
/// \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.
-void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D) {
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- MarkVariableReferenced(Loc, VD);
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- MarkFunctionReferenced(Loc, FD);
- else
- D->setReferenced();
+void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) {
+ if (OdrUse) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ MarkVariableReferenced(Loc, VD);
+ return;
+ }
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ MarkFunctionReferenced(Loc, FD);
+ return;
+ }
+ }
+ D->setReferenced();
}
namespace {
@@ -11161,7 +11455,7 @@ bool MarkReferencedDecls::TraverseTemplateArgument(
const TemplateArgument &Arg) {
if (Arg.getKind() == TemplateArgument::Declaration) {
if (Decl *D = Arg.getAsDecl())
- S.MarkAnyDeclReferenced(Loc, D);
+ S.MarkAnyDeclReferenced(Loc, D, true);
}
return Inherited::TraverseTemplateArgument(Arg);
@@ -11685,10 +11979,11 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
// Rebuild the function type, replacing the result type with DestType.
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType))
- DestType = S.Context.getFunctionType(DestType,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- Proto->getExtProtoInfo());
+ DestType =
+ S.Context.getFunctionType(DestType,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ Proto->getExtProtoInfo());
else
DestType = S.Context.getFunctionNoProtoType(DestType,
FnType->getExtInfo());
@@ -11850,6 +12145,29 @@ ExprResult Sema::forceUnknownAnyToType(Expr *E, QualType ToType) {
return RebuildUnknownAnyExpr(*this, ToType).Visit(E);
}
+ExprResult Sema::checkUnknownAnyArg(SourceLocation callLoc,
+ Expr *arg, QualType &paramType) {
+ // If the syntactic form of the argument is not an explicit cast of
+ // any sort, just do default argument promotion.
+ ExplicitCastExpr *castArg = dyn_cast<ExplicitCastExpr>(arg->IgnoreParens());
+ if (!castArg) {
+ ExprResult result = DefaultArgumentPromotion(arg);
+ if (result.isInvalid()) return ExprError();
+ paramType = result.get()->getType();
+ return result;
+ }
+
+ // Otherwise, use the type that was written in the explicit cast.
+ assert(!arg->hasPlaceholderType());
+ paramType = castArg->getTypeAsWritten();
+
+ // Copy-initialize a parameter of that type.
+ InitializedEntity entity =
+ InitializedEntity::InitializeParameter(Context, paramType,
+ /*consumed*/ false);
+ return PerformCopyInitialization(entity, callLoc, Owned(arg));
+}
+
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
Expr *orig = E;
unsigned diagID = diag::err_uncasted_use_of_unknown_any;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 0919bc5b6fa4..3f2cb026730d 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -13,30 +13,68 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/TemplateDeduction.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "TypeLocBuilder.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace sema;
+/// \brief Handle the result of the special case name lookup for inheriting
+/// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as
+/// constructor names in member using declarations, even if 'X' is not the
+/// name of the corresponding type.
+ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS,
+ SourceLocation NameLoc,
+ IdentifierInfo &Name) {
+ NestedNameSpecifier *NNS = SS.getScopeRep();
+
+ // Convert the nested-name-specifier into a type.
+ QualType Type;
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ Type = QualType(NNS->getAsType(), 0);
+ break;
+
+ case NestedNameSpecifier::Identifier:
+ // Strip off the last layer of the nested-name-specifier and build a
+ // typename type for it.
+ assert(NNS->getAsIdentifier() == &Name && "not a constructor name");
+ Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(),
+ NNS->getAsIdentifier());
+ break;
+
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ llvm_unreachable("Nested name specifier is not a type for inheriting ctor");
+ }
+
+ // This reference to the type is located entirely at the location of the
+ // final identifier in the qualified-id.
+ return CreateParsedType(Type,
+ Context.getTrivialTypeSourceInfo(Type, NameLoc));
+}
+
ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II,
SourceLocation NameLoc,
@@ -263,8 +301,16 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
} else if (ObjectTypePtr)
Diag(NameLoc, diag::err_ident_in_dtor_not_a_type)
<< &II;
- else
- Diag(NameLoc, diag::err_destructor_class_name);
+ else {
+ SemaDiagnosticBuilder DtorDiag = Diag(NameLoc,
+ diag::err_destructor_class_name);
+ if (S) {
+ const DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx))
+ DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ Class->getNameAsString());
+ }
+ }
return ParsedType();
}
@@ -336,7 +382,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
if (RecordD->isPolymorphic() && E->isGLValue()) {
// The subexpression is potentially evaluated; switch the context
// and recheck the subexpression.
- ExprResult Result = TranformToPotentiallyEvaluated(E);
+ ExprResult Result = TransformToPotentiallyEvaluated(E);
if (Result.isInvalid()) return ExprError();
E = Result.take();
@@ -1041,13 +1087,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
} else if (Initializer && isa<InitListExpr>(Initializer))
initStyle = CXXNewExpr::ListInit;
else {
- // In template instantiation, the initializer could be a CXXDefaultArgExpr
- // unwrapped from a CXXConstructExpr that was implicitly built. There is no
- // particularly sane way we can handle this (especially since it can even
- // occur for array new), so we throw the initializer away and have it be
- // rebuilt.
- if (Initializer && isa<CXXDefaultArgExpr>(Initializer))
- Initializer = 0;
assert((!Initializer || isa<ImplicitValueInitExpr>(Initializer) ||
isa<CXXConstructExpr>(Initializer)) &&
"Initializer expression that cannot have been implicitly created.");
@@ -1056,20 +1095,20 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
Expr **Inits = &Initializer;
unsigned NumInits = Initializer ? 1 : 0;
- if (initStyle == CXXNewExpr::CallInit) {
- if (ParenListExpr *List = dyn_cast<ParenListExpr>(Initializer)) {
- Inits = List->getExprs();
- NumInits = List->getNumExprs();
- } else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Initializer)){
- if (!isa<CXXTemporaryObjectExpr>(CCE)) {
- // Can happen in template instantiation. Since this is just an implicit
- // construction, we just take it apart and rebuild it.
- Inits = CCE->getArgs();
- NumInits = CCE->getNumArgs();
- }
- }
+ if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
+ assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init");
+ Inits = List->getExprs();
+ 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.
AutoType *AT = 0;
if (TypeMayContainAuto &&
@@ -1147,7 +1186,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) {
return S.Diag(Loc, diag::err_array_size_not_integral)
- << S.getLangOpts().CPlusPlus0x << T;
+ << S.getLangOpts().CPlusPlus11 << T;
}
virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
@@ -1185,7 +1224,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
QualType T,
QualType ConvTy) {
return S.Diag(Loc,
- S.getLangOpts().CPlusPlus0x
+ S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_array_size_conversion
: diag::ext_array_size_conversion)
<< T << ConvTy->isEnumeralType() << ConvTy;
@@ -1221,7 +1260,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (Value < llvm::APSInt(
llvm::APInt::getNullValue(Value.getBitWidth()),
Value.isUnsigned())) {
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
Diag(ArraySize->getLocStart(),
diag::warn_typecheck_negative_array_new_size)
<< ArraySize->getSourceRange();
@@ -1233,7 +1272,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
unsigned ActiveSizeBits =
ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
Diag(ArraySize->getLocStart(),
diag::warn_array_new_too_large)
<< Value.toString(10)
@@ -1341,9 +1380,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
}
+ // If we can perform the initialization, and we've not already done so,
+ // do it now.
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Inits, NumInits))) {
+ llvm::makeArrayRef(Inits, NumInits)) &&
+ !HaveCompleteInit) {
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
@@ -1379,10 +1421,14 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
// Mark the new and delete operators as referenced.
- if (OperatorNew)
+ if (OperatorNew) {
+ DiagnoseUseOfDecl(OperatorNew, StartLoc);
MarkFunctionReferenced(StartLoc, OperatorNew);
- if (OperatorDelete)
+ }
+ if (OperatorDelete) {
+ DiagnoseUseOfDecl(OperatorDelete, StartLoc);
MarkFunctionReferenced(StartLoc, OperatorDelete);
+ }
// C++0x [expr.new]p17:
// If the new expression creates an array of objects of class type,
@@ -1594,8 +1640,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
EPI.Variadic = Proto->isVariadic();
ExpectedFunctionType
- = Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
- ArgTypes.size(), EPI);
+ = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI);
}
for (LookupResult::iterator D = FoundDelete.begin(),
@@ -1641,7 +1686,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// as a placement deallocation function, would have been
// selected as a match for the allocation function, the program
// is ill-formed.
- if (NumPlaceArgs && getLangOpts().CPlusPlus0x &&
+ if (NumPlaceArgs && getLangOpts().CPlusPlus11 &&
isNonPlacementDeallocationFunction(OperatorDelete)) {
Diag(StartLoc, diag::err_placement_new_non_placement_delete)
<< SourceRange(PlaceArgs[0]->getLocStart(),
@@ -1817,7 +1862,7 @@ void Sema::DeclareGlobalNewDelete() {
// lookup.
// Note that the C++0x versions of operator delete are deallocation functions,
// and thus are implicitly noexcept.
- if (!StdBadAlloc && !getLangOpts().CPlusPlus0x) {
+ if (!StdBadAlloc && !getLangOpts().CPlusPlus11) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class,
@@ -1857,8 +1902,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// Check if this function is already declared.
{
- DeclContext::lookup_iterator Alloc, AllocEnd;
- for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Name);
+ DeclContext::lookup_result R = GlobalCtx->lookup(Name);
+ for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Only look at non-template functions, as it is the predefined,
// non-templated allocation function we are trying to declare here.
@@ -1880,29 +1925,28 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool HasBadAllocExceptionSpec
= (Name.getCXXOverloadedOperator() == OO_New ||
Name.getCXXOverloadedOperator() == OO_Array_New);
- if (HasBadAllocExceptionSpec && !getLangOpts().CPlusPlus0x) {
+ if (HasBadAllocExceptionSpec && !getLangOpts().CPlusPlus11) {
assert(StdBadAlloc && "Must have std::bad_alloc declared");
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
}
FunctionProtoType::ExtProtoInfo EPI;
if (HasBadAllocExceptionSpec) {
- if (!getLangOpts().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus11) {
EPI.ExceptionSpecType = EST_Dynamic;
EPI.NumExceptions = 1;
EPI.Exceptions = &BadAllocType;
}
} else {
- EPI.ExceptionSpecType = getLangOpts().CPlusPlus0x ?
+ EPI.ExceptionSpecType = getLangOpts().CPlusPlus11 ?
EST_BasicNoexcept : EST_DynamicNone;
}
- QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI);
+ QualType FnType = Context.getFunctionType(Return, Argument, EPI);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
SourceLocation(), Name,
- FnType, /*TInfo=*/0, SC_None,
- SC_None, false, true);
+ FnType, /*TInfo=*/0, SC_None, false, true);
Alloc->setImplicit();
if (AddMallocAttr)
@@ -1911,7 +1955,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
SourceLocation(), 0,
Argument, /*TInfo=*/0,
- SC_None, SC_None, 0);
+ SC_None, 0);
Alloc->setParams(Param);
// FIXME: Also add this declaration to the IdentifierResolver, but
@@ -2030,6 +2074,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!Ex.get()->isTypeDependent()) {
// Perform lvalue-to-rvalue cast, if needed.
Ex = DefaultLvalueConversion(Ex.take());
+ if (Ex.isInvalid())
+ return ExprError();
QualType Type = Ex.get()->getType();
@@ -2041,9 +2087,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = RD->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -2323,11 +2371,11 @@ static ExprResult BuildCXXCastArgument(Sema &S,
S.CheckConstructorAccess(CastLoc, Constructor,
InitializedEntity::InitializeTemporary(Ty),
Constructor->getAccess());
-
+
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- ConstructorArgs,
- HadMultipleCandidates, /*ZeroInit*/ false,
+ ConstructorArgs, HadMultipleCandidates,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
return ExprError();
@@ -2479,14 +2527,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ToType, SCS.CopyConstructor,
ConstructorArgs,
/*HadMultipleCandidates*/ false,
- /*ZeroInit*/ false,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
}
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
From, /*HadMultipleCandidates*/ false,
- /*ZeroInit*/ false,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
}
@@ -2782,6 +2830,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
}
+ case ICK_Zero_Event_Conversion:
+ From = ImpCastExprToType(From, ToType,
+ CK_ZeroToOCLEvent,
+ From->getValueKind()).take();
+ break;
+
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
case ICK_Function_To_Pointer:
@@ -2920,10 +2974,13 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
// type due to the overarching C++0x type predicates being implemented
// requiring the complete type.
case UTT_HasNothrowAssign:
+ case UTT_HasNothrowMoveAssign:
case UTT_HasNothrowConstructor:
case UTT_HasNothrowCopy:
case UTT_HasTrivialAssign:
+ case UTT_HasTrivialMoveAssign:
case UTT_HasTrivialDefaultConstructor:
+ case UTT_HasTrivialMoveConstructor:
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
@@ -2942,6 +2999,42 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
llvm_unreachable("Type trait not handled by switch");
}
+static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
+ Sema &Self, SourceLocation KeyLoc, ASTContext &C,
+ bool (CXXRecordDecl::*HasTrivial)() const,
+ bool (CXXRecordDecl::*HasNonTrivial)() const,
+ bool (CXXMethodDecl::*IsDesiredOp)() const)
+{
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
+ return true;
+
+ DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op);
+ DeclarationNameInfo NameInfo(Name, KeyLoc);
+ LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName);
+ if (Self.LookupQualifiedName(Res, RD)) {
+ bool FoundOperator = false;
+ Res.suppressDiagnostics();
+ for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
+ Op != OpEnd; ++Op) {
+ if (isa<FunctionTemplateDecl>(*Op))
+ continue;
+
+ CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
+ if((Operator->*IsDesiredOp)()) {
+ FoundOperator = true;
+ const FunctionProtoType *CPT =
+ Operator->getType()->getAs<FunctionProtoType>();
+ CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+ if (!CPT || !CPT->isNothrow(Self.Context))
+ return false;
+ }
+ }
+ return FoundOperator;
+ }
+ return false;
+}
+
static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
SourceLocation KeyLoc, QualType T) {
assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
@@ -3060,6 +3153,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
//
// 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
// 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+ //
+ // Note that these builtins do not behave as documented in g++: if a class
+ // has both a trivial and a non-trivial special member of a particular kind,
+ // they return false! For now, we emulate this behavior.
+ // FIXME: This appears to be a g++ bug: more complex cases reveal that it
+ // does not correctly compute triviality in the presence of multiple special
+ // members of the same kind. Revisit this once the g++ bug is fixed.
case UTT_HasTrivialDefaultConstructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If __is_pod (type) is true then the trait is true, else if type is
@@ -3067,9 +3167,18 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// constructor ([class.ctor]) then the trait is true, else it is false.
if (T.isPODType(Self.Context))
return true;
- if (const RecordType *RT =
- C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor();
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialDefaultConstructor() &&
+ !RD->hasNonTrivialDefaultConstructor();
+ return false;
+ case UTT_HasTrivialMoveConstructor:
+ // This trait is implemented by MSVC 2012 and needed to parse the
+ // standard library headers. Specifically this is used as the logic
+ // behind std::is_trivially_move_constructible (20.9.4.3).
+ if (T.isPODType(Self.Context))
+ return true;
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor();
return false;
case UTT_HasTrivialCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3079,8 +3188,18 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// is true, else it is false.
if (T.isPODType(Self.Context) || T->isReferenceType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasTrivialCopyConstructor() &&
+ !RD->hasNonTrivialCopyConstructor();
+ return false;
+ case UTT_HasTrivialMoveAssign:
+ // This trait is implemented by MSVC 2012 and needed to parse the
+ // standard library headers. Specifically it is used as the logic
+ // behind std::is_trivially_move_assignable (20.9.4.3)
+ if (T.isPODType(Self.Context))
+ return true;
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment();
return false;
case UTT_HasTrivialAssign:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3095,12 +3214,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// errors if the copy assignment operator is actually used, q.v.
// [class.copy]p12).
- if (C.getBaseElementType(T).isConstQualified())
+ if (T.isConstQualified())
return false;
if (T.isPODType(Self.Context))
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasTrivialCopyAssignment() &&
+ !RD->hasNonTrivialCopyAssignment();
return false;
case UTT_HasTrivialDestructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3117,9 +3237,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
- if (const RecordType *RT =
- C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialDestructor();
return false;
// TODO: Propagate nothrowness for implicitly declared special members.
case UTT_HasNothrowAssign:
@@ -3135,39 +3254,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (T->isReferenceType())
return false;
if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
- return true;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyAssignment())
- return true;
+ return true;
- bool FoundAssign = false;
- DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
- LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
- Sema::LookupOrdinaryName);
- if (Self.LookupQualifiedName(Res, RD)) {
- Res.suppressDiagnostics();
- for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
- Op != OpEnd; ++Op) {
- if (isa<FunctionTemplateDecl>(*Op))
- continue;
-
- CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
- if (Operator->isCopyAssignmentOperator()) {
- FoundAssign = true;
- const FunctionProtoType *CPT
- = Operator->getType()->getAs<FunctionProtoType>();
- CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
- if (!CPT)
- return false;
- if (!CPT->isNothrow(Self.Context))
- return false;
- }
- }
- }
-
- return FoundAssign;
- }
+ if (const RecordType *RT = T->getAs<RecordType>())
+ return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+ &CXXRecordDecl::hasTrivialCopyAssignment,
+ &CXXRecordDecl::hasNonTrivialCopyAssignment,
+ &CXXMethodDecl::isCopyAssignmentOperator);
+ return false;
+ case UTT_HasNothrowMoveAssign:
+ // This trait is implemented by MSVC 2012 and needed to parse the
+ // standard library headers. Specifically this is used as the logic
+ // behind std::is_nothrow_move_assignable (20.9.4.3).
+ if (T.isPODType(Self.Context))
+ return true;
+
+ if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
+ return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+ &CXXRecordDecl::hasTrivialMoveAssignment,
+ &CXXRecordDecl::hasNonTrivialMoveAssignment,
+ &CXXMethodDecl::isMoveAssignmentOperator);
return false;
case UTT_HasNothrowCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3177,16 +3283,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// false.
if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyConstructor())
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialCopyConstructor() &&
+ !RD->hasNonTrivialCopyConstructor())
return true;
bool FoundConstructor = false;
unsigned FoundTQs;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
- Con != ConEnd; ++Con) {
+ DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
+ for (DeclContext::lookup_const_iterator Con = R.begin(),
+ ConEnd = R.end(); Con != ConEnd; ++Con) {
// A template constructor is never a copy constructor.
// FIXME: However, it may actually be selected at the actual overload
// resolution point.
@@ -3218,14 +3324,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// throw an exception then the trait is true, else it is false.
if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDefaultConstructor())
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialDefaultConstructor() &&
+ !RD->hasNonTrivialDefaultConstructor())
return true;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
- Con != ConEnd; ++Con) {
+ DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
+ for (DeclContext::lookup_const_iterator Con = R.begin(),
+ ConEnd = R.end(); Con != ConEnd; ++Con) {
// FIXME: In C++0x, a constructor template can be a default constructor.
if (isa<FunctionTemplateDecl>(*Con))
continue;
@@ -3247,11 +3353,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If type is a class type with a virtual destructor ([class.dtor])
// then the trait is true, else it is false.
- if (const RecordType *Record = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD))
return Destructor->isVirtual();
- }
return false;
// These type trait expressions are modeled on the specifications for the
@@ -3360,8 +3464,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (SawVoid)
return false;
- llvm::SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
- llvm::SmallVector<Expr *, 2> ArgExprs;
+ SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
+ SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
for (unsigned I = 1, N = Args.size(); I != N; ++I) {
QualType T = Args[I]->getType();
@@ -3428,7 +3532,7 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<ParsedType> Args,
SourceLocation RParenLoc) {
- llvm::SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
+ SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
ConvertedArgs.reserve(Args.size());
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
@@ -4769,7 +4873,7 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
// a StmtExpr; currently this is only used for asm statements.
// This is hacky, either create a new CXXStmtWithTemporaries statement or
// a new AsmStmtWithTemporaries.
- CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, &SubStmt, 1,
+ CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, SubStmt,
SourceLocation(),
SourceLocation());
Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
@@ -4782,8 +4886,7 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
/// are omitted for the 'topmost' call in the decltype expression. If the
/// topmost call bound a temporary, strip that temporary off the expression.
ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
- ExpressionEvaluationContextRecord &Rec = ExprEvalContexts.back();
- assert(Rec.IsDecltype && "not in a decltype expression");
+ assert(ExprEvalContexts.back().IsDecltype && "not in a decltype expression");
// C++11 [expr.call]p11:
// If a function call is a prvalue of object type,
@@ -4824,7 +4927,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
E = TopBind->getSubExpr();
// Disable the special decltype handling now.
- Rec.IsDecltype = false;
+ ExprEvalContexts.back().IsDecltype = false;
// In MS mode, don't perform any extra checking of call return types within a
// decltype expression.
@@ -4833,8 +4936,9 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
// Perform the semantic checks we delayed until this point.
CallExpr *TopCall = dyn_cast<CallExpr>(E);
- for (unsigned I = 0, N = Rec.DelayedDecltypeCalls.size(); I != N; ++I) {
- CallExpr *Call = Rec.DelayedDecltypeCalls[I];
+ for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size();
+ I != N; ++I) {
+ CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I];
if (Call == TopCall)
continue;
@@ -4846,8 +4950,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
// Now all relevant types are complete, check the destructors are accessible
// and non-deleted, and annotate them on the temporaries.
- for (unsigned I = 0, N = Rec.DelayedDecltypeBinds.size(); I != N; ++I) {
- CXXBindTemporaryExpr *Bind = Rec.DelayedDecltypeBinds[I];
+ for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeBinds.size();
+ I != N; ++I) {
+ CXXBindTemporaryExpr *Bind =
+ ExprEvalContexts.back().DelayedDecltypeBinds[I];
if (Bind == TopBind)
continue;
@@ -5321,12 +5427,12 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
VK_RValue, OK_Ordinary);
if (HadMultipleCandidates)
ME->setHadMultipleCandidates(true);
+ MarkMemberReferenced(ME);
QualType ResultType = Method->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
- MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK,
Exp.get()->getLocEnd());
@@ -5429,7 +5535,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// normally, we don't need to do anything to handle it, but if it is a
// volatile lvalue with a special form, we perform an lvalue-to-rvalue
// conversion.
- if (getLangOpts().CPlusPlus0x && E->isGLValue() &&
+ if (getLangOpts().CPlusPlus11 && E->isGLValue() &&
E->getType().isVolatileQualified() &&
IsSpecialDiscardedValue(E)) {
ExprResult Res = DefaultLvalueConversion(E);
@@ -5460,7 +5566,9 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return Owned(E);
}
-ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC) {
+ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
+ bool DiscardedValue,
+ bool IsConstexpr) {
ExprResult FullExpr = Owned(FE);
if (!FullExpr.get())
@@ -5469,24 +5577,25 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC) {
if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
- // Top-level message sends default to 'id' when we're in a debugger.
- if (getLangOpts().DebuggerCastResultToId &&
- FullExpr.get()->getType() == Context.UnknownAnyTy &&
- isa<ObjCMessageExpr>(FullExpr.get())) {
+ // 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());
if (FullExpr.isInvalid())
return ExprError();
}
-
- FullExpr = CheckPlaceholderExpr(FullExpr.take());
- if (FullExpr.isInvalid())
- return ExprError();
- FullExpr = IgnoredValueConversions(FullExpr.take());
- if (FullExpr.isInvalid())
- return ExprError();
+ if (DiscardedValue) {
+ FullExpr = CheckPlaceholderExpr(FullExpr.take());
+ if (FullExpr.isInvalid())
+ return ExprError();
+
+ FullExpr = IgnoredValueConversions(FullExpr.take());
+ if (FullExpr.isInvalid())
+ return ExprError();
+ }
- CheckImplicitConversions(FullExpr.get(), CC);
+ CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index a7fd47183a16..847db24632b9 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -11,43 +11,32 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
using namespace clang;
using namespace sema;
+typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> BaseSet;
+static bool BaseIsNotInSet(const CXXRecordDecl *Base, void *BasesPtr) {
+ const BaseSet &Bases = *reinterpret_cast<const BaseSet*>(BasesPtr);
+ return !Bases.count(Base->getCanonicalDecl());
+}
+
/// Determines if the given class is provably not derived from all of
/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
+static bool isProvablyNotDerivedFrom(Sema &SemaRef, CXXRecordDecl *Record,
+ const BaseSet &Bases) {
+ void *BasesPtr = const_cast<void*>(reinterpret_cast<const void*>(&Bases));
+ return BaseIsNotInSet(Record, BasesPtr) &&
+ Record->forallBases(BaseIsNotInSet, BasesPtr);
}
enum IMAKind {
@@ -111,7 +100,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
bool isField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ BaseSet Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -132,7 +121,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
return IMA_Static;
bool IsCXX11UnevaluatedField = false;
- if (SemaRef.getLangOpts().CPlusPlus0x && isField) {
+ if (SemaRef.getLangOpts().CPlusPlus11 && isField) {
// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
@@ -169,16 +158,18 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// is ill-formed.
if (R.getNamingClass() &&
contextClass->getCanonicalDecl() !=
- R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return hasNonInstance ? IMA_Mixed_Unrelated :
- IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
- IMA_Error_Unrelated;
+ R.getNamingClass()->getCanonicalDecl()) {
+ // If the naming class is not the current context, this was a qualified
+ // member name lookup, and it's sufficient to check that we have the naming
+ // class as a base class.
+ Classes.clear();
+ Classes.insert(R.getNamingClass()->getCanonicalDecl());
+ }
// If we can prove that the current context is unrelated to all the
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
+ if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
return hasNonInstance ? IMA_Mixed_Unrelated :
IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
IMA_Error_Unrelated;
@@ -491,14 +482,14 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
QualType BaseType,
const CXXScopeSpec &SS,
const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
+ CXXRecordDecl *BaseRecord =
+ cast_or_null<CXXRecordDecl>(computeDeclContext(BaseType));
+ if (!BaseRecord) {
// We can't check this yet because the base type is still
// dependent.
assert(BaseType->isDependentType());
return false;
}
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
// If this is an implicit member reference and we find a
@@ -513,11 +504,10 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
if (!DC->isRecord())
continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ CXXRecordDecl *MemberRecord = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ if (BaseRecord->getCanonicalDecl() == MemberRecord ||
+ !BaseRecord->isProvablyNotDerivedFrom(MemberRecord))
return false;
}
@@ -1140,30 +1130,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// 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")) {
- Diag(MemberLoc, diag::warn_objc_isa_use);
+ 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,
ObjCImpDecl, HasTemplateArgs);
goto fail;
}
- else if (Member && Member->isStr("isa")) {
- // If an ivar is (1) the first ivar in a root class and (2) named `isa`,
- // then issue the same deprecated warning that id->isa gets.
- ObjCInterfaceDecl *ClassDeclared = 0;
- if (ObjCIvarDecl *IV =
- IDecl->lookupInstanceVariable(Member, ClassDeclared)) {
- if (!ClassDeclared->getSuperClass()
- && (*ClassDeclared->ivar_begin()) == IV) {
- Diag(MemberLoc, diag::warn_objc_isa_use);
- Diag(IV->getLocation(), diag::note_ivar_decl);
- }
- }
- }
if (RequireCompleteType(OpLoc, BaseType, diag::err_typecheck_incomplete_tag,
BaseExpr.get()))
@@ -1269,14 +1244,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (ObjCMethodDecl *MD = getCurMethodDecl()) {
ObjCMethodFamily MF = MD->getMethodFamily();
warn = (MF != OMF_init && MF != OMF_dealloc &&
- MF != OMF_finalize);
+ MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IDecl, MD, IV));
}
if (warn)
Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc,
+ MemberLoc, OpLoc,
BaseExpr.take(),
IsArrow);
@@ -1607,27 +1583,27 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
} else {
QualType BaseType = BaseExpr->getType();
if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
-
+
Qualifiers BaseQuals = BaseType.getQualifiers();
-
+
// GC attributes are never picked up by members.
BaseQuals.removeObjCGCAttr();
-
+
// CVR attributes from the base are picked up by members,
// except that 'mutable' members don't pick up 'const'.
if (Field->isMutable()) BaseQuals.removeConst();
-
+
Qualifiers MemberQuals
= S.Context.getCanonicalType(MemberType).getQualifiers();
-
- // TR 18037 does not allow fields to be declared with address spaces.
+
assert(!MemberQuals.hasAddressSpace());
-
+
+
Qualifiers Combined = BaseQuals + MemberQuals;
if (Combined != MemberQuals)
MemberType = S.Context.getQualifiedType(MemberType, Combined);
}
-
+
S.UnusedPrivateFields.remove(Field);
ExprResult Base =
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index e43b6bff5586..e7b5ec9b0168 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -12,20 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/Edit/Rewriters.h"
-#include "clang/Edit/Commit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/Rewriters.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/SmallString.h"
using namespace clang;
using namespace sema;
@@ -170,9 +170,9 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
QualType NumberType,
bool isLiteral = false,
SourceRange R = SourceRange()) {
- llvm::Optional<NSAPI::NSNumberLiteralMethodKind> Kind
- = S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
-
+ Optional<NSAPI::NSNumberLiteralMethodKind> Kind =
+ S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
+
if (!Kind) {
if (isLiteral) {
S.Diag(Loc, diag::err_invalid_nsnumber_type)
@@ -238,7 +238,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
SourceLocation(), SourceLocation(),
&CX.Idents.get("value"),
NumberType, /*TInfo=*/0, SC_None,
- SC_None, 0);
+ 0);
Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>());
}
@@ -489,7 +489,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
&Context.Idents.get("value"),
Context.getPointerType(ConstCharType),
/*TInfo=*/0,
- SC_None, SC_None, 0);
+ SC_None, 0);
M->setMethodParams(Context, value, ArrayRef<SourceLocation>());
BoxingMethod = M;
}
@@ -656,16 +656,14 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
SourceLocation(),
&Context.Idents.get("objects"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(objects);
ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("cnt"),
Context.UnsignedLongTy,
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(cnt);
Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>());
}
@@ -774,24 +772,21 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
SourceLocation(),
&Context.Idents.get("objects"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(objects);
ParmVarDecl *keys = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("keys"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(keys);
ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("cnt"),
Context.UnsignedLongTy,
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(cnt);
Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>());
}
@@ -981,7 +976,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
llvm::DenseMap<Selector, SourceLocation>::iterator Pos
= ReferencedSelectors.find(Sel);
if (Pos == ReferencedSelectors.end())
- ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
+ ReferencedSelectors.insert(std::make_pair(Sel, AtLoc));
}
// In ARC, forbid the user from using @selector for
@@ -1094,6 +1089,73 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType,
return ReceiverType;
}
+/// Look for an ObjC method whose result type exactly matches the given type.
+static const ObjCMethodDecl *
+findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD,
+ QualType instancetype) {
+ if (MD->getResultType() == instancetype) return MD;
+
+ // For these purposes, a method in an @implementation overrides a
+ // declaration in the @interface.
+ if (const ObjCImplDecl *impl =
+ dyn_cast<ObjCImplDecl>(MD->getDeclContext())) {
+ const ObjCContainerDecl *iface;
+ if (const ObjCCategoryImplDecl *catImpl =
+ dyn_cast<ObjCCategoryImplDecl>(impl)) {
+ iface = catImpl->getCategoryDecl();
+ } else {
+ iface = impl->getClassInterface();
+ }
+
+ const ObjCMethodDecl *ifaceMD =
+ iface->getMethod(MD->getSelector(), MD->isInstanceMethod());
+ if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype);
+ }
+
+ SmallVector<const ObjCMethodDecl *, 4> overrides;
+ MD->getOverriddenMethods(overrides);
+ for (unsigned i = 0, e = overrides.size(); i != e; ++i) {
+ if (const ObjCMethodDecl *result =
+ findExplicitInstancetypeDeclarer(overrides[i], instancetype))
+ return result;
+ }
+
+ return 0;
+}
+
+void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
+ // Only complain if we're in an ObjC method and the required return
+ // 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()))
+ return;
+
+ // Look for a method overridden by this method which explicitly uses
+ // 'instancetype'.
+ if (const ObjCMethodDecl *overridden =
+ findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) {
+ SourceLocation loc;
+ SourceRange range;
+ if (TypeSourceInfo *TSI = overridden->getResultTypeSourceInfo()) {
+ range = TSI->getTypeLoc().getSourceRange();
+ loc = range.getBegin();
+ }
+ if (loc.isInvalid())
+ loc = overridden->getLocation();
+ Diag(loc, diag::note_related_result_type_explicit)
+ << /*current method*/ 1 << range;
+ return;
+ }
+
+ // Otherwise, if we have an interesting method family, note that.
+ // This should always trigger if the above didn't.
+ if (ObjCMethodFamily family = MD->getMethodFamily())
+ Diag(MD->getLocation(), diag::note_related_result_type_family)
+ << /*current method*/ 1
+ << family;
+}
+
void Sema::EmitRelatedResultTypeNote(const Expr *E) {
E = E->IgnoreParenImpCasts();
const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
@@ -1135,10 +1197,16 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (Args[i]->isTypeDependent())
continue;
- ExprResult Result = DefaultArgumentPromotion(Args[i]);
- if (Result.isInvalid())
+ ExprResult result;
+ if (getLangOpts().DebuggerSupport) {
+ QualType paramTy; // ignored
+ result = checkUnknownAnyArg(lbrac, Args[i], paramTy);
+ } else {
+ result = DefaultArgumentPromotion(Args[i]);
+ }
+ if (result.isInvalid())
return true;
- Args[i] = Result.take();
+ Args[i] = result.take();
}
unsigned DiagID;
@@ -1196,6 +1264,22 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
!param->hasAttr<CFConsumedAttr>())
argExpr = stripARCUnbridgedCast(argExpr);
+ // If the parameter is __unknown_anytype, infer its type
+ // from the argument.
+ if (param->getType() == Context.UnknownAnyTy) {
+ QualType paramType;
+ ExprResult argE = checkUnknownAnyArg(lbrac, argExpr, paramType);
+ if (argE.isInvalid()) {
+ IsError = true;
+ } else {
+ Args[i] = argE.take();
+
+ // Update the parameter type in-place.
+ param->setType(paramType);
+ }
+ continue;
+ }
+
if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
param->getType(),
diag::err_call_incomplete_argument, argExpr))
@@ -1539,8 +1623,15 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
if (CurMethod->isInstanceMethod()) {
- QualType T =
- Context.getObjCInterfaceType(CurMethod->getClassInterface());
+ ObjCInterfaceDecl *Super =
+ CurMethod->getClassInterface()->getSuperClass();
+ if (!Super) {
+ // The current class does not have a superclass.
+ Diag(receiverNameLoc, diag::error_root_class_cannot_use_super)
+ << CurMethod->getClassInterface()->getIdentifier();
+ return ExprError();
+ }
+ QualType T = Context.getObjCInterfaceType(Super);
T = Context.getObjCObjectPointerType(T);
return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
@@ -1695,9 +1786,11 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
QualType T;
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
T = Context.getObjCInterfaceType(Class);
- else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) {
T = Context.getTypeDeclType(Type);
- else
+ DiagnoseUseOfDecl(Type, NameLoc);
+ }
+ else
return ObjCInstanceMessage;
// We have a class message, and T is the type we're
@@ -2106,8 +2199,46 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return ExprError();
Receiver = Result.take();
ReceiverType = Receiver->getType();
+
+ // If the receiver is an ObjC pointer, a block pointer, or an
+ // __attribute__((NSObject)) pointer, we don't need to do any
+ // special conversion in order to look up a receiver.
+ if (ReceiverType->isObjCRetainableType()) {
+ // do nothing
+ } else if (!getLangOpts().ObjCAutoRefCount &&
+ !Context.getObjCIdType().isNull() &&
+ (ReceiverType->isPointerType() ||
+ ReceiverType->isIntegerType())) {
+ // Implicitly convert integers and pointers to 'id' but emit a warning.
+ // But not in ARC.
+ Diag(Loc, diag::warn_bad_receiver_type)
+ << ReceiverType
+ << Receiver->getSourceRange();
+ if (ReceiverType->isPointerType()) {
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CK_CPointerToObjCPointerCast).take();
+ } 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();
+ }
+ ReceiverType = Receiver->getType();
+ } else if (getLangOpts().CPlusPlus) {
+ ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
+ if (result.isUsable()) {
+ Receiver = result.take();
+ ReceiverType = Receiver->getType();
+ }
+ }
}
+ // There's a somewhat weird interaction here where we assume that we
+ // won't actually have a method unless we also don't need to do some
+ // of the more detailed type-checking on the receiver.
+
if (!Method) {
// Handle messages to id.
bool receiverIsId = ReceiverType->isObjCIdType();
@@ -2223,7 +2354,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method && getLangOpts().ObjCAutoRefCount) {
Diag(Loc, diag::err_arc_may_not_respond)
- << OCIType->getPointeeType() << Sel;
+ << OCIType->getPointeeType() << Sel
+ << SourceRange(SelectorLocs.front(), SelectorLocs.back());
return ExprError();
}
@@ -2242,48 +2374,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
return ExprError();
- } else if (!getLangOpts().ObjCAutoRefCount &&
- !Context.getObjCIdType().isNull() &&
- (ReceiverType->isPointerType() ||
- ReceiverType->isIntegerType())) {
- // Implicitly convert integers and pointers to 'id' but emit a warning.
- // But not in ARC.
- Diag(Loc, diag::warn_bad_receiver_type)
- << ReceiverType
- << Receiver->getSourceRange();
- if (ReceiverType->isPointerType())
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_CPointerToObjCPointerCast).take();
- 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();
- }
- ReceiverType = Receiver->getType();
} else {
- ExprResult ReceiverRes;
- if (getLangOpts().CPlusPlus)
- ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver);
- if (ReceiverRes.isUsable()) {
- Receiver = ReceiverRes.take();
- return BuildInstanceMessage(Receiver,
- ReceiverType,
- SuperLoc,
- Sel,
- Method,
- LBracLoc,
- SelectorLocs,
- RBracLoc,
- ArgsIn);
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(Loc, diag::err_bad_receiver_type)
- << ReceiverType << Receiver->getSourceRange();
- return ExprError();
- }
+ // Reject other random receiver types (e.g. structs).
+ Diag(Loc, diag::err_bad_receiver_type)
+ << ReceiverType << Receiver->getSourceRange();
+ return ExprError();
}
}
}
@@ -2447,6 +2542,18 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return MaybeBindToTemporary(Result);
}
+static void RemoveSelectorFromWarningCache(Sema &S, Expr* Arg) {
+ if (ObjCSelectorExpr *OSE =
+ dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) {
+ Selector Sel = OSE->getSelector();
+ SourceLocation Loc = OSE->getAtLoc();
+ llvm::DenseMap<Selector, SourceLocation>::iterator Pos
+ = S.ReferencedSelectors.find(Sel);
+ if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc)
+ S.ReferencedSelectors.erase(Pos);
+ }
+}
+
// ActOnInstanceMessage - used for both unary and keyword messages.
// ArgExprs is optional - if it is present, the number of expressions
// is obtained from Sel.getNumArgs().
@@ -2460,6 +2567,20 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
if (!Receiver)
return ExprError();
+ // A ParenListExpr can show up while doing error recovery with invalid code.
+ if (isa<ParenListExpr>(Receiver)) {
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Receiver);
+ if (Result.isInvalid()) return ExprError();
+ Receiver = Result.take();
+ }
+
+ if (RespondsToSelectorSel.isNull()) {
+ IdentifierInfo *SelectorId = &Context.Idents.get("respondsToSelector");
+ RespondsToSelectorSel = Context.Selectors.getUnarySelector(SelectorId);
+ }
+ if (Sel == RespondsToSelectorSel)
+ RemoveSelectorFromWarningCache(*this, Args[0]);
+
return BuildInstanceMessage(Receiver, Receiver->getType(),
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
LBracLoc, SelectorLocs, RBracLoc, Args);
@@ -2770,19 +2891,36 @@ static void addFixitForObjCARCConversion(Sema &S,
SourceLocation afterLParen,
QualType castType,
Expr *castExpr,
+ Expr *realCast,
const char *bridgeKeyword,
const char *CFBridgeName) {
// We handle C-style and implicit casts here.
switch (CCK) {
case Sema::CCK_ImplicitConversion:
case Sema::CCK_CStyleCast:
+ case Sema::CCK_OtherCast:
break;
case Sema::CCK_FunctionalCast:
- case Sema::CCK_OtherCast:
return;
}
if (CFBridgeName) {
+ if (CCK == Sema::CCK_OtherCast) {
+ if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
+ SourceRange range(NCE->getOperatorLoc(),
+ NCE->getAngleBrackets().getEnd());
+ SmallString<32> BridgeCall;
+
+ SourceManager &SM = S.getSourceManager();
+ char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
+ if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts()))
+ BridgeCall += ' ';
+
+ BridgeCall += CFBridgeName;
+ DiagB.AddFixItHint(FixItHint::CreateReplacement(range, BridgeCall));
+ }
+ return;
+ }
Expr *castedE = castExpr;
if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(castedE))
castedE = CCE->getSubExpr();
@@ -2814,6 +2952,16 @@ static void addFixitForObjCARCConversion(Sema &S,
if (CCK == Sema::CCK_CStyleCast) {
DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword));
+ } else if (CCK == Sema::CCK_OtherCast) {
+ if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
+ std::string castCode = "(";
+ castCode += bridgeKeyword;
+ castCode += castType.getAsString();
+ castCode += ")";
+ SourceRange Range(NCE->getOperatorLoc(),
+ NCE->getAngleBrackets().getEnd());
+ DiagB.AddFixItHint(FixItHint::CreateReplacement(Range, castCode));
+ }
} else {
std::string castCode = "(";
castCode += bridgeKeyword;
@@ -2838,7 +2986,8 @@ static void addFixitForObjCARCConversion(Sema &S,
static void
diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
QualType castType, ARCConversionTypeClass castACTC,
- Expr *castExpr, ARCConversionTypeClass exprACTC,
+ Expr *castExpr, Expr *realCast,
+ ARCConversionTypeClass exprACTC,
Sema::CheckedConversionKind CCK) {
SourceLocation loc =
(castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
@@ -2885,17 +3034,24 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
if (CreateRule != ACC_plusOne)
{
- DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
+ 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, "__bridge ", 0);
+ castType, castExpr, realCast, "__bridge ", 0);
}
if (CreateRule != ACC_plusZero)
{
- DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc,
- diag::note_arc_bridge_transfer)
- << castExprType << br;
+ DiagnosticBuilder DiagB =
+ (CCK == Sema::CCK_OtherCast && !br) ?
+ S.Diag(noteLoc, diag::note_arc_cstyle_bridge_transfer) << castExprType :
+ S.Diag(br ? castExpr->getExprLoc() : noteLoc,
+ diag::note_arc_bridge_transfer)
+ << castExprType << br;
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, "__bridge_transfer ",
+ castType, castExpr, realCast, "__bridge_transfer ",
br ? "CFBridgingRelease" : 0);
}
@@ -2918,17 +3074,23 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
if (CreateRule != ACC_plusOne)
{
- DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
+ 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, "__bridge ", 0);
+ castType, castExpr, realCast, "__bridge ", 0);
}
if (CreateRule != ACC_plusZero)
{
- DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc,
- diag::note_arc_bridge_retained)
- << castType << br;
+ DiagnosticBuilder DiagB =
+ (CCK == Sema::CCK_OtherCast && !br) ?
+ S.Diag(noteLoc, diag::note_arc_cstyle_bridge_retained) << castType :
+ S.Diag(br ? castExpr->getExprLoc() : noteLoc,
+ diag::note_arc_bridge_retained)
+ << castType << br;
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, "__bridge_retained ",
+ castType, castExpr, realCast, "__bridge_retained ",
br ? "CFBridgingRetain" : 0);
}
@@ -3025,7 +3187,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
return ACR_unbridged;
diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, exprACTC, CCK);
+ castExpr, castExpr, exprACTC, CCK);
return ACR_okay;
}
@@ -3060,7 +3222,7 @@ void Sema::diagnoseARCUnbridgedCast(Expr *e) {
assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable);
diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, ACTC_retainable, CCK);
+ castExpr, realCast, ACTC_retainable, CCK);
}
/// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index b61b9307dde9..2a845ba9898b 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -178,7 +178,7 @@ static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S)
if (T.isBooleanType() && S.LangOpts.CPlusPlus)
return "false";
if (T.isPointerType() || T.isMemberPointerType()) {
- if (S.LangOpts.CPlusPlus0x)
+ if (S.LangOpts.CPlusPlus11)
return "nullptr";
if (isMacroDefined(S, "NULL"))
return "NULL";
@@ -205,7 +205,7 @@ std::string Sema::getFixItZeroInitializerForType(QualType T) const {
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
if (!RD || !RD->hasDefinition())
return std::string();
- if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor())
+ if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
return "{}";
if (RD->isAggregate())
return " = {}";
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3596bbfc725a..63309e376eac 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -11,16 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Designator.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
@@ -901,11 +901,11 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
if (Index >= IList->getNumInits()) {
if (!VerifyOnly)
SemaRef.Diag(IList->getLocStart(),
- SemaRef.getLangOpts().CPlusPlus0x ?
+ SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_empty_scalar_initializer :
diag::err_empty_scalar_initializer)
<< IList->getSourceRange();
- hadError = !SemaRef.getLangOpts().CPlusPlus0x;
+ hadError = !SemaRef.getLangOpts().CPlusPlus11;
++Index;
++StructuredIndex;
return;
@@ -985,7 +985,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
}
Expr *expr = IList->getInit(Index);
- if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus0x) {
+ if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus11) {
if (!VerifyOnly)
SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
<< DeclType << IList->getSourceRange();
@@ -1632,8 +1632,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
StructuredList = IsFirstDesignator? SyntacticToSemantic.lookup(IList)
: getStructuredSubobjectInit(IList, Index, CurrentObjectType,
StructuredList, StructuredIndex,
- SourceRange(D->getStartLocation(),
- DIE->getSourceRange().getEnd()));
+ SourceRange(D->getLocStart(),
+ DIE->getLocEnd()));
assert(StructuredList && "Expected a structured initializer list");
}
@@ -1706,7 +1706,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// struct/union.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
FieldDecl *ReplacementField = 0;
- if (Lookup.first == Lookup.second) {
+ if (Lookup.empty()) {
// Name lookup didn't find anything. Determine whether this
// was a typo for another field name.
FieldInitializerValidatorCCC Validator(RT->getDecl());
@@ -1739,7 +1739,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Name lookup found something, but it wasn't a field.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
- SemaRef.Diag((*Lookup.first)->getLocation(),
+ SemaRef.Diag(Lookup.front()->getLocation(),
diag::note_field_designator_found);
++Index;
return true;
@@ -1801,10 +1801,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (!VerifyOnly) {
DesignatedInitExpr::Designator *NextD
= DIE->getDesignator(DesigIdx + 1);
- SemaRef.Diag(NextD->getStartLocation(),
+ SemaRef.Diag(NextD->getLocStart(),
diag::err_designator_into_flexible_array_member)
- << SourceRange(NextD->getStartLocation(),
- DIE->getSourceRange().getEnd());
+ << SourceRange(NextD->getLocStart(),
+ DIE->getLocEnd());
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
}
@@ -2424,6 +2424,8 @@ void InitializationSequence::Step::Destroy() {
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
case SK_StdInitializerList:
+ case SK_OCLSamplerInit:
+ case SK_OCLZeroEvent:
break;
case SK_ConversionSequence:
@@ -2652,6 +2654,20 @@ void InitializationSequence::AddStdInitializerListConstructionStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddOCLSamplerInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_OCLSamplerInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddOCLZeroEventStep(QualType T) {
+ Step S;
+ S.Kind = SK_OCLZeroEvent;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
@@ -2744,14 +2760,14 @@ static OverloadingResult
ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
- DeclContext::lookup_iterator Con,
- DeclContext::lookup_iterator ConEnd,
+ ArrayRef<NamedDecl *> Ctors,
OverloadCandidateSet::iterator &Best,
bool CopyInitializing, bool AllowExplicit,
bool OnlyListConstructors, bool InitListSyntax) {
CandidateSet.clear();
- for (; Con != ConEnd; ++Con) {
+ for (ArrayRef<NamedDecl *>::iterator
+ Con = Ctors.begin(), ConEnd = Ctors.end(); Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
bool SuppressUserConversions = false;
@@ -2842,8 +2858,11 @@ static void TryConstructorInitialization(Sema &S,
// - Otherwise, if T is a class type, constructors are considered. The
// applicable constructors are enumerated, and the best one is chosen
// through overload resolution.
- DeclContext::lookup_iterator ConStart, ConEnd;
- llvm::tie(ConStart, ConEnd) = S.LookupConstructors(DestRecordDecl);
+ DeclContext::lookup_result R = S.LookupConstructors(DestRecordDecl);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating (e.g. because of deserialization).
+ // To be safe we copy the lookup results to a new container.
+ SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
OverloadingResult Result = OR_No_Viable_Function;
OverloadCandidateSet::iterator Best;
@@ -2861,11 +2880,9 @@ static void TryConstructorInitialization(Sema &S,
// If the initializer list has no elements and T has a default constructor,
// the first phase is omitted.
- if (ILE->getNumInits() != 0 ||
- (!DestRecordDecl->hasDeclaredDefaultConstructor() &&
- !DestRecordDecl->needsImplicitDefaultConstructor()))
+ if (ILE->getNumInits() != 0 || !DestRecordDecl->hasDefaultConstructor())
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
- CandidateSet, ConStart, ConEnd, Best,
+ CandidateSet, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructor=*/true,
InitListSyntax);
@@ -2883,7 +2900,7 @@ static void TryConstructorInitialization(Sema &S,
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
- CandidateSet, ConStart, ConEnd, Best,
+ CandidateSet, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructors=*/false,
InitListSyntax);
@@ -2983,7 +3000,7 @@ static void TryReferenceListInitialization(Sema &S,
InitializationSequence &Sequence)
{
// First, catch C++03 where this isn't possible.
- if (!S.getLangOpts().CPlusPlus0x) {
+ if (!S.getLangOpts().CPlusPlus11) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
return;
}
@@ -3023,6 +3040,10 @@ static void TryReferenceListInitialization(Sema &S,
Sequence.RewrapReferenceInitList(cv1T1, InitList);
return;
}
+
+ // Update the initializer if we've resolved an overloaded function.
+ if (Sequence.step_begin() != Sequence.step_end())
+ Sequence.RewrapReferenceInitList(cv1T1, InitList);
}
// Not reference-related. Create a temporary and bind to that.
@@ -3067,14 +3088,13 @@ static void TryListInitialization(Sema &S,
// C++11 [dcl.init.list]p3:
// - If T is an aggregate, aggregate initialization is performed.
if (!DestType->isAggregateType()) {
- if (S.getLangOpts().CPlusPlus0x) {
+ if (S.getLangOpts().CPlusPlus11) {
// - Otherwise, if the initializer list has no elements and T is a
// class type with a default constructor, the object is
// value-initialized.
if (InitList->getNumInits() == 0) {
CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
- if (RD->hasDeclaredDefaultConstructor() ||
- RD->needsImplicitDefaultConstructor()) {
+ if (RD->hasDefaultConstructor()) {
TryValueInitialization(S, Entity, Kind, Sequence, InitList);
return;
}
@@ -3099,7 +3119,7 @@ static void TryListInitialization(Sema &S,
InitListChecker CheckInitList(S, Entity, InitList,
DestType, /*VerifyOnly=*/true,
Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus0x);
+ !S.getLangOpts().CPlusPlus11);
if (CheckInitList.HadError()) {
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
return;
@@ -3152,10 +3172,14 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// to see if there is a suitable conversion.
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(T1RecordDecl);
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
+ DeclContext::lookup_result R = S.LookupConstructors(T1RecordDecl);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating (e.g. because of deserialization).
+ // To be safe we copy the lookup results to a new container.
+ SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
+ for (SmallVector<NamedDecl*, 16>::iterator
+ CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
+ NamedDecl *D = *CI;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
// Find the constructor (which may be a template).
@@ -3191,10 +3215,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// functions.
CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = T2RecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -3237,10 +3262,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
return Result;
FunctionDecl *Function = Best->Function;
-
- // This is the overload that will actually be used for the initialization, so
- // mark it as used.
- S.MarkFunctionReferenced(DeclLoc, Function);
+ // This is the overload that will be used for this initialization step if we
+ // use this initialization. Mark it as referenced.
+ Function->setReferenced();
// Compute the returned type of the conversion.
if (isa<CXXConversionDecl>(Function))
@@ -3456,9 +3480,9 @@ static void TryReferenceInitializationCore(Sema &S,
//
// The constructor that would be used to make the copy shall
// be callable whether or not the copy is actually done.
- if (!S.getLangOpts().CPlusPlus0x && !S.getLangOpts().MicrosoftExt)
+ if (!S.getLangOpts().CPlusPlus11 && !S.getLangOpts().MicrosoftExt)
Sequence.AddExtraneousCopyToTemporary(cv2T2);
- else if (S.getLangOpts().CPlusPlus0x)
+ else if (S.getLangOpts().CPlusPlus11)
CheckCXX98CompatAccessibleCopy(S, Entity, Initializer);
}
@@ -3494,6 +3518,14 @@ static void TryReferenceInitializationCore(Sema &S,
return;
}
+ if ((RefRelationship == Sema::Ref_Compatible ||
+ RefRelationship == Sema::Ref_Compatible_With_Added_Qualification) &&
+ isRValueRef && InitCategory.isLValue()) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_RValueReferenceBindingToLValue);
+ return;
+ }
+
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
@@ -3589,7 +3621,7 @@ static void TryValueInitialization(Sema &S,
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
bool NeedZeroInitialization = true;
- if (!S.getLangOpts().CPlusPlus0x) {
+ if (!S.getLangOpts().CPlusPlus11) {
// C++98:
// -- if T is a class type (clause 9) with a user-declared constructor
// (12.1), then the default constructor for T is called (and the
@@ -3616,6 +3648,22 @@ static void TryValueInitialization(Sema &S,
if (NeedZeroInitialization)
Sequence.AddZeroInitializationStep(Entity.getType());
+ // C++03:
+ // -- if T is a non-union class type without a user-declared constructor,
+ // then every non-static data member and base class component of T is
+ // value-initialized;
+ // [...] A program that calls for [...] value-initialization of an
+ // entity of reference type is ill-formed.
+ //
+ // C++11 doesn't need this handling, because value-initialization does not
+ // occur recursively there, and the implicit default constructor is
+ // defined as deleted in the problematic cases.
+ if (!S.getLangOpts().CPlusPlus11 &&
+ ClassDecl->hasUninitializedReferenceMember()) {
+ Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference);
+ return;
+ }
+
// If this is list-value-initialization, pass the empty init list on when
// building the constructor call. This affects the semantics of a few
// things (such as whether an explicit default constructor can be called).
@@ -3700,12 +3748,11 @@ static void TryUserDefinedConversion(Sema &S,
// Try to complete the type we're converting to.
if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- DeclContext::lookup_iterator ConOrig, ConEndOrig;
- llvm::tie(ConOrig, ConEndOrig) = S.LookupConstructors(DestRecordDecl);
+ DeclContext::lookup_result R = S.LookupConstructors(DestRecordDecl);
// The container holding the constructors can under certain conditions
// be changed while iterating. To be safe we copy the lookup results
// to a new container.
- SmallVector<NamedDecl*, 8> CopyOfCon(ConOrig, ConEndOrig);
+ SmallVector<NamedDecl*, 8> CopyOfCon(R.begin(), R.end());
for (SmallVector<NamedDecl*, 8>::iterator
Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
Con != ConEnd; ++Con) {
@@ -3750,11 +3797,11 @@ static void TryUserDefinedConversion(Sema &S,
CXXRecordDecl *SourceRecordDecl
= cast<CXXRecordDecl>(SourceRecordType->getDecl());
- const UnresolvedSetImpl *Conversions
- = SourceRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = SourceRecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -3791,7 +3838,7 @@ static void TryUserDefinedConversion(Sema &S,
}
FunctionDecl *Function = Best->Function;
- S.MarkFunctionReferenced(DeclLoc, Function);
+ Function->setReferenced();
bool HadMultipleCandidates = (CandidateSet.size() > 1);
if (isa<CXXConstructorDecl>(Function)) {
@@ -3837,14 +3884,15 @@ enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
/// Determines whether this expression is an acceptable ICR source.
static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
- bool isAddressOf) {
+ bool isAddressOf, bool &isWeakAccess) {
// Skip parens.
e = e->IgnoreParens();
// Skip address-of nodes.
if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
if (op->getOpcode() == UO_AddrOf)
- return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true);
+ return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true,
+ isWeakAccess);
// Skip certain casts.
} else if (CastExpr *ce = dyn_cast<CastExpr>(e)) {
@@ -3853,7 +3901,7 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
case CK_BitCast:
case CK_LValueBitCast:
case CK_NoOp:
- return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf);
+ return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf, isWeakAccess);
case CK_ArrayToPointerDecay:
return IIK_nonscalar;
@@ -3867,6 +3915,11 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
// If we have a declaration reference, it had better be a local variable.
} else if (isa<DeclRefExpr>(e)) {
+ // set isWeakAccess to true, to mean that there will be an implicit
+ // load which requires a cleanup.
+ if (e->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ isWeakAccess = true;
+
if (!isAddressOf) return IIK_nonlocal;
VarDecl *var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
@@ -3876,10 +3929,11 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
// If we have a conditional operator, check both sides.
} else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
- if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf))
+ if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf,
+ isWeakAccess))
return iik;
- return isInvalidICRSource(C, cond->getRHS(), isAddressOf);
+ return isInvalidICRSource(C, cond->getRHS(), isAddressOf, isWeakAccess);
// These are never scalar.
} else if (isa<ArraySubscriptExpr>(e)) {
@@ -3898,8 +3952,13 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
/// indirect copy/restore.
static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
assert(src->isRValue());
-
- InvalidICRKind iik = isInvalidICRSource(S.Context, src, false);
+ bool isWeakAccess = false;
+ InvalidICRKind iik = isInvalidICRSource(S.Context, src, false, isWeakAccess);
+ // If isWeakAccess to true, there will be an implicit
+ // load which requires a cleanup.
+ if (S.getLangOpts().ObjCAutoRefCount && isWeakAccess)
+ S.ExprNeedsCleanups = true;
+
if (iik == IIK_okay) return;
S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
@@ -3973,6 +4032,39 @@ static bool tryObjCWritebackConversion(Sema &S,
return true;
}
+static bool TryOCLSamplerInitialization(Sema &S,
+ InitializationSequence &Sequence,
+ QualType DestType,
+ Expr *Initializer) {
+ if (!S.getLangOpts().OpenCL || !DestType->isSamplerT() ||
+ !Initializer->isIntegerConstantExpr(S.getASTContext()))
+ return false;
+
+ Sequence.AddOCLSamplerInitStep(DestType);
+ return true;
+}
+
+//
+// OpenCL 1.2 spec, s6.12.10
+//
+// The event argument can also be used to associate the
+// async_work_group_copy with a previous async copy allowing
+// an event to be shared by multiple async copies; otherwise
+// event should be zero.
+//
+static bool TryOCLZeroEventInitialization(Sema &S,
+ InitializationSequence &Sequence,
+ QualType DestType,
+ Expr *Initializer) {
+ if (!S.getLangOpts().OpenCL || !DestType->isEventT() ||
+ !Initializer->isIntegerConstantExpr(S.getASTContext()) ||
+ (Initializer->EvaluateKnownConstInt(S.getASTContext()) != 0))
+ return false;
+
+ Sequence.AddOCLZeroEventStep(DestType);
+ return true;
+}
+
InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4115,7 +4207,13 @@ InitializationSequence::InitializationSequence(Sema &S,
tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
return;
}
-
+
+ if (TryOCLSamplerInitialization(S, *this, DestType, Initializer))
+ return;
+
+ if (TryOCLZeroEventInitialization(S, *this, DestType, Initializer))
+ return;
+
// Handle initialization in C
AddCAssignmentStep(DestType);
MaybeProduceObjCObject(S, *this, Entity);
@@ -4258,7 +4356,7 @@ getAssignmentAction(const InitializedEntity &Entity) {
llvm_unreachable("Invalid EntityKind!");
}
-/// \brief Whether we should binding a created object as a temporary when
+/// \brief Whether we should bind a created object as a temporary when
/// initializing the given entity.
static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
@@ -4288,7 +4386,6 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
/// created for that initialization, requires destruction.
static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
- case InitializedEntity::EK_Member:
case InitializedEntity::EK_Result:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
@@ -4299,6 +4396,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_LambdaCapture:
return false;
+ case InitializedEntity::EK_Member:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Temporary:
@@ -4316,12 +4414,17 @@ static void LookupCopyAndMoveConstructors(Sema &S,
OverloadCandidateSet &CandidateSet,
CXXRecordDecl *Class,
Expr *CurInitExpr) {
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(Class);
- Con != ConEnd; ++Con) {
+ DeclContext::lookup_result R = S.LookupConstructors(Class);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating (e.g. because of deserialization).
+ // To be safe we copy the lookup results to a new container.
+ SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
+ for (SmallVector<NamedDecl*, 16>::iterator
+ CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
+ NamedDecl *D = *CI;
CXXConstructorDecl *Constructor = 0;
- if ((Constructor = dyn_cast<CXXConstructorDecl>(*Con))) {
+ if ((Constructor = dyn_cast<CXXConstructorDecl>(D))) {
// Handle copy/moveconstructors, only.
if (!Constructor || Constructor->isInvalidDecl() ||
!Constructor->isCopyOrMoveConstructor() ||
@@ -4336,7 +4439,7 @@ static void LookupCopyAndMoveConstructors(Sema &S,
}
// Handle constructor templates.
- FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(*Con);
+ FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl->isInvalidDecl())
continue;
@@ -4513,8 +4616,6 @@ static ExprResult CopyObject(Sema &S,
return S.Owned(CurInitExpr);
}
- S.MarkFunctionReferenced(Loc, Constructor);
-
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions, or
// the copy constructor may have default arguments).
@@ -4526,6 +4627,7 @@ static ExprResult CopyObject(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
ConstructorArgs,
HadMultipleCandidates,
+ /*ListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -4542,7 +4644,7 @@ static ExprResult CopyObject(Sema &S,
static void CheckCXX98CompatAccessibleCopy(Sema &S,
const InitializedEntity &Entity,
Expr *CurInitExpr) {
- assert(S.getLangOpts().CPlusPlus0x);
+ assert(S.getLangOpts().CPlusPlus11);
const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>();
if (!Record)
@@ -4615,7 +4717,8 @@ PerformConstructorInitialization(Sema &S,
const InitializationKind &Kind,
MultiExprArg Args,
const InitializationSequence::Step& Step,
- bool &ConstructorInitRequiresZeroInit) {
+ bool &ConstructorInitRequiresZeroInit,
+ bool IsListInitialization) {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step.Function.Function);
@@ -4653,7 +4756,8 @@ PerformConstructorInitialization(Sema &S,
// call.
if (S.CompleteConstructorCall(Constructor, Args,
Loc, ConstructorArgs,
- AllowExplicitConv))
+ AllowExplicitConv,
+ IsListInitialization))
return ExprError();
@@ -4673,13 +4777,12 @@ PerformConstructorInitialization(Sema &S,
if (Kind.getKind() != InitializationKind::IK_DirectList)
ParenRange = Kind.getParenRange();
- CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
- Constructor,
- TSInfo,
- ConstructorArgs,
- ParenRange,
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit));
+ CurInit = S.Owned(
+ new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor,
+ TSInfo, ConstructorArgs,
+ ParenRange, IsListInitialization,
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit));
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@@ -4704,6 +4807,7 @@ PerformConstructorInitialization(Sema &S,
Constructor, /*Elidable=*/true,
ConstructorArgs,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4712,6 +4816,7 @@ PerformConstructorInitialization(Sema &S,
Constructor,
ConstructorArgs,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4802,9 +4907,9 @@ InitializationSequence::Perform(Sema &S,
if (DeclaratorDecl *DD = Entity.getDecl()) {
if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {
TypeLoc TL = TInfo->getTypeLoc();
- if (IncompleteArrayTypeLoc *ArrayLoc
- = dyn_cast<IncompleteArrayTypeLoc>(&TL))
- Brackets = ArrayLoc->getBracketsRange();
+ if (IncompleteArrayTypeLoc ArrayLoc =
+ TL.getAs<IncompleteArrayTypeLoc>())
+ Brackets = ArrayLoc.getBracketsRange();
}
}
@@ -4835,7 +4940,7 @@ InitializationSequence::Perform(Sema &S,
if (Steps.empty())
return S.Owned((Expr *)0);
- if (S.getLangOpts().CPlusPlus0x && Entity.getType()->isReferenceType() &&
+ if (S.getLangOpts().CPlusPlus11 && Entity.getType()->isReferenceType() &&
Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
Entity.getKind() != InitializedEntity::EK_Parameter) {
// Produce a C++98 compatibility warning if we are initializing a reference
@@ -4895,7 +5000,9 @@ InitializationSequence::Perform(Sema &S,
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
- case SK_StdInitializerList: {
+ case SK_StdInitializerList:
+ case SK_OCLSamplerInit:
+ case SK_OCLZeroEvent: {
assert(Args.size() == 1);
CurInit = Args[0];
if (!CurInit.get()) return ExprError();
@@ -5047,6 +5154,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
ConstructorArgs,
HadMultipleCandidates,
+ /*ListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -5161,10 +5269,11 @@ InitializationSequence::Perform(Sema &S,
QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type;
bool IsTemporary = Entity.getType()->isReferenceType();
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
- InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity,
+ InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
+ InitListChecker PerformInitList(S, InitEntity,
InitList, Ty, /*VerifyOnly=*/false,
Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus0x);
+ !S.getLangOpts().CPlusPlus11);
if (PerformInitList.HadError())
return ExprError();
@@ -5180,7 +5289,9 @@ InitializationSequence::Perform(Sema &S,
InitListExpr *StructuredInitList =
PerformInitList.getFullyStructuredList();
CurInit.release();
- CurInit = S.Owned(StructuredInitList);
+ CurInit = shouldBindAsTemporary(InitEntity)
+ ? S.MaybeBindToTemporary(StructuredInitList)
+ : S.Owned(StructuredInitList);
break;
}
@@ -5202,7 +5313,8 @@ InitializationSequence::Perform(Sema &S,
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
Kind, Arg, *Step,
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/ true);
break;
}
@@ -5235,7 +5347,8 @@ InitializationSequence::Perform(Sema &S,
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
: Entity,
Kind, Args, *Step,
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/ false);
break;
}
@@ -5359,7 +5472,7 @@ InitializationSequence::Perform(Sema &S,
case SK_StdInitializerList: {
QualType Dest = Step->Type;
QualType E;
- bool Success = S.isStdInitializerList(Dest, &E);
+ bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E);
(void)Success;
assert(Success && "Destination type changed?");
@@ -5390,9 +5503,9 @@ InitializationSequence::Perform(Sema &S,
for (unsigned i = 0; i < NumInits; ++i) {
Element.setElementIndex(i);
ExprResult Init = S.Owned(ILE->getInit(i));
- ExprResult Res = S.PerformCopyInitialization(Element,
- Init.get()->getExprLoc(),
- Init);
+ ExprResult Res = S.PerformCopyInitialization(
+ Element, Init.get()->getExprLoc(), Init,
+ /*TopLevelOfInitList=*/ true);
assert(!Res.isInvalid() && "Result changed since try phase.");
Converted[i] = Res.take();
}
@@ -5405,6 +5518,32 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.Owned(Semantic);
break;
}
+ case SK_OCLSamplerInit: {
+ assert(Step->Type->isSamplerT() &&
+ "Sampler initialization on non sampler type.");
+
+ QualType SourceType = CurInit.get()->getType();
+ InitializedEntity::EntityKind EntityKind = Entity.getKind();
+
+ if (EntityKind == InitializedEntity::EK_Parameter) {
+ if (!SourceType->isSamplerT())
+ S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
+ << SourceType;
+ } else if (EntityKind != InitializedEntity::EK_Variable) {
+ llvm_unreachable("Invalid EntityKind!");
+ }
+
+ break;
+ }
+ case SK_OCLZeroEvent: {
+ assert(Step->Type->isEventT() &&
+ "Event initialization on non event type.");
+
+ CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type,
+ CK_ZeroToOCLEvent,
+ CurInit.get()->getValueKind());
+ break;
+ }
}
}
@@ -5418,9 +5557,67 @@ InitializationSequence::Perform(Sema &S,
return CurInit;
}
+/// Somewhere within T there is an uninitialized reference subobject.
+/// Dig it out and diagnose it.
+static bool DiagnoseUninitializedReference(Sema &S, SourceLocation Loc,
+ QualType T) {
+ if (T->isReferenceType()) {
+ S.Diag(Loc, diag::err_reference_without_init)
+ << T.getNonReferenceType();
+ return true;
+ }
+
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || !RD->hasUninitializedReferenceMember())
+ return false;
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end(); FI != FE; ++FI) {
+ if (FI->isUnnamedBitfield())
+ continue;
+
+ if (DiagnoseUninitializedReference(S, FI->getLocation(), FI->getType())) {
+ S.Diag(Loc, diag::note_value_initialization_here) << RD;
+ return true;
+ }
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ if (DiagnoseUninitializedReference(S, BI->getLocStart(), BI->getType())) {
+ S.Diag(Loc, diag::note_value_initialization_here) << RD;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
//===----------------------------------------------------------------------===//
// Diagnose initialization failures
//===----------------------------------------------------------------------===//
+
+/// Emit notes associated with an initialization that failed due to a
+/// "simple" conversion failure.
+static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity,
+ Expr *op) {
+ QualType destType = entity.getType();
+ if (destType.getNonReferenceType()->isObjCObjectPointerType() &&
+ op->getType()->isObjCObjectPointerType()) {
+
+ // Emit a possible note about the conversion failing because the
+ // operand is a message send with a related result type.
+ S.EmitRelatedResultTypeNote(op);
+
+ // Emit a possible note about a return failing because we're
+ // expecting a related result type.
+ if (entity.getKind() == InitializedEntity::EK_Result)
+ S.EmitRelatedResultTypeNoteForReturn(destType);
+ }
+}
+
bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -5432,10 +5629,17 @@ bool InitializationSequence::Diagnose(Sema &S,
switch (Failure) {
case FK_TooManyInitsForReference:
// FIXME: Customize for the initialized entity?
- if (NumArgs == 0)
- S.Diag(Kind.getLocation(), diag::err_reference_without_init)
- << DestType.getNonReferenceType();
- else // FIXME: diagnostic below could be better!
+ if (NumArgs == 0) {
+ // Dig out the reference subobject which is uninitialized and diagnose it.
+ // If this is value-initialization, this could be nested some way within
+ // the target type.
+ assert(Kind.getKind() == InitializationKind::IK_Value ||
+ DestType->isReferenceType());
+ bool Diagnosed =
+ DiagnoseUninitializedReference(S, Kind.getLocation(), DestType);
+ assert(Diagnosed && "couldn't find uninitialized reference to diagnose");
+ (void)Diagnosed;
+ } else // FIXME: diagnostic below could be better!
S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
<< SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
break;
@@ -5558,9 +5762,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< Args[0]->getType()
<< Args[0]->getSourceRange();
- if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
- Args[0]->getType()->isObjCObjectPointerType())
- S.EmitRelatedResultTypeNote(Args[0]);
+ emitBadConversionNotes(S, Entity, Args[0]);
break;
case FK_ConversionFailed: {
@@ -5573,9 +5775,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
S.HandleFunctionTypeMismatch(PDiag, FromType, DestType);
S.Diag(Kind.getLocation(), PDiag);
- if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
- Args[0]->getType()->isObjCObjectPointerType())
- S.EmitRelatedResultTypeNote(Args[0]);
+ emitBadConversionNotes(S, Entity, Args[0]);
break;
}
@@ -5649,7 +5849,8 @@ bool InitializationSequence::Diagnose(Sema &S,
= cast<CXXConstructorDecl>(S.CurContext);
if (Entity.getKind() == InitializedEntity::EK_Base) {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << Constructor->isImplicit()
+ << (Constructor->getInheritedConstructor() ? 2 :
+ Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*base=*/0
<< Entity.getType();
@@ -5661,7 +5862,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getTagDeclType(BaseDecl);
} else {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << Constructor->isImplicit()
+ << (Constructor->getInheritedConstructor() ? 2 :
+ Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
<< Entity.getName();
@@ -5722,7 +5924,8 @@ bool InitializationSequence::Diagnose(Sema &S,
// initialized.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
- << Constructor->isImplicit()
+ << (Constructor->getInheritedConstructor() ? 2 :
+ Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*const=*/1
<< Entity.getName();
@@ -5746,7 +5949,7 @@ bool InitializationSequence::Diagnose(Sema &S,
InitListChecker DiagnoseInitList(S, Entity, InitList,
DestType, /*VerifyOnly=*/false,
Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus0x);
+ !S.getLangOpts().CPlusPlus11);
assert(DiagnoseInitList.HadError() &&
"Inconsistent init list check result.");
break;
@@ -5763,7 +5966,7 @@ bool InitializationSequence::Diagnose(Sema &S,
unsigned NumInits = InitList->getNumInits();
QualType DestType = Entity.getType();
QualType E;
- bool Success = S.isStdInitializerList(DestType, &E);
+ bool Success = S.isStdInitializerList(DestType.getNonReferenceType(), &E);
(void)Success;
assert(Success && "Where did the std::initializer_list go?");
InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
@@ -6047,8 +6250,20 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_StdInitializerList:
OS << "std::initializer_list from initializer list";
break;
+
+ case SK_OCLSamplerInit:
+ OS << "OpenCL sampler_t from integer constant";
+ break;
+
+ case SK_OCLZeroEvent:
+ OS << "OpenCL event_t from zero";
+ break;
}
+
+ OS << " [" << S->Type.getAsString() << ']';
}
+
+ OS << '\n';
}
void InitializationSequence::dump() const {
@@ -6104,7 +6319,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
// narrowing conversion even if the value is a constant and can be
// represented exactly as an integer.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
diag::warn_init_list_type_narrowing
: S.isSFINAEContext()?
diag::err_init_list_type_narrowing_sfinae
@@ -6117,7 +6332,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
case NK_Constant_Narrowing:
// A constant value was narrowed.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
diag::warn_init_list_constant_narrowing
: S.isSFINAEContext()?
diag::err_init_list_constant_narrowing_sfinae
@@ -6130,7 +6345,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
case NK_Variable_Narrowing:
// A variable's value may have been narrowed.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
diag::warn_init_list_variable_narrowing
: S.isSFINAEContext()?
diag::err_init_list_variable_narrowing_sfinae
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 15cd2a73e7f7..53fa6dafdd3b 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
+#include "clang/AST/ExprCXX.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/Lex/Preprocessor.h"
-#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace sema;
@@ -55,7 +55,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
- llvm::ArrayRef<ParmVarDecl *> Params) {
+ ArrayRef<ParmVarDecl *> Params) {
// C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function
// call operator (13.5.4) whose parameters and return type are described by
@@ -74,7 +74,6 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
IntroducerRange.getBegin(),
MethodNameLoc),
MethodType->getType(), MethodType,
- /*isStatic=*/false,
SC_None,
/*isInline=*/true,
/*isConstExpr=*/false,
@@ -225,73 +224,153 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
}
}
-static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
- QualType &DeducedType,
- QualType &AlternateType) {
- // Handle ReturnStmts with no expressions.
- if (!E) {
- if (AlternateType.isNull())
- AlternateType = Ctx.VoidTy;
+/// If this expression is an enumerator-like expression of some type
+/// T, return the type T; otherwise, return null.
+///
+/// Pointer comparisons on the result here should always work because
+/// it's derived from either the parent of an EnumConstantDecl
+/// (i.e. the definition) or the declaration returned by
+/// EnumType::getDecl() (i.e. the definition).
+static EnumDecl *findEnumForBlockReturn(Expr *E) {
+ // An expression is an enumerator-like expression of type T if,
+ // ignoring parens and parens-like expressions:
+ E = E->IgnoreParens();
+
+ // - it is an enumerator whose enum type is T or
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (EnumConstantDecl *D
+ = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ return cast<EnumDecl>(D->getDeclContext());
+ }
+ return 0;
+ }
- return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
+ // - it is a comma expression whose RHS is an enumerator-like
+ // expression of type T or
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ return findEnumForBlockReturn(BO->getRHS());
+ return 0;
}
- QualType StrictType = E->getType();
- QualType LooseType = StrictType;
-
- // In C, enum constants have the type of their underlying integer type,
- // not the enum. When inferring block return types, we should allow
- // the enum type if an enum constant is used, unless the enum is
- // anonymous (in which case there can be no variables of its type).
- if (!Ctx.getLangOpts().CPlusPlus) {
- const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
- if (DRE) {
- const Decl *D = DRE->getDecl();
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
- const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
- if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
- LooseType = Ctx.getTypeDeclType(Enum);
- }
- }
+ // - it is a statement-expression whose value expression is an
+ // enumerator-like expression of type T or
+ if (StmtExpr *SE = dyn_cast<StmtExpr>(E)) {
+ if (Expr *last = dyn_cast_or_null<Expr>(SE->getSubStmt()->body_back()))
+ return findEnumForBlockReturn(last);
+ return 0;
}
- // Special case for the first return statement we find.
- // The return type has already been tentatively set, but we might still
- // have an alternate type we should prefer.
- if (AlternateType.isNull())
- AlternateType = LooseType;
-
- if (Ctx.hasSameType(DeducedType, StrictType)) {
- // FIXME: The loose type is different when there are constants from two
- // different enums. We could consider warning here.
- if (AlternateType != Ctx.DependentTy)
- if (!Ctx.hasSameType(AlternateType, LooseType))
- AlternateType = Ctx.VoidTy;
- return true;
+ // - it is a ternary conditional operator (not the GNU ?:
+ // extension) whose second and third operands are
+ // enumerator-like expressions of type T or
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ if (EnumDecl *ED = findEnumForBlockReturn(CO->getTrueExpr()))
+ if (ED == findEnumForBlockReturn(CO->getFalseExpr()))
+ return ED;
+ return 0;
}
- if (Ctx.hasSameType(DeducedType, LooseType)) {
- // Use DependentTy to signal that we're using an alternate type and may
- // need to add casts somewhere.
- AlternateType = Ctx.DependentTy;
- return true;
+ // (implicitly:)
+ // - it is an implicit integral conversion applied to an
+ // enumerator-like expression of type T or
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ // We can only see integral conversions in valid enumerator-like
+ // expressions.
+ if (ICE->getCastKind() == CK_IntegralCast)
+ return findEnumForBlockReturn(ICE->getSubExpr());
+ return 0;
}
- if (Ctx.hasSameType(AlternateType, StrictType) ||
- Ctx.hasSameType(AlternateType, LooseType)) {
- DeducedType = AlternateType;
- // Use DependentTy to signal that we're using an alternate type and may
- // need to add casts somewhere.
- AlternateType = Ctx.DependentTy;
- return true;
+ // - it is an expression of that formal enum type.
+ if (const EnumType *ET = E->getType()->getAs<EnumType>()) {
+ return ET->getDecl();
}
- return false;
+ // Otherwise, nope.
+ return 0;
+}
+
+/// Attempt to find a type T for which the returned expression of the
+/// given statement is an enumerator-like expression of that type.
+static EnumDecl *findEnumForBlockReturn(ReturnStmt *ret) {
+ if (Expr *retValue = ret->getRetValue())
+ return findEnumForBlockReturn(retValue);
+ return 0;
+}
+
+/// Attempt to find a common type T for which all of the returned
+/// expressions in a block are enumerator-like expressions of that
+/// type.
+static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt*> returns) {
+ ArrayRef<ReturnStmt*>::iterator i = returns.begin(), e = returns.end();
+
+ // Try to find one for the first return.
+ EnumDecl *ED = findEnumForBlockReturn(*i);
+ if (!ED) return 0;
+
+ // Check that the rest of the returns have the same enum.
+ for (++i; i != e; ++i) {
+ if (findEnumForBlockReturn(*i) != ED)
+ return 0;
+ }
+
+ // Never infer an anonymous enum type.
+ if (!ED->hasNameForLinkage()) return 0;
+
+ return ED;
+}
+
+/// Adjust the given return statements so that they formally return
+/// the given type. It should require, at most, an IntegralCast.
+static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
+ QualType returnType) {
+ for (ArrayRef<ReturnStmt*>::iterator
+ i = returns.begin(), e = returns.end(); i != e; ++i) {
+ ReturnStmt *ret = *i;
+ Expr *retValue = ret->getRetValue();
+ if (S.Context.hasSameType(retValue->getType(), returnType))
+ continue;
+
+ // Right now we only support integral fixup casts.
+ assert(returnType->isIntegralOrUnscopedEnumerationType());
+ assert(retValue->getType()->isIntegralOrUnscopedEnumerationType());
+
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(retValue);
+
+ Expr *E = (cleanups ? cleanups->getSubExpr() : retValue);
+ E = ImplicitCastExpr::Create(S.Context, returnType, CK_IntegralCast,
+ E, /*base path*/ 0, VK_RValue);
+ if (cleanups) {
+ cleanups->setSubExpr(E);
+ } else {
+ ret->setRetValue(E);
+ }
+ }
}
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
+ // C++ Core Issue #975, proposed resolution:
+ // If a lambda-expression does not include a trailing-return-type,
+ // it is as if the trailing-return-type denotes the following type:
+ // - if there are no return statements in the compound-statement,
+ // or all return statements return either an expression of type
+ // void or no expression or braced-init-list, the type void;
+ // - otherwise, if all return statements return an expression
+ // and the types of the returned expressions after
+ // lvalue-to-rvalue conversion (4.1 [conv.lval]),
+ // array-to-pointer conversion (4.2 [conv.array]), and
+ // function-to-pointer conversion (4.3 [conv.func]) are the
+ // same, that common type;
+ // - otherwise, the program is ill-formed.
+ //
+ // In addition, in blocks in non-C++ modes, if all of the return
+ // statements are enumerator-like expressions of some type T, where
+ // T has a name for linkage, then we infer the return type of the
+ // block to be that type.
+
// First case: no return statements, implicit void return type.
ASTContext &Ctx = getASTContext();
if (CSI.Returns.empty()) {
@@ -308,6 +387,17 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
if (CSI.ReturnType->isDependentType())
return;
+ // Try to apply the enum-fuzz rule.
+ if (!getLangOpts().CPlusPlus) {
+ assert(isa<BlockScopeInfo>(CSI));
+ const EnumDecl *ED = findCommonEnumForBlockReturns(CSI.Returns);
+ if (ED) {
+ CSI.ReturnType = Context.getTypeDeclType(ED);
+ adjustBlockReturnsToEnum(*this, CSI.Returns, CSI.ReturnType);
+ return;
+ }
+ }
+
// Third case: only one return statement. Don't bother doing extra work!
SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
E = CSI.Returns.end();
@@ -316,47 +406,25 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
// General case: many return statements.
// Check that they all have compatible return types.
- // For now, that means "identical", with an exception for enum constants.
- // (In C, enum constants have the type of their underlying integer type,
- // not the type of the enum. C++ uses the type of the enum.)
- QualType AlternateType;
// We require the return types to strictly match here.
+ // Note that we've already done the required promotions as part of
+ // processing the return statement.
for (; I != E; ++I) {
const ReturnStmt *RS = *I;
const Expr *RetE = RS->getRetValue();
- if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) {
- // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
- Diag(RS->getLocStart(),
- diag::err_typecheck_missing_return_type_incompatible)
- << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType
- << isa<LambdaScopeInfo>(CSI);
- // Don't bother fixing up the return statements in the block if some of
- // them are unfixable anyway.
- AlternateType = Ctx.VoidTy;
- // Continue iterating so that we keep emitting diagnostics.
- }
- }
- // If our return statements turned out to be compatible, but we needed to
- // pick a different return type, go through and fix the ones that need it.
- if (AlternateType == Ctx.DependentTy) {
- for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
- E = CSI.Returns.end();
- I != E; ++I) {
- ReturnStmt *RS = *I;
- Expr *RetE = RS->getRetValue();
- if (RetE->getType() == CSI.ReturnType)
- continue;
+ QualType ReturnType = (RetE ? RetE->getType() : Context.VoidTy);
+ if (Context.hasSameType(ReturnType, CSI.ReturnType))
+ continue;
- // Right now we only support integral fixup casts.
- assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType());
- assert(RetE->getType()->isIntegralOrUnscopedEnumerationType());
- ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType,
- CK_IntegralCast);
- assert(Casted.isUsable());
- RS->setRetValue(Casted.take());
- }
+ // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
+ // TODO: It's possible that the *first* return is the divergent one.
+ Diag(RS->getLocStart(),
+ diag::err_typecheck_missing_return_type_incompatible)
+ << ReturnType << CSI.ReturnType
+ << isa<LambdaScopeInfo>(CSI);
+ // Continue iterating so that we keep emitting diagnostics.
}
}
@@ -376,7 +444,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool ExplicitResultType = true;
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
- llvm::SmallVector<ParmVarDecl *, 8> Params;
+ SmallVector<ParmVarDecl *, 8> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -385,7 +453,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
QualType MethodTy = Context.getFunctionType(Context.DependentTy,
- /*Args=*/0, /*NumArgs=*/0, EPI);
+ ArrayRef<QualType>(),
+ EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -449,7 +518,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Handle explicit captures.
SourceLocation PrevCaptureLoc
= Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
- for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+ for (SmallVector<LambdaCapture, 4>::const_iterator
C = Intro.Captures.begin(),
E = Intro.Captures.end();
C != E;
@@ -628,16 +697,18 @@ static void addFunctionPointerConversion(Sema &S,
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
- FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- ExtInfo);
+ FunctionTy =
+ S.Context.getFunctionType(Proto->getResultType(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ ExtInfo);
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo);
+ QualType ConvTy =
+ S.Context.getFunctionType(FunctionPtrTy, ArrayRef<QualType>(), ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -666,7 +737,7 @@ static void addFunctionPointerConversion(Sema &S,
= CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy,
CallOperator->getTypeSourceInfo(),
- /*IsStatic=*/true, SC_Static, /*IsInline=*/true,
+ SC_Static, /*IsInline=*/true,
/*IsConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
SmallVector<ParmVarDecl *, 4> InvokeParams;
@@ -679,7 +750,6 @@ static void addFunctionPointerConversion(Sema &S,
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
- From->getStorageClassAsWritten(),
/*DefaultArg=*/0));
}
Invoke->setParams(InvokeParams);
@@ -701,15 +771,16 @@ static void addBlockPointerConversion(Sema &S,
ExtInfo.TypeQuals = 0;
QualType FunctionTy
= S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, 0, 0, ExtInfo);
+ QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, ArrayRef<QualType>(),
+ ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -734,8 +805,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
bool IsInstantiation) {
// Collect information from the lambda scope.
- llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
- llvm::SmallVector<Expr *, 4> CaptureInits;
+ SmallVector<LambdaExpr::Capture, 4> Captures;
+ SmallVector<Expr *, 4> CaptureInits;
LambdaCaptureDefault CaptureDefault;
CXXRecordDecl *Class;
CXXMethodDecl *CallOperator;
@@ -744,8 +815,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
bool ContainsUnexpandedParameterPack;
- llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
- llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
+ SmallVector<VarDecl *, 4> ArrayIndexVars;
+ SmallVector<unsigned, 4> ArrayIndexStarts;
{
LambdaScopeInfo *LSI = getCurLambda();
CallOperator = LSI->CallOperator;
@@ -821,8 +892,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionTy
= Context.getFunctionType(LSI->ReturnType,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
@@ -902,8 +973,8 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
CXXRecordDecl *Lambda = Conv->getParent();
CXXMethodDecl *CallOperator
= cast<CXXMethodDecl>(
- *Lambda->lookup(
- Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ Lambda->lookup(
+ Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced();
CallOperator->setUsed();
@@ -937,7 +1008,6 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
- From->getStorageClassAsWritten(),
/*DefaultArg=*/0));
}
Block->setParams(BlockParams);
@@ -952,7 +1022,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
ConvLocation, 0,
Src->getType(), CapVarTSI,
- SC_None, SC_None);
+ SC_None);
BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
/*Nested=*/false, /*Copy=*/Init.take());
Block->setCaptures(Context, &Capture, &Capture + 1,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f6987e7bfbe0..f26b8ed7f7ae 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -11,16 +11,7 @@
// Objective-C++.
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Overload.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/TemplateDeduction.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/TypoCorrection.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -32,8 +23,17 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/SetVector.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/TinyPtrVector.h"
@@ -287,10 +287,10 @@ void LookupResult::configure() {
IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus,
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.
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:
@@ -302,6 +302,15 @@ void LookupResult::configure() {
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;
+ }
+ }
}
}
@@ -371,6 +380,12 @@ void LookupResult::resolveKind() {
NamedDecl *D = Decls[I]->getUnderlyingDecl();
D = cast<NamedDecl>(D->getCanonicalDecl());
+ // Ignore an invalid declaration unless it's the only one left.
+ if (D->isInvalidDecl() && I < N-1) {
+ Decls[I] = Decls[--N];
+ continue;
+ }
+
// Redeclarations of types via typedef can occur both within a scope
// and, through using declarations and directives, across scopes. There is
// no ambiguity if they all refer to the same type, so unique based on the
@@ -451,9 +466,9 @@ void LookupResult::resolveKind() {
void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
CXXBasePaths::const_paths_iterator I, E;
- DeclContext::lookup_iterator DI, DE;
for (I = P.begin(), E = P.end(); I != E; ++I)
- for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
+ for (DeclContext::lookup_iterator DI = I->Decls.begin(),
+ DE = I->Decls.end(); DI != DE; ++DI)
addDecl(*DI);
}
@@ -528,22 +543,17 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
/// \brief Determine whether we can declare a special member function within
/// the class at this point.
-static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
- const CXXRecordDecl *Class) {
+static bool CanDeclareSpecialMemberFunction(const CXXRecordDecl *Class) {
// We need to have a definition for the class.
if (!Class->getDefinition() || Class->isDependentContext())
return false;
// We can't be in the middle of defining the class.
- if (const RecordType *RecordTy
- = Context.getTypeDeclType(Class)->getAs<RecordType>())
- return !RecordTy->isBeingDefined();
-
- return false;
+ return !Class->isBeingDefined();
}
void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
- if (!CanDeclareSpecialMemberFunction(Context, Class))
+ if (!CanDeclareSpecialMemberFunction(Class))
return;
// If the default constructor has not yet been declared, do so now.
@@ -551,14 +561,14 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
DeclareImplicitDefaultConstructor(Class);
// If the copy constructor has not yet been declared, do so now.
- if (!Class->hasDeclaredCopyConstructor())
+ if (Class->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(Class);
// If the copy assignment operator has not yet been declared, do so now.
- if (!Class->hasDeclaredCopyAssignment())
+ if (Class->needsImplicitCopyAssignment())
DeclareImplicitCopyAssignment(Class);
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// If the move constructor has not yet been declared, do so now.
if (Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class); // might not actually do it
@@ -569,7 +579,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
}
// If the destructor has not yet been declared, do so now.
- if (!Class->hasDeclaredDestructor())
+ if (Class->needsImplicitDestructor())
DeclareImplicitDestructor(Class);
}
@@ -602,14 +612,13 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
switch (Name.getNameKind()) {
case DeclarationName::CXXConstructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getDefinition() &&
- CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) {
CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
if (Record->needsImplicitDefaultConstructor())
S.DeclareImplicitDefaultConstructor(Class);
- if (!Record->hasDeclaredCopyConstructor())
+ if (Record->needsImplicitCopyConstructor())
S.DeclareImplicitCopyConstructor(Class);
- if (S.getLangOpts().CPlusPlus0x &&
+ if (S.getLangOpts().CPlusPlus11 &&
Record->needsImplicitMoveConstructor())
S.DeclareImplicitMoveConstructor(Class);
}
@@ -617,8 +626,8 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
case DeclarationName::CXXDestructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getDefinition() && !Record->hasDeclaredDestructor() &&
- CanDeclareSpecialMemberFunction(S.Context, Record))
+ if (Record->getDefinition() && Record->needsImplicitDestructor() &&
+ CanDeclareSpecialMemberFunction(Record))
S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record));
break;
@@ -627,12 +636,11 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
break;
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
- if (Record->getDefinition() &&
- CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) {
CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
- if (!Record->hasDeclaredCopyAssignment())
+ if (Record->needsImplicitCopyAssignment())
S.DeclareImplicitCopyAssignment(Class);
- if (S.getLangOpts().CPlusPlus0x &&
+ if (S.getLangOpts().CPlusPlus11 &&
Record->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(Class);
}
@@ -654,8 +662,9 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
// Perform lookup into this declaration context.
- DeclContext::lookup_const_iterator I, E;
- for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
+ DeclContext::lookup_const_result DR = DC->lookup(R.getLookupName());
+ for (DeclContext::lookup_const_iterator I = DR.begin(), E = DR.end(); I != E;
+ ++I) {
NamedDecl *D = *I;
if ((D = R.getAcceptableDecl(D))) {
R.addDecl(D);
@@ -680,9 +689,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
if (!Record->isCompleteDefinition())
return Found;
- const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
- UEnd = Unresolved->end(); U != UEnd; ++U) {
+ for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(),
+ UEnd = Record->conversion_end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
if (!ConvTemplate)
continue;
@@ -723,7 +731,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
EPI.NumExceptions = 0;
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
- 0, 0, EPI);
+ ArrayRef<QualType>(), EPI);
// Perform template argument deduction against the type that we would
// expect the function to have.
@@ -946,6 +954,21 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
continue;
}
+ // If this is a file context, we need to perform unqualified name
+ // lookup considering using directives.
+ if (Ctx->isFileContext()) {
+ UnqualUsingDirectiveSet UDirs;
+ UDirs.visit(Ctx, Ctx);
+ UDirs.done();
+
+ if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) {
+ R.resolveKind();
+ return true;
+ }
+
+ continue;
+ }
+
// Perform qualified name lookup into this context.
// FIXME: In some cases, we know that every name that could be found by
// this qualified name lookup will also be on the identifier chain. For
@@ -980,7 +1003,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// Unqualified name lookup in C++ requires looking into scopes
// that aren't strictly lexical, and therefore we walk through the
// context as well as walking through the scopes.
-
for (; S; S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
@@ -1344,7 +1366,7 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
Path.Decls = BaseRecord->lookup(N);
- return Path.Decls.first != Path.Decls.second;
+ return !Path.Decls.empty();
}
/// \brief Determine whether the given set of member declarations contains only
@@ -1530,13 +1552,13 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// 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.
- if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) {
+ if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) {
CXXBasePaths::paths_iterator FirstPath = Paths.begin();
- DeclContext::lookup_iterator FirstD = FirstPath->Decls.first;
- DeclContext::lookup_iterator CurrentD = Path->Decls.first;
+ DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin();
+ DeclContext::lookup_iterator CurrentD = Path->Decls.begin();
- while (FirstD != FirstPath->Decls.second &&
- CurrentD != Path->Decls.second) {
+ while (FirstD != FirstPath->Decls.end() &&
+ CurrentD != Path->Decls.end()) {
if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() !=
(*CurrentD)->getUnderlyingDecl()->getCanonicalDecl())
break;
@@ -1545,8 +1567,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
++CurrentD;
}
- if (FirstD == FirstPath->Decls.second &&
- CurrentD == Path->Decls.second)
+ if (FirstD == FirstPath->Decls.end() &&
+ CurrentD == Path->Decls.end())
continue;
}
@@ -1561,7 +1583,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// A static member, a nested type or an enumerator defined in
// a base class T can unambiguously be found even if an object
// has more than one base class subobject of type T.
- if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second))
+ if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end()))
continue;
// We have found a nonstatic member name in multiple, distinct
@@ -1573,8 +1595,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Lookup in a base class succeeded; return these results.
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) {
+ DeclContext::lookup_result DR = Paths.front().Decls;
+ for (DeclContext::lookup_iterator I = DR.begin(), E = DR.end(); I != E; ++I) {
NamedDecl *D = *I;
AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess,
D->getAccess());
@@ -1655,7 +1677,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
<< Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
<< LookupRange;
- DeclContext::lookup_iterator Found = Paths->front().Decls.first;
+ DeclContext::lookup_iterator Found = Paths->front().Decls.begin();
while (isa<CXXMethodDecl>(*Found) &&
cast<CXXMethodDecl>(*Found)->isStatic())
++Found;
@@ -1674,7 +1696,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
for (CXXBasePaths::paths_iterator Path = Paths->begin(),
PathEnd = Paths->end();
Path != PathEnd; ++Path) {
- Decl *D = *Path->Decls.first;
+ Decl *D = Path->Decls.front();
if (DeclsPrinted.insert(D).second)
Diag(D->getLocation(), diag::note_ambiguous_member_found);
}
@@ -2233,9 +2255,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
bool RValueThis,
bool ConstThis,
bool VolatileThis) {
- RD = RD->getDefinition();
- assert((RD && !RD->isBeingDefined()) &&
+ assert(CanDeclareSpecialMemberFunction(RD) &&
"doing special member lookup into record that isn't fully complete");
+ RD = RD->getDefinition();
if (RValueThis || ConstThis || VolatileThis)
assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
"constructors and destructors always have unqualified lvalue this");
@@ -2265,7 +2287,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (!RD->hasDeclaredDestructor())
+ if (RD->needsImplicitDestructor())
DeclareImplicitDestructor(RD);
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
@@ -2294,15 +2316,15 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (!RD->hasDeclaredCopyConstructor())
+ if (RD->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(RD);
- if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveConstructor())
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(RD);
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (!RD->hasDeclaredCopyAssignment())
+ if (RD->needsImplicitCopyAssignment())
DeclareImplicitCopyAssignment(RD);
- if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveAssignment())
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment())
DeclareImplicitMoveAssignment(RD);
}
@@ -2345,12 +2367,11 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// 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()));
- DeclContext::lookup_iterator I, E;
+ DeclContext::lookup_result R = RD->lookup(Name);
- llvm::tie(I, E) = RD->lookup(Name);
- assert((I != E) &&
+ assert(!R.empty() &&
"lookup for a constructor or assignment operator was empty");
- for ( ; I != E; ++I) {
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
Decl *Cand = *I;
if (Cand->isInvalidDecl())
@@ -2451,12 +2472,12 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
/// \brief Look up the constructors for the given class.
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the implicit constructors have not yet been declared, do so now.
- if (CanDeclareSpecialMemberFunction(Context, Class)) {
+ if (CanDeclareSpecialMemberFunction(Class)) {
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
- if (!Class->hasDeclaredCopyConstructor())
+ if (Class->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(Class);
- if (getLangOpts().CPlusPlus0x && Class->needsImplicitMoveConstructor())
+ if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class);
}
@@ -2544,7 +2565,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (FD->getNumParams() == 1 &&
FD->getParamDecl(0)->getType()->getAs<PointerType>())
IsRaw = true;
- else {
+ else if (FD->getNumParams() == ArgTys.size()) {
IsExactMatch = true;
for (unsigned ArgIdx = 0; ArgIdx != ArgTys.size(); ++ArgIdx) {
QualType ParamTy = FD->getParamDecl(ArgIdx)->getType();
@@ -2690,8 +2711,9 @@ 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_iterator I, E;
- for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
+ DeclContext::lookup_result R = (*NS)->lookup(Name);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
NamedDecl *D = *I;
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
@@ -2850,8 +2872,10 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
for (DeclContext::all_lookups_iterator L = Ctx->lookups_begin(),
LEnd = Ctx->lookups_end();
L != LEnd; ++L) {
- for (DeclContext::lookup_result R = *L; R.first != R.second; ++R.first) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*R.first)) {
+ 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)) {
if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
Visited.add(ND);
@@ -2918,10 +2942,12 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Traverse the contexts of Objective-C classes.
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
// Traverse categories.
- for (ObjCCategoryDecl *Category = IFace->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
+ LookupVisibleDecls(*Cat, Result, QualifiedNameLookup, false,
Consumer, Visited);
}
@@ -3135,7 +3161,7 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
namespace {
-typedef llvm::SmallVector<TypoCorrection, 1> TypoResultList;
+typedef SmallVector<TypoCorrection, 1> TypoResultList;
typedef llvm::StringMap<TypoResultList, llvm::BumpPtrAllocator> TypoResultsMap;
typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
@@ -3560,7 +3586,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
Consumer.addKeywordResult("typename");
Consumer.addKeywordResult("wchar_t");
- if (SemaRef.getLangOpts().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus11) {
Consumer.addKeywordResult("char16_t");
Consumer.addKeywordResult("char32_t");
Consumer.addKeywordResult("constexpr");
@@ -3599,7 +3625,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
Consumer.addKeywordResult("this");
- if (SemaRef.getLangOpts().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus11) {
Consumer.addKeywordResult("alignof");
Consumer.addKeywordResult("nullptr");
}
@@ -3656,7 +3682,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("using");
- if (SemaRef.getLangOpts().CPlusPlus0x)
+ if (SemaRef.getLangOpts().CPlusPlus11)
Consumer.addKeywordResult("static_assert");
}
}
@@ -3731,6 +3757,17 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (!ActiveTemplateInstantiations.empty())
return TypoCorrection();
+ // Don't try to correct 'super'.
+ if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier())
+ return TypoCorrection();
+
+ // This is for testing.
+ if (Diags.getWarnOnSpellCheck()) {
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+ "spell-checking initiated for %0");
+ Diag(TypoName.getLoc(), DiagID) << TypoName.getName();
+ }
+
NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
TypoCorrectionConsumer Consumer(*this, Typo);
@@ -3860,7 +3897,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
KnownNamespaces[ExternalKnownNamespaces[I]] = true;
}
- for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
KNI = KnownNamespaces.begin(),
KNIEnd = KnownNamespaces.end();
KNI != KNIEnd; ++KNI)
@@ -3869,7 +3906,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Weed out any names that could not be found by name lookup or, if a
// CorrectionCandidateCallback object was provided, failed validation.
- llvm::SmallVector<TypoCorrection, 16> QualifiedResults;
+ SmallVector<TypoCorrection, 16> QualifiedResults;
LookupResult TmpRes(*this, TypoName, LookupKind);
TmpRes.suppressDiagnostics();
while (!Consumer.empty()) {
@@ -3971,9 +4008,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Only perform the qualified lookups for C++
if (SearchNamespaces) {
TmpRes.suppressDiagnostics();
- for (llvm::SmallVector<TypoCorrection,
- 16>::iterator QRI = QualifiedResults.begin(),
- QRIEnd = QualifiedResults.end();
+ for (SmallVector<TypoCorrection,
+ 16>::iterator QRI = QualifiedResults.begin(),
+ QRIEnd = QualifiedResults.end();
QRI != QRIEnd; ++QRI) {
for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(),
NIEnd = Namespaces.end();
@@ -4094,7 +4131,7 @@ void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
if (isKeyword())
CorrectionDecls.clear();
- CorrectionDecls.push_back(CDecl);
+ CorrectionDecls.push_back(CDecl->getUnderlyingDecl());
if (!CorrectionName)
CorrectionName = CDecl->getDeclName();
@@ -4111,3 +4148,21 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const {
return CorrectionName.getAsString();
}
+
+bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candidate) {
+ if (!candidate.isResolved())
+ return true;
+
+ if (candidate.isKeyword())
+ 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;
+ }
+
+ return WantTypeSpecifiers;
+}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 8d708607f6eb..c348a9cb7687 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -13,16 +13,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ASTMutationListener.h"
-#include "clang/Lex/Lexer.h"
+#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"
-#include "clang/Lex/Preprocessor.h"
using namespace clang;
@@ -112,6 +112,33 @@ static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
return 0;
}
+/// \brief Check this Objective-C property against a property declared in the
+/// given protocol.
+static void
+CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
+ ObjCProtocolDecl *Proto,
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 16> &Known) {
+ // Have we seen this protocol before?
+ if (!Known.insert(Proto))
+ return;
+
+ // Look for a property with the same name.
+ DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *ProtoProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier());
+ return;
+ }
+ }
+
+ // 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);
+ }
+}
+
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
SourceLocation LParenLoc,
FieldDeclarator &FD,
@@ -139,34 +166,31 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
!(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
!(Attributes & ObjCDeclSpec::DQ_PR_weak)));
- // Proceed with constructing the ObjCPropertDecls.
+ // Proceed with constructing the ObjCPropertyDecls.
ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
- if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ ObjCPropertyDecl *Res = 0;
+ if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
if (CDecl->IsClassExtension()) {
- Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
+ Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
FD, GetterSel, SetterSel,
isAssign, isReadWrite,
Attributes,
ODS.getPropertyAttributes(),
isOverridingProperty, TSI,
MethodImplKind);
- if (Res) {
- CheckObjCPropertyAttributes(Res, AtLoc, Attributes, false);
- if (getLangOpts().ObjCAutoRefCount)
- checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
- }
- ActOnDocumentableDecl(Res);
- return Res;
+ if (!Res)
+ return 0;
}
-
- ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
- GetterSel, SetterSel,
- isAssign, isReadWrite,
- Attributes,
- ODS.getPropertyAttributes(),
- TSI, MethodImplKind);
- if (lexicalDC)
- Res->setLexicalDeclContext(lexicalDC);
+ }
+
+ if (!Res) {
+ Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
+ GetterSel, SetterSel, isAssign, isReadWrite,
+ Attributes, ODS.getPropertyAttributes(),
+ TSI, MethodImplKind);
+ if (lexicalDC)
+ Res->setLexicalDeclContext(lexicalDC);
+ }
// Validate the attributes on the @property.
CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
@@ -176,6 +200,52 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyDecl(*this, Res);
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;
+ 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()) {
+ 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])) {
+ DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier());
+ FoundInSuper = true;
+ break;
+ }
+ }
+ }
+
+ 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);
+ }
+ } 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);
+ }
+ }
+ } 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);
+ }
+ } 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);
+ }
+ }
+
ActOnDocumentableDecl(Res);
return Res;
}
@@ -251,7 +321,7 @@ static unsigned getOwnershipRule(unsigned attr) {
ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
}
-Decl *
+ObjCPropertyDecl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
SourceLocation LParenLoc,
@@ -270,20 +340,22 @@ Sema::HandlePropertyInClassExtension(Scope *S,
IdentifierInfo *PropertyId = FD.D.getIdentifier();
ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
- if (CCPrimary)
+ if (CCPrimary) {
// Check for duplicate declaration of this property in current and
// other class extensions.
- for (const ObjCCategoryDecl *ClsExtDecl =
- CCPrimary->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- if (ObjCPropertyDecl *prevDecl =
- ObjCPropertyDecl::findPropertyDecl(ClsExtDecl, PropertyId)) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = CCPrimary->known_extensions_begin(),
+ ExtEnd = CCPrimary->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCPropertyDecl *prevDecl
+ = ObjCPropertyDecl::findPropertyDecl(*Ext, PropertyId)) {
Diag(AtLoc, diag::err_duplicate_property);
Diag(prevDecl->getLocation(), diag::note_property_declare);
return 0;
}
}
-
+ }
+
// Create a new ObjCPropertyDecl with the DeclContext being
// the class extension.
// FIXME. We should really be using CreatePropertyDecl for this.
@@ -296,6 +368,10 @@ Sema::HandlePropertyInClassExtension(Scope *S,
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
// Set setter/getter selector name. Needed later.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
@@ -577,20 +653,20 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
switch (propertyLifetime) {
case Qualifiers::OCL_Strong:
- S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
+ S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)
<< property->getDeclName()
<< ivar->getDeclName()
<< ivarLifetime;
break;
case Qualifiers::OCL_Weak:
- S.Diag(propertyImplLoc, diag::error_weak_property)
+ S.Diag(ivar->getLocation(), diag::error_weak_property)
<< property->getDeclName()
<< ivar->getDeclName();
break;
case Qualifiers::OCL_ExplicitNone:
- S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership)
+ S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
<< property->getDeclName()
<< ivar->getDeclName()
<< ((property->getPropertyAttributesAsWritten()
@@ -606,6 +682,8 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
}
S.Diag(property->getLocation(), diag::note_property_declare);
+ if (propertyImplLoc.isValid())
+ S.Diag(propertyImplLoc, diag::note_property_synthesize);
}
/// setImpliedPropertyAttributeForReadOnlyProperty -
@@ -644,16 +722,18 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl,
ObjCPropertyDecl *property) {
unsigned Attributes = property->getPropertyAttributesAsWritten();
bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly);
- for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
- CDecl; CDecl = CDecl->getNextClassExtension()) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = ClassDecl->known_extensions_begin(),
+ ExtEnd = ClassDecl->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
ObjCPropertyDecl *ClassExtProperty = 0;
- for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
- E = CDecl->prop_end(); P != E; ++P) {
- if ((*P)->getIdentifier() == property->getIdentifier()) {
- ClassExtProperty = *P;
+ DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ ClassExtProperty = dyn_cast<ObjCPropertyDecl>(R[0]);
+ if (ClassExtProperty)
break;
- }
}
+
if (ClassExtProperty) {
warn = false;
unsigned classExtPropertyAttr =
@@ -763,22 +843,40 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return 0;
}
}
-
if (Synthesize&&
(PIkind & ObjCPropertyDecl::OBJC_PR_readonly) &&
property->hasAttr<IBOutletAttr>() &&
!AtLoc.isValid()) {
- Diag(IC->getLocation(), diag::warn_auto_readonly_iboutlet_property);
- Diag(property->getLocation(), diag::note_property_declare);
- SourceLocation readonlyLoc;
- if (LocPropertyAttribute(Context, "readonly",
- property->getLParenLoc(), readonlyLoc)) {
- SourceLocation endLoc =
- readonlyLoc.getLocWithOffset(strlen("readonly")-1);
- SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
- Diag(property->getLocation(),
- diag::note_auto_readonly_iboutlet_fixup_suggest) <<
- FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
+ 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) {
+ DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
+ if (!R.empty())
+ if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) {
+ PIkind = ExtProp->getPropertyAttributesAsWritten();
+ if (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) {
+ ReadWriteProperty = true;
+ break;
+ }
+ }
+ }
+
+ if (!ReadWriteProperty) {
+ Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
+ << property->getName();
+ SourceLocation readonlyLoc;
+ if (LocPropertyAttribute(Context, "readonly",
+ property->getLParenLoc(), readonlyLoc)) {
+ SourceLocation endLoc =
+ readonlyLoc.getLocWithOffset(strlen("readonly")-1);
+ SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
+ Diag(property->getLocation(),
+ diag::note_auto_readonly_iboutlet_fixup_suggest) <<
+ FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
+ }
}
}
@@ -1036,6 +1134,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
MarkDeclRefReferenced(SelfExpr);
Expr *IvarRefExpr =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
+ Ivar->getLocation(),
SelfExpr, true, true);
ExprResult Res =
PerformCopyInitialization(InitializedEntity::InitializeResult(
@@ -1071,6 +1170,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
MarkDeclRefReferenced(SelfExpr);
Expr *lhs =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
+ Ivar->getLocation(),
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
@@ -1198,15 +1298,21 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
}
if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "atomic" << inheritedName;
- if (Property->getSetterName() != SuperProperty->getSetterName())
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
+ if (Property->getSetterName() != SuperProperty->getSetterName()) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "setter" << inheritedName;
- if (Property->getGetterName() != SuperProperty->getGetterName())
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
+ if (Property->getGetterName() != SuperProperty->getGetterName()) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "getter" << inheritedName;
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
QualType LHSType =
Context.getCanonicalType(SuperProperty->getType());
@@ -1270,119 +1376,56 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
return false;
}
-/// ComparePropertiesInBaseAndSuper - This routine compares property
-/// declarations in base and its super class, if any, and issues
-/// diagnostics in a variety of inconsistent situations.
-///
-void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
- ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
- if (!SDecl)
- return;
- // FIXME: O(N^2)
- for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(),
- E = SDecl->prop_end(); S != E; ++S) {
- ObjCPropertyDecl *SuperPDecl = *S;
- // Does property in super class has declaration in current class?
- for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(),
- E = IDecl->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *PDecl = *I;
- if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
- DiagnosePropertyMismatch(PDecl, SuperPDecl,
- SDecl->getIdentifier());
- }
- }
-}
-
/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
/// of properties declared in a protocol and compares their attribute against
/// the same property declared in the class or category.
void
-Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
- ObjCProtocolDecl *PDecl) {
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
- if (!IDecl) {
- // Category
- ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl) {
+ if (!CDecl)
+ return;
+
+ // Category case.
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ // FIXME: We should perform this check when the property in the category
+ // is declared.
assert (CatDecl && "MatchOneProtocolPropertiesInClass");
if (!CatDecl->IsClassExtension())
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = *P;
- ObjCCategoryDecl::prop_iterator CP, CE;
- // Is this property already in category's list of properties?
- for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP)
- if (CP->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier());
+ ObjCPropertyDecl *ProtoProp = *P;
+ DeclContext::lookup_result R
+ = CatDecl->lookup(ProtoProp->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *CatProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ if (CatProp != ProtoProp) {
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch(CatProp, ProtoProp,
+ PDecl->getIdentifier());
+ }
+ }
+ }
}
return;
}
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = *P;
- ObjCInterfaceDecl::prop_iterator CP, CE;
- // Is this property already in class's list of properties?
- for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP)
- if (CP->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier());
- }
-}
-/// CompareProperties - This routine compares properties
-/// declared in 'ClassOrProtocol' objects (which can be a class or an
-/// inherited protocol with the list of properties for class/category 'CDecl'
-///
-void Sema::CompareProperties(Decl *CDecl, Decl *ClassOrProtocol) {
- Decl *ClassDecl = ClassOrProtocol;
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
-
- if (!IDecl) {
- // Category
- ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "CompareProperties");
- if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
- E = MDecl->protocol_end(); P != E; ++P)
- // Match properties of category with those of protocol (*P)
- MatchOneProtocolPropertiesInClass(CatDecl, *P);
-
- // Go thru the list of protocols for this category and recursively match
- // their properties with those in the category.
- for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
- E = CatDecl->protocol_end(); P != E; ++P)
- CompareProperties(CatDecl, *P);
- } else {
- ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
- E = MD->protocol_end(); P != E; ++P)
- MatchOneProtocolPropertiesInClass(CatDecl, *P);
+ // Class
+ // FIXME: We should perform this check when the property in the class
+ // is declared.
+ ObjCInterfaceDecl *IDecl = cast<ObjCInterfaceDecl>(CDecl);
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *ProtoProp = *P;
+ DeclContext::lookup_result R
+ = IDecl->lookup(ProtoProp->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *ClassProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ if (ClassProp != ProtoProp) {
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch(ClassProp, ProtoProp,
+ PDecl->getIdentifier());
+ }
+ }
}
- return;
- }
-
- if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- for (ObjCInterfaceDecl::all_protocol_iterator
- P = MDecl->all_referenced_protocol_begin(),
- E = MDecl->all_referenced_protocol_end(); P != E; ++P)
- // Match properties of class IDecl with those of protocol (*P).
- MatchOneProtocolPropertiesInClass(IDecl, *P);
-
- // Go thru the list of protocols for this class and recursively match
- // their properties with those declared in the class.
- for (ObjCInterfaceDecl::all_protocol_iterator
- P = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); P != E; ++P)
- CompareProperties(IDecl, *P);
- } else {
- ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
- E = MD->protocol_end(); P != E; ++P)
- MatchOneProtocolPropertiesInClass(IDecl, *P);
}
}
@@ -1402,14 +1445,14 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
// Main class has the property as 'readonly'. Must search
// through the category list to see if the property's
// attribute has been over-ridden to 'readwrite'.
- for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- // Even if property is ready only, if a category has a user defined setter,
- // it is not considered read only.
- if (Category->getInstanceMethod(PDecl->getSetterName()))
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IDecl->visible_categories_begin(),
+ CatEnd = IDecl->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (Cat->getInstanceMethod(PDecl->getSetterName()))
return false;
ObjCPropertyDecl *P =
- Category->FindPropertyDeclaration(PDecl->getIdentifier());
+ Cat->FindPropertyDeclaration(PDecl->getIdentifier());
if (P && !P->isReadOnly())
return false;
}
@@ -1438,7 +1481,7 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
}
/// CollectImmediateProperties - This routine collects all properties in
-/// the class and its conforming protocols; but not those it its super class.
+/// the class and its conforming protocols; but not those in its super class.
void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
ObjCContainerDecl::PropertyMap &PropMap,
ObjCContainerDecl::PropertyMap &SuperPropMap) {
@@ -1493,36 +1536,84 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
ObjCInterfaceDecl::PropertyMap &PropMap) {
if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
+ ObjCInterfaceDecl::PropertyDeclOrder PO;
while (SDecl) {
- SDecl->collectPropertiesToImplement(PropMap);
+ SDecl->collectPropertiesToImplement(PropMap, PO);
SDecl = SDecl->getSuperClass();
}
}
}
+/// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
+/// an ivar synthesized for 'Method' and 'Method' is a property accessor
+/// declared in class 'IFace'.
+bool
+Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
+ ObjCMethodDecl *Method, ObjCIvarDecl *IV) {
+ if (!IV->getSynthesize())
+ return false;
+ ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),
+ Method->isInstanceMethod());
+ if (!IMD || !IMD->isPropertyAccessor())
+ return false;
+
+ // 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))
+ return true;
+ }
+ return false;
+}
+
+
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl) {
ObjCInterfaceDecl::PropertyMap PropMap;
- IDecl->collectPropertiesToImplement(PropMap);
+ ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
+ IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
if (PropMap.empty())
return;
ObjCInterfaceDecl::PropertyMap SuperPropMap;
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (ObjCInterfaceDecl::PropertyMap::iterator
- P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = P->second;
+ for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
+ ObjCPropertyDecl *Prop = PropertyOrder[i];
// If property to be implemented in the super class, ignore.
- if (SuperPropMap[Prop->getIdentifier()])
+ if (SuperPropMap[Prop->getIdentifier()]) {
+ ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
+ if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) &&
+ (PropInSuperClass->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_readonly) &&
+ !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
+ !IDecl->HasUserDeclaredSetterMethod(Prop)) {
+ Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
+ << Prop->getIdentifier()->getName();
+ Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
+ }
continue;
+ }
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
+ if (ObjCPropertyImplDecl *PID =
+ IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
+ if (PID->getPropertyDecl() != Prop) {
+ Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
+ << Prop->getIdentifier()->getName();
+ if (!PID->getLocation().isInvalid())
+ Diag(PID->getLocation(), diag::note_property_synthesize);
+ }
+ continue;
+ }
// Property may have been synthesized by user.
if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
continue;
@@ -1571,12 +1662,25 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const SelectorSet &InsMap) {
- ObjCContainerDecl::PropertyMap SuperPropMap;
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
- CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
+ 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);
+ }
+ }
+ if (IDecl)
+ CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
ObjCContainerDecl::PropertyMap PropMap;
- CollectImmediateProperties(CDecl, PropMap, SuperPropMap);
+ CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
if (PropMap.empty())
return;
@@ -1592,7 +1696,8 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// Is there a matching propery synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>())
+ PropImplMap.count(Prop) ||
+ Prop->getAvailability() == AR_Unavailable)
continue;
if (!InsMap.count(Prop->getGetterName())) {
Diag(IMPDecl->getLocation(),
@@ -1829,6 +1934,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (property->hasAttr<NSReturnsNotRetainedAttr>())
GetterMethod->addAttr(
::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
+
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckARCMethodDecl(GetterMethod);
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
@@ -1866,7 +1974,6 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getType().getUnqualifiedType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
SetterMethod->setMethodParams(Context, Argument,
ArrayRef<SourceLocation>());
@@ -1878,6 +1985,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// and the real context should be the same.
if (lexicalDC)
SetterMethod->setLexicalDeclContext(lexicalDC);
+
+ // 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)
+ CheckARCMethodDecl(SetterMethod);
} else
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
new file mode 100644
index 000000000000..b8acb2d7310e
--- /dev/null
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -0,0 +1,181 @@
+//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements semantic analysis for OpenMP directives and
+/// clauses
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclOpenMP.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Lookup.h"
+using namespace clang;
+
+namespace {
+
+ class VarDeclFilterCCC : public CorrectionCandidateCallback {
+ private:
+ Sema &Actions;
+ public:
+ VarDeclFilterCCC(Sema &S) : Actions(S) { }
+ virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+ NamedDecl *ND = Candidate.getCorrectionDecl();
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
+ return VD->hasGlobalStorage() &&
+ Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
+ Actions.getCurScope());
+ }
+ return false;
+ }
+ };
+}
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
+ SourceLocation Loc,
+ Scope *CurScope,
+ ArrayRef<DeclarationNameInfo> IdList) {
+ SmallVector<DeclRefExpr *, 5> Vars;
+ for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(),
+ E = IdList.end();
+ I != E; ++I) {
+ LookupResult Lookup(*this, *I, LookupOrdinaryName);
+ LookupParsedName(Lookup, CurScope, NULL, true);
+
+ if (Lookup.isAmbiguous())
+ continue;
+
+ VarDecl *VD;
+ if (!Lookup.isSingleResult()) {
+ VarDeclFilterCCC Validator(*this);
+ TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope,
+ 0, Validator);
+ std::string CorrectedStr = Corrected.getAsString(getLangOpts());
+ std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
+ if (Lookup.empty()) {
+ if (Corrected.isResolved()) {
+ Diag(I->getLoc(), diag::err_undeclared_var_use_suggest)
+ << I->getName() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
+ } else {
+ Diag(I->getLoc(), diag::err_undeclared_var_use)
+ << I->getName();
+ }
+ } else {
+ Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
+ << I->getName() << Corrected.isResolved() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
+ }
+ if (!Corrected.isResolved()) continue;
+ VD = Corrected.getCorrectionDeclAs<VarDecl>();
+ } else {
+ if (!(VD = Lookup.getAsSingle<VarDecl>())) {
+ Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
+ << I->getName() << 0;
+ Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
+ continue;
+ }
+ }
+
+ // OpenMP [2.9.2, Syntax, C/C++]
+ // Variables must be file-scope, namespace-scope, or static block-scope.
+ if (!VD->hasGlobalStorage()) {
+ Diag(I->getLoc(), diag::err_omp_global_var_arg)
+ << getOpenMPDirectiveName(OMPD_threadprivate)
+ << !VD->isStaticLocal();
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2]
+ // A threadprivate directive for file-scope variables must appear outside
+ // any definition or declaration.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.3]
+ // A threadprivate directive for static class member variables must appear
+ // in the class definition, in the same scope in which the member
+ // variables are declared.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.4]
+ // A threadprivate directive for namespace-scope variables must appear
+ // outside any definition or declaration other than the namespace
+ // definition itself.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.6]
+ // A threadprivate directive for static block-scope variables must appear
+ // in the scope of the variable and not in a nested scope.
+ NamedDecl *ND = cast<NamedDecl>(VD);
+ if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
+ Diag(I->getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
+ // A threadprivate directive must lexically precede all references to any
+ // of the variables in its list.
+ if (VD->isUsed()) {
+ Diag(I->getLoc(), diag::err_omp_var_used)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ continue;
+ }
+
+ QualType ExprType = VD->getType().getNonReferenceType();
+ DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD,
+ ExprType,
+ VK_RValue,
+ I->getLoc()).take());
+ Vars.push_back(Var);
+ }
+ if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
+ CurContext->addDecl(D);
+ return DeclGroupPtrTy::make(DeclGroupRef(D));
+ }
+ return DeclGroupPtrTy();
+}
+
+OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
+ SourceLocation Loc,
+ ArrayRef<DeclRefExpr *> VarList) {
+ SmallVector<DeclRefExpr *, 5> Vars;
+ for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
+ E = VarList.end();
+ I != E; ++I) {
+ VarDecl *VD = cast<VarDecl>((*I)->getDecl());
+ SourceLocation ILoc = (*I)->getLocation();
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.10]
+ // A threadprivate variable must not have an incomplete type.
+ if (RequireCompleteType(ILoc, VD->getType(),
+ diag::err_omp_incomplete_type)) {
+ continue;
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.10]
+ // 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();
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ // Check if threadspecified is set.
+ if (VD->isThreadSpecified()) {
+ Diag(ILoc, diag::err_omp_var_thread_local) << VD;
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ Vars.push_back(*I);
+ }
+ return Vars.empty() ?
+ 0 : OMPThreadPrivateDecl::Create(Context,
+ getCurLexicalContext(),
+ Loc, Vars);
+}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 911187857fe1..89d495ddc197 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1,4 +1,4 @@
-//===--- SemaOverload.cpp - C++ Overloading ---------------------*- C++ -*-===//
+//===--- SemaOverload.cpp - C++ Overloading -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,13 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Template.h"
-#include "clang/Sema/TemplateDeduction.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Overload.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -25,26 +19,37 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
#include <algorithm>
namespace clang {
using namespace sema;
-/// A convenience routine for creating a decayed reference to a
-/// function.
+/// A convenience routine for creating a decayed reference to a function.
static ExprResult
-CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates,
+CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
+ bool HadMultipleCandidates,
SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(),
VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
+
+ S.MarkDeclRefReferenced(DRE);
+ S.DiagnoseUseOfDecl(FoundDecl, Loc);
+
ExprResult E = S.Owned(DRE);
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
@@ -535,12 +540,16 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
namespace {
// Structure used by OverloadCandidate::DeductionFailureInfo to store
- // template parameter and template argument information.
- struct DFIParamWithArguments {
- TemplateParameter Param;
+ // template argument information.
+ struct DFIArguments {
TemplateArgument FirstArg;
TemplateArgument SecondArg;
};
+ // Structure used by OverloadCandidate::DeductionFailureInfo to store
+ // template parameter and template argument information.
+ struct DFIParamWithArguments : DFIArguments {
+ TemplateParameter Param;
+ };
}
/// \brief Convert from Sema's representation of template deduction information
@@ -566,6 +575,15 @@ static MakeDeductionFailureInfo(ASTContext &Context,
Result.Data = Info.Param.getOpaqueValue();
break;
+ case Sema::TDK_NonDeducedMismatch: {
+ // FIXME: Should allocate from normal heap so that we can free this later.
+ DFIArguments *Saved = new (Context) DFIArguments;
+ Saved->FirstArg = Info.FirstArg;
+ Saved->SecondArg = Info.SecondArg;
+ Result.Data = Saved;
+ break;
+ }
+
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified: {
// FIXME: Should allocate from normal heap so that we can free this later.
@@ -587,8 +605,11 @@ static MakeDeductionFailureInfo(ASTContext &Context,
}
break;
- case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
+ Result.Data = Info.Expression;
+ break;
+
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
@@ -604,10 +625,12 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_FailedOverloadResolution:
break;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
+ case Sema::TDK_NonDeducedMismatch:
// FIXME: Destroy the data?
Data = 0;
break;
@@ -622,8 +645,7 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
break;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
}
@@ -644,6 +666,8 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -655,8 +679,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
return static_cast<DFIParamWithArguments*>(Data)->Param;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
@@ -666,24 +689,25 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
TemplateArgumentList *
OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
- case Sema::TDK_Success:
- case Sema::TDK_Invalid:
- case Sema::TDK_InstantiationDepth:
- case Sema::TDK_TooManyArguments:
- case Sema::TDK_TooFewArguments:
- case Sema::TDK_Incomplete:
- case Sema::TDK_InvalidExplicitArguments:
- case Sema::TDK_Inconsistent:
- case Sema::TDK_Underqualified:
- return 0;
+ case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_Underqualified:
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ return 0;
- case Sema::TDK_SubstitutionFailure:
- return static_cast<TemplateArgumentList*>(Data);
+ case Sema::TDK_SubstitutionFailure:
+ return static_cast<TemplateArgumentList*>(Data);
- // Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
- break;
+ // Unhandled
+ case Sema::TDK_MiscellaneousDeductionFailure:
+ break;
}
return 0;
@@ -699,15 +723,16 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_FailedOverloadResolution:
return 0;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
- return &static_cast<DFIParamWithArguments*>(Data)->FirstArg;
+ case Sema::TDK_NonDeducedMismatch:
+ return &static_cast<DFIArguments*>(Data)->FirstArg;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
@@ -725,21 +750,31 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_FailedOverloadResolution:
return 0;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
- return &static_cast<DFIParamWithArguments*>(Data)->SecondArg;
+ case Sema::TDK_NonDeducedMismatch:
+ return &static_cast<DFIArguments*>(Data)->SecondArg;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
return 0;
}
+Expr *
+OverloadCandidate::DeductionFailureInfo::getExpr() {
+ if (static_cast<Sema::TemplateDeductionResult>(Result) ==
+ Sema::TDK_FailedOverloadResolution)
+ return static_cast<Expr*>(Data);
+
+ return 0;
+}
+
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
@@ -885,7 +920,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
// function templates hide function templates with different
// return types or template parameter lists.
bool UseMemberUsingDeclRules =
- (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord();
+ (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord() &&
+ !New->getFriendObjectKind();
if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) {
if (!IsOverload(New, OldT->getTemplatedDecl(), UseMemberUsingDeclRules)) {
@@ -929,13 +965,21 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
return Ovl_Overload;
}
-bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
- // If both of the functions are extern "C", then they are not
- // overloads.
- if (Old->isExternC() && New->isExternC())
+static bool canBeOverloaded(const FunctionDecl &D) {
+ if (D.getAttr<OverloadableAttr>())
+ return true;
+ if (D.isExternC())
+ return false;
+
+ // Main cannot be overloaded (basic.start.main).
+ if (D.isMain())
return false;
+ return true;
+}
+
+static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
@@ -946,8 +990,8 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return true;
// Is the function New an overload of the function Old?
- QualType OldQType = Context.getCanonicalType(Old->getType());
- QualType NewQType = Context.getCanonicalType(New->getType());
+ QualType OldQType = S.Context.getCanonicalType(Old->getType());
+ QualType NewQType = S.Context.getCanonicalType(New->getType());
// Compare the signatures (C++ 1.3.10) of the two functions to
// determine whether they are overloads. If we find any mismatch
@@ -968,7 +1012,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (OldQType != NewQType &&
(OldType->getNumArgs() != NewType->getNumArgs() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !FunctionArgTypesAreEqual(OldType, NewType)))
+ !S.FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -984,9 +1028,9 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// However, we don't consider either of these when deciding whether
// a member introduced by a shadow declaration is hidden.
if (!UseUsingDeclRules && NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, TPL_TemplateMatch) ||
+ (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ false, S.TPL_TemplateMatch) ||
OldType->getResultType() != NewType->getResultType()))
return true;
@@ -998,34 +1042,55 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// 13.1p2). While not part of the definition of the signature,
// this check is important to determine whether these functions
// can be overloaded.
- CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New);
if (OldMethod && NewMethod &&
- !OldMethod->isStatic() && !NewMethod->isStatic() &&
- (OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() ||
- OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) {
- if (!UseUsingDeclRules &&
- OldMethod->getRefQualifier() != NewMethod->getRefQualifier() &&
- (OldMethod->getRefQualifier() == RQ_None ||
- NewMethod->getRefQualifier() == RQ_None)) {
- // C++0x [over.load]p2:
- // - Member function declarations with the same name and the same
- // parameter-type-list as well as member function template
- // declarations with the same name, the same parameter-type-list, and
- // the same template parameter lists cannot be overloaded if any of
- // them, but not all, have a ref-qualifier (8.3.5).
- Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
- << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
- Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ !OldMethod->isStatic() && !NewMethod->isStatic()) {
+ if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) {
+ if (!UseUsingDeclRules &&
+ (OldMethod->getRefQualifier() == RQ_None ||
+ NewMethod->getRefQualifier() == RQ_None)) {
+ // C++0x [over.load]p2:
+ // - Member function declarations with the same name and the same
+ // parameter-type-list as well as member function template
+ // declarations with the same name, the same parameter-type-list, and
+ // the same template parameter lists cannot be overloaded if any of
+ // them, but not all, have a ref-qualifier (8.3.5).
+ S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
+ << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
+ S.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ }
+ return true;
}
- return true;
+ // We may not have applied the implicit const for a constexpr member
+ // function yet (because we haven't yet resolved whether this is a static
+ // or non-static member function). Add it now, on the assumption that this
+ // is a redeclaration of OldMethod.
+ unsigned NewQuals = NewMethod->getTypeQualifiers();
+ if (NewMethod->isConstexpr() && !isa<CXXConstructorDecl>(NewMethod))
+ NewQuals |= Qualifiers::Const;
+ if (OldMethod->getTypeQualifiers() != NewQuals)
+ return true;
}
// The signatures match; this is not an overload.
return false;
}
+bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
+ if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules))
+ return false;
+
+ // If both of the functions are extern "C", then they are not
+ // overloads.
+ if (!canBeOverloaded(*Old) && !canBeOverloaded(*New))
+ return false;
+
+ return true;
+}
+
/// \brief Checks availability of the function depending on the current
/// function context. Inside an unavailable function, unavailability is ignored.
///
@@ -1577,6 +1642,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// tryAtomicConversion has updated the standard conversion sequence
// appropriately.
return true;
+ } else if (ToType->isEventT() &&
+ From->isIntegerConstantExpr(S.getASTContext()) &&
+ (From->EvaluateKnownConstInt(S.getASTContext()) == 0)) {
+ SCS.Second = ICK_Zero_Event_Conversion;
+ FromType = ToType;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@@ -1606,9 +1676,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
CanonTo = S.Context.getCanonicalType(ToType);
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
- (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
- || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr()
- || CanonFrom.getObjCLifetime() != CanonTo.getObjCLifetime())) {
+ CanonFrom.getLocalQualifiers() != CanonTo.getLocalQualifiers()) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -1818,7 +1886,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
return true;
// Half can be promoted to float.
- if (FromBuiltin->getKind() == BuiltinType::Half &&
+ if (!getLangOpts().NativeHalfType &&
+ FromBuiltin->getKind() == BuiltinType::Half &&
ToBuiltin->getKind() == BuiltinType::Float)
return true;
}
@@ -2880,8 +2949,8 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(To);
+ DeclContext::lookup_result R = S.LookupConstructors(To);
+ for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -2980,7 +3049,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
S.IsDerivedFrom(From->getType(), ToType)))
ConstructorsOnly = true;
- S.RequireCompleteType(From->getLocStart(), ToType, 0);
+ S.RequireCompleteType(From->getExprLoc(), ToType, 0);
// RequireCompleteType may have returned true due to some invalid decl
// during template instantiation, but ToType may be complete enough now
// to try to recover.
@@ -3008,8 +3077,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ListInitializing = true;
}
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
+ DeclContext::lookup_result R = S.LookupConstructors(ToRecordDecl);
+ for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -3065,10 +3134,11 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
- const UnresolvedSetImpl *Conversions
- = FromRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = FromRecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
DeclAccessPair FoundDecl = I.getPair();
NamedDecl *D = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
@@ -3198,7 +3268,7 @@ static ImplicitConversionSequence::CompareKind
compareConversionFunctions(Sema &S,
FunctionDecl *Function1,
FunctionDecl *Function2) {
- if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus0x)
+ if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus11)
return ImplicitConversionSequence::Indistinguishable;
// Objective-C++:
@@ -3868,6 +3938,15 @@ CompareDerivedToBaseConversions(Sema &S,
return ImplicitConversionSequence::Indistinguishable;
}
+/// \brief Determine whether the given type is valid, e.g., it is not an invalid
+/// C++ class.
+static bool isTypeValid(QualType T) {
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
+ return !Record->isInvalidDecl();
+
+ return true;
+}
+
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
/// determine whether they are reference-related,
/// reference-compatible, reference-compatible with added
@@ -3901,7 +3980,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (!RequireCompleteType(Loc, OrigT2, 0) &&
- IsDerivedFrom(UnqualT2, UnqualT1))
+ isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
+ IsDerivedFrom(UnqualT2, UnqualT1))
DerivedToBase = true;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
@@ -3959,10 +4039,11 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(DeclLoc);
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = T2RecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -4213,7 +4294,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// allow the use of rvalue references in C++98/03 for the benefit of
// standard library implementors; therefore, we need the xvalue check here.
ICS.Standard.DirectBinding =
- S.getLangOpts().CPlusPlus0x ||
+ S.getLangOpts().CPlusPlus11 ||
(InitCategory.isPRValue() && !T2->isRecordType());
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
@@ -4374,7 +4455,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
bool toStdInitializerList = false;
QualType X;
if (ToType->isArrayType())
- X = S.Context.getBaseElementType(ToType);
+ X = S.Context.getAsArrayType(ToType)->getElementType();
else
toStdInitializerList = S.isStdInitializerList(ToType, &X);
if (!X.isNull()) {
@@ -4595,7 +4676,7 @@ static bool TryCopyInitialization(const CanQualType FromQTy,
/// parameter of the given member function (@c Method) from the
/// expression @p From.
static ImplicitConversionSequence
-TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
+TryObjectArgumentInitialization(Sema &S, QualType FromType,
Expr::Classification FromClassification,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
@@ -4611,7 +4692,6 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
ImplicitConversionSequence ICS;
// We need to have an object of class type.
- QualType FromType = OrigFromType;
if (const PointerType *PT = FromType->getAs<PointerType>()) {
FromType = PT->getPointeeType();
@@ -4646,7 +4726,7 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
!= FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
ICS.setBad(BadConversionSequence::bad_qualifiers,
- OrigFromType, ImplicitParamType);
+ FromType, ImplicitParamType);
return ICS;
}
@@ -4811,6 +4891,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
case ICK_Identity:
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
+ case ICK_Zero_Event_Conversion:
return true;
case ICK_Boolean_Conversion:
@@ -4857,7 +4938,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value,
CCEKind CCE) {
- assert(LangOpts.CPlusPlus0x && "converted constant expression outside C++11");
+ assert(LangOpts.CPlusPlus11 && "converted constant expression outside C++11");
assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
if (checkPlaceholderForOverload(*this, From))
@@ -4939,7 +5020,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
}
// Check the expression is a constant expression.
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
Expr::EvalResult Eval;
Eval.Diag = &Notes;
@@ -5104,15 +5185,15 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
// Look for a conversion to an integral or enumeration type.
UnresolvedSet<4> ViableConversions;
UnresolvedSet<4> ExplicitConversions;
- const UnresolvedSetImpl *Conversions
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
- bool HadMultipleCandidates = (Conversions->size() > 1);
+ bool HadMultipleCandidates
+ = (std::distance(Conversions.first, Conversions.second) > 1);
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E;
- ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
if (isIntegralOrEnumerationType(
@@ -5230,7 +5311,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
void
Sema::AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
@@ -5353,7 +5434,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
/// \brief Add all of the function declarations in the given function set to
/// the overload canddiate set.
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
TemplateArgumentListInfo *ExplicitTemplateArgs) {
@@ -5428,7 +5509,7 @@ void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
const FunctionProtoType* Proto
@@ -5532,7 +5613,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(MethodTmpl))
@@ -5582,7 +5663,7 @@ void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(FunctionTemplate))
@@ -5816,7 +5897,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
Expr *Object,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet) {
if (!CandidateSet.isNewCandidate(Conversion))
return;
@@ -6286,10 +6367,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
return;
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSetImpl *Conversions
- = ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = ClassDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -6355,11 +6437,12 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
if (!ClassDecl->hasDefinition())
return VRQuals;
- const UnresolvedSetImpl *Conversions =
- ClassDecl->getVisibleConversionFunctions();
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -7449,7 +7532,7 @@ public:
S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet);
}
- if (S.getLangOpts().CPlusPlus0x) {
+ if (S.getLangOpts().CPlusPlus11) {
for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
@@ -7667,7 +7750,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
bool Operator, SourceLocation Loc,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
@@ -8380,7 +8463,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
case Sema::TDK_SubstitutionFailure: {
// Format the template argument list into the argument string.
- llvm::SmallString<128> TemplateArgString;
+ SmallString<128> TemplateArgString;
if (TemplateArgumentList *Args =
Cand->DeductionFailure.getTemplateArgumentList()) {
TemplateArgString = " ";
@@ -8402,7 +8485,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
// Format the SFINAE diagnostic into the argument string.
// FIXME: Add a general mechanism to include a PartialDiagnostic *'s
// formatted message in another diagnostic.
- llvm::SmallString<128> SFINAEArgString;
+ SmallString<128> SFINAEArgString;
SourceRange R;
if (PDiag) {
SFINAEArgString = ": ";
@@ -8416,10 +8499,25 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
return;
}
+ case Sema::TDK_FailedOverloadResolution: {
+ OverloadExpr::FindResult R =
+ OverloadExpr::find(Cand->DeductionFailure.getExpr());
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_failed_overload_resolution)
+ << R.Expression->getName();
+ return;
+ }
+
+ case Sema::TDK_NonDeducedMismatch:
+ // FIXME: Provide a source location to indicate what we couldn't match.
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch)
+ << *Cand->DeductionFailure.getFirstArg()
+ << *Cand->DeductionFailure.getSecondArg();
+ return;
+
// TODO: diagnose these individually, then kill off
// note_ovl_candidate_bad_deduction, which is uselessly vague.
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
MaybeEmitInheritedConstructorNote(S, Fn);
return;
@@ -8597,6 +8695,7 @@ RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_MiscellaneousDeductionFailure:
return 3;
case Sema::TDK_InstantiationDepth:
@@ -8721,7 +8820,7 @@ struct CompareOverloadCandidatesForDisplay {
/// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first. Produces the FixIt set if possible.
void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
@@ -8809,7 +8908,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
/// set.
void OverloadCandidateSet::NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
StringRef Opc,
SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
@@ -9400,7 +9499,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
static void AddOverloadedCallCandidate(Sema &S,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading,
bool KnownValid) {
@@ -9431,7 +9530,7 @@ static void AddOverloadedCallCandidate(Sema &S,
/// \brief Add the overload candidates named by callee and/or found by argument
/// dependent lookup to the given overload set.
void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
@@ -9495,7 +9594,7 @@ static bool
DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
const CXXScopeSpec &SS, LookupResult &R,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
return false;
@@ -9536,18 +9635,23 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
SemaRef.FindAssociatedClassesAndNamespaces(FnLoc, Args,
AssociatedNamespaces,
AssociatedClasses);
- // Never suggest declaring a function within namespace 'std'.
Sema::AssociatedNamespaceSet SuggestedNamespaces;
- if (DeclContext *Std = SemaRef.getStdNamespace()) {
- for (Sema::AssociatedNamespaceSet::iterator
- it = AssociatedNamespaces.begin(),
- end = AssociatedNamespaces.end(); it != end; ++it) {
- if (!Std->Encloses(*it))
- SuggestedNamespaces.insert(*it);
- }
- } else {
- // Lacking the 'std::' namespace, use all of the associated namespaces.
- SuggestedNamespaces = AssociatedNamespaces;
+ DeclContext *Std = SemaRef.getStdNamespace();
+ for (Sema::AssociatedNamespaceSet::iterator
+ it = AssociatedNamespaces.begin(),
+ end = AssociatedNamespaces.end(); it != end; ++it) {
+ // Never suggest declaring a function within namespace 'std'.
+ if (Std && Std->Encloses(*it))
+ continue;
+
+ // Never suggest declaring a function within a namespace with a reserved
+ // name, like __gnu_cxx.
+ NamespaceDecl *NS = dyn_cast<NamespaceDecl>(*it);
+ if (NS &&
+ NS->getQualifiedNameAsString().find("__") != std::string::npos)
+ continue;
+
+ SuggestedNamespaces.insert(*it);
}
SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup)
@@ -9587,7 +9691,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
static bool
DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
SourceLocation OpLoc,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
DeclarationName OpName =
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
@@ -9827,7 +9931,6 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
switch (OverloadResult) {
case OR_Success: {
FunctionDecl *FDecl = (*Best)->Function;
- SemaRef.MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl);
SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
@@ -10015,8 +10118,6 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkFunctionReferenced(OpLoc, FnDecl);
-
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
@@ -10040,15 +10141,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Input = InputInit.take();
}
- DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
-
// Determine the result type.
QualType ResultTy = FnDecl->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -10240,8 +10339,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkFunctionReferenced(OpLoc, FnDecl);
-
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
@@ -10282,8 +10379,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Args[1] = RHS = Arg1.takeAs<Expr>();
}
- DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
-
// Determine the result type.
QualType ResultTy = FnDecl->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
@@ -10291,6 +10386,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -10304,6 +10400,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
FnDecl))
return ExprError();
+ ArrayRef<const Expr *> ArgsArray(Args, 2);
+ // Cut off the implicit 'this'.
+ if (isa<CXXMethodDecl>(FnDecl))
+ ArgsArray = ArgsArray.slice(1);
+ checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc,
+ TheCall->getSourceRange(), VariadicDoesNotApply);
+
return MaybeBindToTemporary(TheCall);
} else {
// We matched a built-in operator. Convert the arguments, then
@@ -10376,16 +10479,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (isImplicitlyDeleted(Best->Function)) {
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
Diag(OpLoc, diag::err_ovl_deleted_special_oper)
- << getSpecialMember(Method)
- << BinaryOperator::getOpcodeStr(Opc)
- << getDeletedOrUnavailableSuffix(Best->Function);
+ << Context.getRecordType(Method->getParent())
+ << getSpecialMember(Method);
- if (getSpecialMember(Method) != CXXInvalid) {
- // The user probably meant to call this special member. Just
- // explain why it's deleted.
- NoteDeletedFunction(Method);
- return ExprError();
- }
+ // The user probably meant to call this special member. Just
+ // explain why it's deleted.
+ NoteDeletedFunction(Method);
+ return ExprError();
} else {
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
@@ -10463,10 +10563,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkFunctionReferenced(LLoc, FnDecl);
-
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
- DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -10498,6 +10595,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
DeclarationNameInfo OpLocInfo(OpName, LLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ Best->FoundDecl,
HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
@@ -10715,7 +10813,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
- MarkFunctionReferenced(UnresExpr->getMemberLoc(), Method);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
@@ -10880,10 +10977,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- const UnresolvedSetImpl *Conversions
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -10989,9 +11087,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
RParenLoc);
}
- MarkFunctionReferenced(LParenLoc, Best->Function);
CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
- DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
@@ -11025,7 +11121,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
DeclarationNameInfo OpLocInfo(
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc));
- ExprResult NewFn = CreateFunctionRefExpr(*this, Method,
+ ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
@@ -11190,9 +11286,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
return ExprError();
}
- MarkFunctionReferenced(OpLoc, Best->Function);
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
- DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
@@ -11204,7 +11298,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
Base = BaseResult.take();
// Build the operator call.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, Method,
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -11259,10 +11353,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
}
FunctionDecl *FD = Best->Function;
- MarkFunctionReferenced(UDSuffixLoc, FD);
- DiagnoseUseOfDecl(Best->FoundDecl, UDSuffixLoc);
-
- ExprResult Fn = CreateFunctionRefExpr(*this, FD, HadMultipleCandidates,
+ ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl,
+ HadMultipleCandidates,
SuffixInfo.getLoc(),
SuffixInfo.getInfo());
if (Fn.isInvalid())
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index a8d75b290f19..b135507b1ac0 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -31,10 +31,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -113,7 +114,7 @@ namespace {
Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) {
// Fortunately, the constraint that we're rebuilding something
// with a base limits the number of cases here.
- assert(refExpr->getBase());
+ assert(refExpr->isObjectReceiver());
if (refExpr->isExplicitProperty()) {
return new (S.Context)
@@ -562,8 +563,9 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
if (const ObjCInterfaceDecl *IFace =
dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) {
const StringRef thisPropertyName(prop->getName());
+ // Try flipping the case of the first character.
char front = thisPropertyName.front();
- front = islower(front) ? toupper(front) : tolower(front);
+ front = isLowercase(front) ? toUppercase(front) : toLowercase(front);
SmallString<100> PropertyName = thisPropertyName;
PropertyName[0] = front;
IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName);
@@ -713,10 +715,9 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {
// Explicit properties always have getters, but implicit ones don't.
// Check that before proceeding.
- if (RefExpr->isImplicitProperty() &&
- !RefExpr->getImplicitPropertyGetter()) {
+ if (RefExpr->isImplicitProperty() && !RefExpr->getImplicitPropertyGetter()) {
S.Diag(RefExpr->getLocation(), diag::err_getter_not_found)
- << RefExpr->getBase()->getType();
+ << RefExpr->getSourceRange();
return ExprError();
}
@@ -954,16 +955,15 @@ Sema::ObjCSubscriptKind
// objective-C pointer type.
UnresolvedSet<4> ViableConversions;
UnresolvedSet<4> ExplicitConversions;
- const UnresolvedSetImpl *Conversions
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
int NoIntegrals=0, NoObjCIdPointers=0;
SmallVector<CXXConversionDecl *, 4> ConversionDecls;
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E;
- ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
QualType CT = Conversion->getConversionType().getNonReferenceType();
@@ -1087,7 +1087,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
: S.Context.getObjCIdType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
AtIndexGetter->setMethodParams(S.Context, Argument,
ArrayRef<SourceLocation>());
@@ -1202,7 +1201,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
S.Context.getObjCIdType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
Params.push_back(object);
ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter,
@@ -1213,7 +1211,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
: S.Context.getObjCIdType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
Params.push_back(key);
AtIndexSetter->setMethodParams(S.Context, Params, ArrayRef<SourceLocation>());
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index f55174e05cc1..ff1db821b658 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -12,21 +12,22 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.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/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -35,9 +36,13 @@
using namespace clang;
using namespace sema;
-StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
- Expr *E = expr.get();
- if (!E) // FIXME: FullExprArg has no error state?
+StmtResult Sema::ActOnExprStmt(ExprResult FE) {
+ if (FE.isInvalid())
+ return StmtError();
+
+ FE = ActOnFinishFullExpr(FE.get(), FE.get()->getExprLoc(),
+ /*DiscardedValue*/ true);
+ if (FE.isInvalid())
return StmtError();
// C99 6.8.3p2: The expression in an expression statement is evaluated as a
@@ -45,10 +50,15 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
// operand, even incomplete types.
// Same thing in for stmt first clause (when expr) and third clause.
- return Owned(static_cast<Stmt*>(E));
+ return Owned(static_cast<Stmt*>(FE.take()));
}
+StmtResult Sema::ActOnExprStmtError() {
+ DiscardCleanupsInEvaluationContext();
+ return StmtError();
+}
+
StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
bool HasLeadingEmptyMacro) {
return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro));
@@ -125,7 +135,7 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
// Suppress warnings when the operator, suspicious as it may be, comes from
// a macro expansion.
- if (Loc.isMacroID())
+ if (S.SourceMgr.isMacroBodyExpansion(Loc))
return false;
S.Diag(Loc, diag::warn_unused_comparison)
@@ -152,12 +162,20 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
const Expr *E = dyn_cast_or_null<Expr>(S);
if (!E)
return;
+ SourceLocation ExprLoc = E->IgnoreParens()->getExprLoc();
+ // In most cases, we don't want to warn if the expression is written in a
+ // macro body, or if the macro comes from a system header. If the offending
+ // expression is a call to a function with the warn_unused_result attribute,
+ // we warn no matter the location. Because of the order in which the various
+ // checks need to happen, we factor out the macro-related test here.
+ bool ShouldSuppress =
+ SourceMgr.isMacroBodyExpansion(ExprLoc) ||
+ SourceMgr.isInSystemMacro(ExprLoc);
const Expr *WarnExpr;
SourceLocation Loc;
SourceRange R1, R2;
- if (SourceMgr.isInSystemMacro(E->getExprLoc()) ||
- !E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
+ if (!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
return;
// If this is a GNU statement expression expanded from a macro, it is probably
@@ -185,12 +203,16 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
// If the callee has attribute pure, const, or warn_unused_result, warn with
- // a more specific message to make it clear what is happening.
+ // a more specific message to make it clear what is happening. If the call
+ // 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>()) {
Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
+ if (ShouldSuppress)
+ return;
if (FD->getAttr<PureAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
return;
@@ -200,7 +222,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
}
}
- } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ } else if (ShouldSuppress)
+ return;
+
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) {
Diag(Loc, diag::err_arc_unused_init_message) << R1;
return;
@@ -229,7 +254,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
// We really do want to use the non-canonical type here.
if (T == Context.VoidPtrTy) {
- PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc());
+ PointerTypeLoc TL = TI->getTypeLoc().castAs<PointerTypeLoc>();
Diag(Loc, diag::warn_unused_voidptr)
<< FixItHint::CreateRemoval(TL.getStarLoc());
@@ -298,7 +323,9 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
}
- return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
+ return Owned(new (Context) CompoundStmt(Context,
+ llvm::makeArrayRef(Elts, NumElts),
+ L, R));
}
StmtResult
@@ -312,7 +339,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
return StmtError();
}
- if (!getLangOpts().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus11) {
// C99 6.8.4.2p3: The expression shall be an integer constant.
// However, GCC allows any evaluatable integer expression.
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent()) {
@@ -328,6 +355,12 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
// Recover from an error by just forgetting about it.
}
}
+
+ LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
+ getLangOpts().CPlusPlus11).take();
+ if (RHSVal)
+ RHSVal = ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
+ getLangOpts().CPlusPlus11).take();
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
ColonLoc);
@@ -390,6 +423,13 @@ StmtResult
Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
Stmt *thenStmt, SourceLocation ElseLoc,
Stmt *elseStmt) {
+ // If the condition was invalid, discard the if statement. We could recover
+ // better by replacing it with a valid expr, but don't do that yet.
+ if (!CondVal.get() && !CondVar) {
+ getCurFunction()->setHasDroppedStmt();
+ return StmtError();
+ }
+
ExprResult CondResult(CondVal.release());
VarDecl *ConditionVar = 0;
@@ -595,8 +635,7 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
Cond = CondResult.take();
if (!CondVar) {
- CheckImplicitConversions(Cond, SwitchLoc);
- CondResult = MaybeCreateExprWithCleanups(Cond);
+ CondResult = ActOnFinishFullExpr(Cond, SwitchLoc);
if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
@@ -710,7 +749,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
llvm::APSInt LoVal;
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++11 [stmt.switch]p2: the constant-expression shall be a converted
// constant expression of the promoted type of the switch condition.
ExprResult ConvLo =
@@ -792,7 +831,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(CurrCase)) {
CurrString = DeclRef->getDecl()->getName();
}
- llvm::SmallString<16> CaseValStr;
+ SmallString<16> CaseValStr;
CaseVals[i-1].first.toString(CaseValStr);
if (PrevString == CurrString)
@@ -830,7 +869,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Expr *Hi = CR->getRHS();
llvm::APSInt HiVal;
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++11 [stmt.switch]p2: the constant-expression shall be a converted
// constant expression of the promoted type of the switch condition.
ExprResult ConvHi =
@@ -1149,12 +1188,11 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
assert(Cond && "ActOnDoStmt(): missing expression");
ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
- if (CondResult.isInvalid() || CondResult.isInvalid())
+ if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
- CheckImplicitConversions(Cond, DoLoc);
- CondResult = MaybeCreateExprWithCleanups(Cond);
+ CondResult = ActOnFinishFullExpr(Cond, DoLoc);
if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
@@ -1170,13 +1208,13 @@ namespace {
// of the excluded constructs are used.
class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
llvm::SmallPtrSet<VarDecl*, 8> &Decls;
- llvm::SmallVector<SourceRange, 10> &Ranges;
+ SmallVector<SourceRange, 10> &Ranges;
bool Simple;
public:
typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
- llvm::SmallVector<SourceRange, 10> &Ranges) :
+ SmallVector<SourceRange, 10> &Ranges) :
Inherited(S.Context),
Decls(Decls),
Ranges(Ranges),
@@ -1325,7 +1363,7 @@ public:
PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
llvm::SmallPtrSet<VarDecl*, 8> Decls;
- llvm::SmallVector<SourceRange, 10> Ranges;
+ SmallVector<SourceRange, 10> Ranges;
DeclExtractor DE(S, Decls, Ranges);
DE.Visit(Second);
@@ -1361,8 +1399,8 @@ public:
// Load SourceRanges into diagnostic if there is room.
// Otherwise, load the SourceRange of the conditional expression.
if (Ranges.size() <= PartialDiagnostic::MaxArguments)
- for (llvm::SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
- E = Ranges.end();
+ for (SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
+ E = Ranges.end();
I != E; ++I)
PDiag << *I;
else
@@ -1432,12 +1470,10 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
if (result.isInvalid()) return StmtError();
E = result.take();
- CheckImplicitConversions(E);
-
- result = MaybeCreateExprWithCleanups(E);
- if (result.isInvalid()) return StmtError();
-
- return Owned(static_cast<Stmt*>(result.take()));
+ ExprResult FullExpr = ActOnFinishFullExpr(E);
+ if (FullExpr.isInvalid())
+ return StmtError();
+ return StmtResult(static_cast<Stmt*>(FullExpr.take()));
}
ExprResult
@@ -1508,7 +1544,7 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
}
// Wrap up any cleanups in the expression.
- return Owned(MaybeCreateExprWithCleanups(collection));
+ return Owned(collection);
}
StmtResult
@@ -1553,6 +1589,10 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
if (CollectionExprResult.isInvalid())
return StmtError();
+ CollectionExprResult = ActOnFinishFullExpr(CollectionExprResult.take());
+ if (CollectionExprResult.isInvalid())
+ return StmtError();
+
return Owned(new (Context) ObjCForCollectionStmt(First,
CollectionExprResult.take(), 0,
ForLoc, RParenLoc));
@@ -1625,7 +1665,7 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
- TInfo, SC_Auto, SC_None);
+ TInfo, SC_None);
Decl->setImplicit();
return Decl;
}
@@ -1937,8 +1977,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
Diag(Range->getLocStart(), diag::err_for_range_invalid)
<< RangeLoc << Range->getType() << BEFFailure;
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(&Range, /*NumArgs=*/1));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Range);
}
// Return an error if no fix was discovered.
if (RangeStatus != FRS_Success)
@@ -2096,9 +2135,13 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
E = ExprRes.take();
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
- E = MaybeCreateExprWithCleanups(E);
}
+ ExprResult ExprRes = ActOnFinishFullExpr(E);
+ if (ExprRes.isInvalid())
+ return StmtError();
+ E = ExprRes.take();
+
getCurFunction()->setHasIndirectGoto();
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
@@ -2370,8 +2413,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.take();
}
ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
NRVOCandidate);
@@ -2400,8 +2445,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
QualType RelatedRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
- if (FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
+ if (FD->isNoReturn())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< FD->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
@@ -2473,8 +2517,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.take();
}
}
@@ -2490,24 +2536,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
Result = new (Context) ReturnStmt(ReturnLoc);
} else {
+ assert(RetValExp || FnRetType->isDependentType());
const VarDecl *NRVOCandidate = 0;
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
// we have a non-void function with an expression, continue checking
- if (!RelatedRetType.isNull()) {
- // If we have a related result type, perform an extra conversion here.
- // FIXME: The diagnostics here don't really describe what is happening.
- InitializedEntity Entity =
- InitializedEntity::InitializeTemporary(RelatedRetType);
-
- ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(),
- RetValExp);
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
- }
- RetValExp = Res.takeAs<Expr>();
- }
+ 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
@@ -2517,23 +2551,40 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// the C version of which boils down to CheckSingleAssignmentConstraints.
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType,
+ RetType,
NRVOCandidate != 0);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
- FnRetType, RetValExp);
+ RetType, RetValExp);
if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
+ // FIXME: Clean up temporaries here anyway?
return StmtError();
}
-
RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ // If we have a related result type, we need to implicitly
+ // convert back to the formal result type. We can't pretend to
+ // initialize the result again --- we might end double-retaining
+ // --- so instead we initialize a notional temporary; this can
+ // lead to less-than-great diagnostics, but this stage is much
+ // less likely to fail than the previous stage.
+ if (!RelatedRetType.isNull()) {
+ Entity = InitializedEntity::InitializeTemporary(FnRetType);
+ Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp);
+ if (Res.isInvalid()) {
+ // FIXME: Clean up temporaries here anyway?
+ return StmtError();
+ }
+ RetValExp = Res.takeAs<Expr>();
+ }
+
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.take();
}
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
@@ -2583,7 +2634,11 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
if (Result.isInvalid())
return StmtError();
- Throw = MaybeCreateExprWithCleanups(Result.take());
+ Result = ActOnFinishFullExpr(Result.take());
+ if (Result.isInvalid())
+ return StmtError();
+ Throw = Result.take();
+
QualType ThrowType = Throw->getType();
// Make sure the expression type is an ObjC pointer or "void *".
if (!ThrowType->isDependentType() &&
@@ -2634,7 +2689,7 @@ Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
}
// The operand to @synchronized is a full-expression.
- return MaybeCreateExprWithCleanups(operand);
+ return ActOnFinishFullExpr(operand);
}
StmtResult
@@ -2756,7 +2811,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
// and warns.
return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
- Handlers, NumHandlers));
+ llvm::makeArrayRef(Handlers, NumHandlers)));
}
StmtResult
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 7c2c766e4615..da33bdf717e6 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -12,25 +12,25 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.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/ADT/SmallString.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/MC/MCParser/MCAsmParser.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
@@ -124,11 +124,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Check that the output exprs are valid lvalues.
Expr *OutputExpr = Exprs[i];
- if (CheckAsmLValue(OutputExpr, *this)) {
+ if (CheckAsmLValue(OutputExpr, *this))
return StmtError(Diag(OutputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_output)
- << OutputExpr->getSourceRange());
- }
+ diag::err_asm_invalid_lvalue_in_output)
+ << OutputExpr->getSourceRange());
+
+ if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
+ diag::err_dereference_incomplete_type))
+ return StmtError();
OutputConstraintInfos.push_back(Info);
}
@@ -179,6 +182,22 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
Exprs[i] = Result.take();
InputConstraintInfos.push_back(Info);
+
+ const Type *Ty = Exprs[i]->getType().getTypePtr();
+ if (Ty->isDependentType())
+ continue;
+
+ if (!Ty->isVoidType() || !Info.allowsMemory())
+ if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(),
+ diag::err_dereference_incomplete_type))
+ return StmtError();
+
+ unsigned Size = Context.getTypeSize(Ty);
+ if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
+ Size))
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_input_size)
+ << Info.getConstraintStr());
}
// Check that the clobbers are valid.
@@ -377,7 +396,7 @@ static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
static bool buildMSAsmString(Sema &SemaRef,
SourceLocation AsmLoc,
ArrayRef<Token> AsmToks,
- llvm::SmallVectorImpl<unsigned> &TokOffsets,
+ SmallVectorImpl<unsigned> &TokOffsets,
std::string &AsmString) {
assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
@@ -426,9 +445,14 @@ public:
: SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { }
~MCAsmParserSemaCallbackImpl() {}
- void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, unsigned &Size){
+ void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc,
+ unsigned &Length, unsigned &Size,
+ unsigned &Type, bool &IsVarDecl){
SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc);
- NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Size);
+
+ NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Length,
+ Size, Type,
+ IsVarDecl);
return static_cast<void *>(OpDecl);
}
@@ -471,8 +495,12 @@ public:
}
NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
- unsigned &Size) {
+ unsigned &Length, unsigned &Size,
+ unsigned &Type, bool &IsVarDecl) {
+ Length = 1;
Size = 0;
+ Type = 0;
+ IsVarDecl = false;
LookupResult Result(*this, &Context.Idents.get(Name), Loc,
Sema::LookupOrdinaryName);
@@ -487,12 +515,19 @@ NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
return 0;
}
- NamedDecl *ND = Result.getFoundDecl();
- if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
- if (VarDecl *Var = dyn_cast<VarDecl>(ND))
- Size = Context.getTypeInfo(Var->getType()).first;
-
- return ND;
+ NamedDecl *FoundDecl = Result.getFoundDecl();
+ if (isa<FunctionDecl>(FoundDecl))
+ return FoundDecl;
+ if (VarDecl *Var = dyn_cast<VarDecl>(FoundDecl)) {
+ QualType Ty = Var->getType();
+ Type = Size = Context.getTypeSizeInChars(Ty).getQuantity();
+ if (Ty->isArrayType()) {
+ const ArrayType *ATy = Context.getAsArrayType(Ty);
+ Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
+ Length = Size / Type;
+ }
+ IsVarDecl = true;
+ return FoundDecl;
}
// FIXME: Handle other kinds of results? (FieldDecl, etc.)
@@ -512,13 +547,12 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
if (!BaseResult.isSingleResult())
return true;
- NamedDecl *FoundDecl = BaseResult.getFoundDecl();
const RecordType *RT = 0;
- if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) {
+ 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 (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl))
RT = TD->getUnderlyingType()->getAs<RecordType>();
- }
if (!RT)
return true;
@@ -551,8 +585,15 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
SmallVector<Expr*, 4> Exprs;
SmallVector<StringRef, 4> ClobberRefs;
+ llvm::Triple TheTriple = Context.getTargetInfo().getTriple();
+ llvm::Triple::ArchType ArchTy = TheTriple.getArch();
+ bool UnsupportedArch = ArchTy != llvm::Triple::x86 &&
+ ArchTy != llvm::Triple::x86_64;
+ if (UnsupportedArch)
+ Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
+
// Empty asm statements don't need to instantiate the AsmParser, etc.
- if (AsmToks.empty()) {
+ if (UnsupportedArch || AsmToks.empty()) {
StringRef EmptyAsmStr;
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
@@ -563,13 +604,13 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
}
std::string AsmString;
- llvm::SmallVector<unsigned, 8> TokOffsets;
+ SmallVector<unsigned, 8> TokOffsets;
if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString))
return StmtError();
// Get the target specific parser.
std::string Error;
- const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
+ const std::string &TT = TheTriple.getTriple();
const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
@@ -614,7 +655,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
SmallVector<std::pair<void *, bool>, 4> OpDecls;
SmallVector<std::string, 4> Constraints;
SmallVector<std::string, 4> Clobbers;
- if (Parser->ParseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
+ if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
NumOutputs, NumInputs, OpDecls, Constraints,
Clobbers, MII, IP, MCAPSI))
return StmtError();
@@ -641,7 +682,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
if (OpExpr.isInvalid())
return StmtError();
- // Need offset of variable.
+ // Need address of variable.
if (OpDecls[i].second)
OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf,
OpExpr.take());
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index b268b4502c4f..eb0188a0db3d 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -58,8 +58,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
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::warn_attribute_invalid_on_stmt)
- << A.getName()->getName() << St->getLocStart();
+ S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
+ << A.getName() << St->getLocStart();
return 0;
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f56b05406d07..990626189e18 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -9,23 +9,23 @@
// This file implements semantic analysis for C++ templates.
//===----------------------------------------------------------------------===/
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Template.h"
-#include "clang/Sema/TemplateDeduction.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeVisitor.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ParsedTemplate.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@@ -356,7 +356,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope &&
- !(getLangOpts().CPlusPlus0x && !Found.empty())) {
+ !(getLangOpts().CPlusPlus11 && !Found.empty())) {
// C++03 [basic.lookup.classref]p1:
// [...] If the lookup in the class of the object expression finds a
// template, the name is also looked up in the context of the entire
@@ -510,7 +510,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
TemplateName Template = Arg.getAsTemplate().get();
TemplateArgument TArg;
if (Arg.getEllipsisLoc().isValid())
- TArg = TemplateArgument(Template, llvm::Optional<unsigned int>());
+ TArg = TemplateArgument(Template, Optional<unsigned int>());
else
TArg = Template;
return TemplateArgumentLoc(TArg,
@@ -1171,7 +1171,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
// template-argument, that declaration shall be a definition and shall be
// the only declaration of the function template in the translation unit.
// (C++98/03 doesn't have this wording; see DR226).
- S.Diag(ParamLoc, S.getLangOpts().CPlusPlus0x ?
+ S.Diag(ParamLoc, S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_parameter_default_in_function_template
: diag::ext_template_parameter_default_in_function_template)
<< DefArgRange;
@@ -2359,7 +2359,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
TemplateTy &Result) {
if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TemplateKWLoc,
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_outside_of_template :
diag::ext_template_outside_of_template)
<< FixItHint::CreateRemoval(TemplateKWLoc);
@@ -2387,7 +2387,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode with a warning, retroactively applying the DR.
bool MemberOfUnknownSpecialization;
- TemplateNameKind TNK = isTemplateName(0, SS, TemplateKWLoc.isValid(), Name,
+ TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
ObjectType, EnteringContext, Result,
MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
@@ -2972,7 +2972,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// We have a template template parameter but the template
// argument does not refer to a template.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
- << getLangOpts().CPlusPlus0x;
+ << getLangOpts().CPlusPlus11;
return true;
case TemplateArgument::Declaration:
@@ -3023,7 +3023,7 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
///
/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
/// is not a pack expansion, so returns an empty Optional.
-static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (NTTP->isExpandedParameterPack())
@@ -3036,7 +3036,7 @@ static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
return TTP->getNumExpansionTemplateParameters();
}
- return llvm::Optional<unsigned>();
+ return None;
}
/// \brief Check that the given template argument list is well-formed
@@ -3068,7 +3068,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Param != ParamEnd; /* increment in loop */) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
- if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+ if (Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
if (*Expansions == ArgumentPack.size()) {
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
@@ -3486,16 +3486,16 @@ bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) {
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_local_type :
diag::ext_template_arg_local_type)
<< S.Context.getTypeDeclType(Tag) << SR;
return true;
}
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) {
+ if (!Tag->hasNameForLinkage()) {
S.Diag(SR.getBegin(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_unnamed_type :
diag::ext_template_arg_unnamed_type) << SR;
S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here);
@@ -3549,7 +3549,7 @@ 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.CPlusPlus0x ?
+ 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,
@@ -3576,7 +3576,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
if (Arg->isValueDependent() || Arg->isTypeDependent())
return NPV_NotNullPointer;
- if (!S.getLangOpts().CPlusPlus0x)
+ if (!S.getLangOpts().CPlusPlus11)
return NPV_NotNullPointer;
// Determine whether we have a constant expression.
@@ -3586,7 +3586,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
Arg = ArgRV.take();
Expr::EvalResult EvalResult;
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
EvalResult.Diag = &Notes;
if (!Arg->EvaluateAsRValue(EvalResult, S.Context) ||
EvalResult.HasSideEffects) {
@@ -3704,7 +3704,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid && !ExtraParens) {
S.Diag(Arg->getLocStart(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_extra_parens :
diag::ext_template_arg_extra_parens)
<< Arg->getSourceRange();
@@ -3794,7 +3794,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Address / reference template args must have external linkage in C++98.
if (Entity->getLinkage() == InternalLinkage) {
- S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus0x ?
+ S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_object_internal :
diag::ext_template_arg_object_internal)
<< !Func << Entity << Arg->getSourceRange();
@@ -3950,7 +3950,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Create the template argument.
Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
ParamType->isReferenceType());
- S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
+ S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity, false);
return false;
}
@@ -4010,7 +4010,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid && !ExtraParens) {
S.Diag(Arg->getLocStart(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_extra_parens :
diag::ext_template_arg_extra_parens)
<< Arg->getSourceRange();
@@ -4139,7 +4139,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// We can't check arbitrary value-dependent arguments.
// FIXME: If there's no viable conversion to the template parameter type,
// we should be able to diagnose that prior to instantiation.
@@ -4495,6 +4495,16 @@ ExprResult
Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ParamType,
SourceLocation Loc) {
+ // C++ [temp.param]p8:
+ //
+ // A non-type template-parameter of type "array of T" or
+ // "function returning T" is adjusted to be of type "pointer to
+ // T" or "pointer to function returning T", respectively.
+ if (ParamType->isArrayType())
+ ParamType = Context.getArrayDecayedType(ParamType);
+ else if (ParamType->isFunctionType())
+ ParamType = Context.getPointerType(ParamType);
+
// For a NULL non-type template argument, return nullptr casted to the
// parameter's type.
if (Arg.getKind() == TemplateArgument::NullPtr) {
@@ -4560,6 +4570,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
}
QualType T = VD->getType().getNonReferenceType();
+
if (ParamType->isPointerType()) {
// When the non-type template parameter is a pointer, take the
// address of the declaration.
@@ -4589,6 +4600,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
VK = VK_LValue;
T = Context.getQualifiedType(T,
TargetRef->getPointeeType().getQualifiers());
+ } else if (isa<FunctionDecl>(VD)) {
+ // References to functions are always lvalues.
+ VK = VK_LValue;
}
return BuildDeclRefExpr(VD, T, VK, Loc);
@@ -4606,7 +4620,18 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc) {
assert(Arg.getKind() == TemplateArgument::Integral &&
"Operation is only valid for integral template arguments");
- QualType T = Arg.getIntegralType();
+ QualType OrigT = Arg.getIntegralType();
+
+ // If this is an enum type that we're instantiating, we need to use an integer
+ // type the same size as the enumerator. We don't want to build an
+ // IntegerLiteral with enum type. The integer type of an enum type can be of
+ // any integral type with C++11 enum classes, make sure we create the right
+ // type of literal for it.
+ QualType T = OrigT;
+ if (const EnumType *ET = OrigT->getAs<EnumType>())
+ T = ET->getDecl()->getIntegerType();
+
+ Expr *E;
if (T->isAnyCharacterType()) {
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
@@ -4618,34 +4643,22 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
else
Kind = CharacterLiteral::Ascii;
- return Owned(new (Context) CharacterLiteral(
- Arg.getAsIntegral().getZExtValue(),
- Kind, T, Loc));
+ E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
+ Kind, T, Loc);
+ } else if (T->isBooleanType()) {
+ E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
+ T, Loc);
+ } else if (T->isNullPtrType()) {
+ E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
+ } else {
+ E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), T, Loc);
}
- if (T->isBooleanType())
- return Owned(new (Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral().getBoolValue(),
- T, Loc));
-
- if (T->isNullPtrType())
- return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
-
- // If this is an enum type that we're instantiating, we need to use an integer
- // type the same size as the enumerator. We don't want to build an
- // IntegerLiteral with enum type.
- QualType BT;
- if (const EnumType *ET = T->getAs<EnumType>())
- BT = ET->getDecl()->getIntegerType();
- else
- BT = T;
-
- Expr *E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), BT, Loc);
- if (T->isEnumeralType()) {
+ if (OrigT->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
- E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, E, 0,
- Context.getTrivialTypeSourceInfo(T, Loc),
+ E = CStyleCastExpr::Create(Context, OrigT, VK_RValue, CK_IntegralCast, E, 0,
+ Context.getTrivialTypeSourceInfo(OrigT, Loc),
Loc, Loc);
}
@@ -4961,11 +4974,11 @@ static bool CheckTemplateSpecializationScope(Sema &S,
EntityKind = 4;
else if (isa<RecordDecl>(Specialized))
EntityKind = 5;
- else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus0x)
+ else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus11)
EntityKind = 6;
else {
S.Diag(Loc, diag::err_template_spec_unknown_kind)
- << S.getLangOpts().CPlusPlus0x;
+ << S.getLangOpts().CPlusPlus11;
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
return true;
}
@@ -5036,17 +5049,17 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// An explicit specialization shall be declared in a namespace enclosing
// the specialized template.
if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) {
- bool IsCPlusPlus0xExtension = DC->Encloses(SpecializedContext);
+ bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext);
if (isa<TranslationUnitDecl>(SpecializedContext)) {
- assert(!IsCPlusPlus0xExtension &&
+ assert(!IsCPlusPlus11Extension &&
"DC encloses TU but isn't in enclosing namespace set");
S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
<< EntityKind << Specialized;
} else if (isa<NamespaceDecl>(SpecializedContext)) {
int Diag;
- if (!IsCPlusPlus0xExtension)
+ if (!IsCPlusPlus11Extension)
Diag = diag::err_template_spec_decl_out_of_scope;
- else if (!S.getLangOpts().CPlusPlus0x)
+ else if (!S.getLangOpts().CPlusPlus11)
Diag = diag::ext_template_spec_decl_out_of_scope;
else
Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope;
@@ -5056,7 +5069,7 @@ static bool CheckTemplateSpecializationScope(Sema &S,
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
ComplainedAboutScope =
- !(IsCPlusPlus0xExtension && S.getLangOpts().CPlusPlus0x);
+ !(IsCPlusPlus11Extension && S.getLangOpts().CPlusPlus11);
}
}
@@ -5629,23 +5642,21 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
TemplateParameterLists);
- if (FunctionTemplateDecl *FunctionTemplate
- = dyn_cast_or_null<FunctionTemplateDecl>(DP))
- return ActOnStartOfFunctionDef(FnBodyScope,
- FunctionTemplate->getTemplatedDecl());
- if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(DP))
- return ActOnStartOfFunctionDef(FnBodyScope, Function);
- return 0;
+ return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
- // FIXME: "make check" is clean if the call to dropAttrs() is commented out.
D->dropAttrs();
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();
}
}
@@ -5803,7 +5814,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// In C++98/03 mode, we only give an extension warning here, because it
// is not harmful to try to explicitly instantiate something that
// has been explicitly specialized.
- Diag(NewLoc, getLangOpts().CPlusPlus0x ?
+ Diag(NewLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_explicit_instantiation_after_specialization :
diag::ext_explicit_instantiation_after_specialization)
<< PrevDecl;
@@ -5925,6 +5936,26 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
Ovl->getDeclContext()->getRedeclContext()))
continue;
+ // When matching a constexpr member function template specialization
+ // against the primary template, we don't yet know whether the
+ // specialization has an implicit 'const' (because we don't know whether
+ // it will be a static member function until we know which template it
+ // specializes), so adjust it now assuming it specializes this template.
+ QualType FT = FD->getType();
+ if (FD->isConstexpr()) {
+ CXXMethodDecl *OldMD =
+ dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ if (OldMD && OldMD->isConst()) {
+ const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.TypeQuals |= Qualifiers::Const;
+ FT = Context.getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
+ }
+ }
+
// C++ [temp.expl.spec]p11:
// A trailing template-argument can be left unspecified in the
// template-id naming an explicit function template specialization
@@ -5935,10 +5966,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplateDeductionInfo Info(FD->getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
- FD->getType(),
- Specialization,
- Info)) {
+ = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FT,
+ Specialization, Info)) {
// FIXME: Template argument deduction failed; record why it failed, so
// that we can provide nifty diagnostics.
(void)TDK;
@@ -6028,8 +6057,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplArgs, /*InsertPos=*/0,
SpecInfo->getTemplateSpecializationKind(),
ExplicitTemplateArgs);
- FD->setStorageClass(Specialization->getStorageClass());
-
+
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Previous.clear();
@@ -6257,19 +6285,19 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(OrigContext)) {
if (WasQualifiedName)
S.Diag(InstLoc,
- S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().CPlusPlus11?
diag::err_explicit_instantiation_out_of_scope :
diag::warn_explicit_instantiation_out_of_scope_0x)
<< D << NS;
else
S.Diag(InstLoc,
- S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().CPlusPlus11?
diag::err_explicit_instantiation_unqualified_wrong_namespace :
diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x)
<< D << NS;
} else
S.Diag(InstLoc,
- S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().CPlusPlus11?
diag::err_explicit_instantiation_must_be_global :
diag::warn_explicit_instantiation_must_be_global_0x)
<< D;
@@ -6663,7 +6691,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// well.
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::err_explicit_instantiation_inline :
diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
@@ -6920,7 +6948,7 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TypenameLoc,
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_typename_outside_of_template :
diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
@@ -6933,15 +6961,15 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
- DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(IdLoc);
} else {
- ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>();
TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(QualifierLoc);
- cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(IdLoc);
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
}
return CreateParsedType(T, TSI);
@@ -6959,7 +6987,7 @@ Sema::ActOnTypenameType(Scope *S,
SourceLocation RAngleLoc) {
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TypenameLoc,
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_typename_outside_of_template :
diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
@@ -7031,12 +7059,12 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
if (!NNS || !NNS.getNestedNameSpecifier()->getAsType())
return false;
TypeLoc EnableIfTy = NNS.getTypeLoc();
- TemplateSpecializationTypeLoc *EnableIfTSTLoc =
- dyn_cast<TemplateSpecializationTypeLoc>(&EnableIfTy);
- if (!EnableIfTSTLoc || EnableIfTSTLoc->getNumArgs() == 0)
+ TemplateSpecializationTypeLoc EnableIfTSTLoc =
+ EnableIfTy.getAs<TemplateSpecializationTypeLoc>();
+ if (!EnableIfTSTLoc || EnableIfTSTLoc.getNumArgs() == 0)
return false;
const TemplateSpecializationType *EnableIfTST =
- cast<TemplateSpecializationType>(EnableIfTSTLoc->getTypePtr());
+ cast<TemplateSpecializationType>(EnableIfTSTLoc.getTypePtr());
// ... which names a complete class template declaration...
const TemplateDecl *EnableIfDecl =
@@ -7051,7 +7079,7 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
return false;
// Assume the first template argument is the condition.
- CondRange = EnableIfTSTLoc->getArgLoc(0).getSourceRange();
+ CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange();
return true;
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index bf4533d6998c..f3bbe8a0f10c 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -10,18 +10,18 @@
//
//===----------------------------------------------------------------------===/
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallBitVector.h"
-#include "TreeTransform.h"
#include <algorithm>
namespace clang {
@@ -130,8 +130,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- bool NumberOfArgumentsMustMatch = true);
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
@@ -482,21 +481,26 @@ DeduceTemplateArguments(Sema &S,
return DeduceTemplateArguments(S, TemplateParams,
Param->getArgs(), Param->getNumArgs(),
SpecArg->getArgs(), SpecArg->getNumArgs(),
- Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/false);
+ Info, Deduced);
}
// If the argument type is a class template specialization, we
// perform template argument deduction using its template
// arguments.
const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
- if (!RecordArg)
+ if (!RecordArg) {
+ Info.FirstArg = TemplateArgument(QualType(Param, 0));
+ Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_NonDeducedMismatch;
+ }
ClassTemplateSpecializationDecl *SpecArg
= dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
- if (!SpecArg)
+ if (!SpecArg) {
+ Info.FirstArg = TemplateArgument(QualType(Param, 0));
+ Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_NonDeducedMismatch;
+ }
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
@@ -710,7 +714,7 @@ DeduceTemplateArguments(Sema &S,
if (NumParams != NumArgs &&
!(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
!(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1])))
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
// C++0x [temp.deduct.type]p10:
// Similarly, if P has a form that contains (T), then each parameter type
@@ -727,14 +731,14 @@ DeduceTemplateArguments(Sema &S,
// Make sure we have an argument.
if (ArgIdx >= NumArgs)
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
if (isa<PackExpansionType>(Args[ArgIdx])) {
// C++0x [temp.deduct.type]p22:
// If the original function parameter associated with A is a function
// parameter pack and the function parameter associated with P is not
// a function parameter pack, then template argument deduction fails.
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
}
if (Sema::TemplateDeductionResult Result
@@ -827,7 +831,7 @@ DeduceTemplateArguments(Sema &S,
// Make sure we don't have any extra arguments.
if (ArgIdx < NumArgs)
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
return Sema::TDK_Success;
}
@@ -1749,8 +1753,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- bool NumberOfArgumentsMustMatch) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
// C++0x [temp.deduct.type]p9:
// If the template argument list of P contains a pack expansion that is not
// the last template argument, the entire template argument list is a
@@ -1770,13 +1773,12 @@ DeduceTemplateArguments(Sema &S,
// Check whether we have enough arguments.
if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
- return NumberOfArgumentsMustMatch? Sema::TDK_NonDeducedMismatch
- : Sema::TDK_Success;
+ return Sema::TDK_Success;
if (Args[ArgIdx].isPackExpansion()) {
// FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here,
// but applied to pack expansions that are template arguments.
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
}
// Perform deduction for this Pi/Ai pair.
@@ -1867,11 +1869,6 @@ DeduceTemplateArguments(Sema &S,
return Result;
}
- // If there is an argument remaining, then we had too many arguments.
- if (NumberOfArgumentsMustMatch &&
- hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
- return Sema::TDK_NonDeducedMismatch;
-
return Sema::TDK_Success;
}
@@ -2400,7 +2397,7 @@ Sema::SubstituteExplicitTemplateArguments(
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
ResultType = SubstType(Proto->getResultType(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
@@ -2420,15 +2417,10 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_SubstitutionFailure;
if (FunctionType) {
- *FunctionType = BuildFunctionType(ResultType,
- ParamTypes.data(), ParamTypes.size(),
- Proto->isVariadic(),
- Proto->hasTrailingReturn(),
- Proto->getTypeQuals(),
- Proto->getRefQualifier(),
+ *FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
- Proto->getExtInfo());
+ Proto->getExtProtoInfo());
if (FunctionType->isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
@@ -2656,11 +2648,15 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
if (CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
&NumExplicitArgs)
- == Param)
+ == Param) {
Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));
- else
- Builder.push_back(TemplateArgument::getEmptyPack());
+ // Forget the partially-substituted pack; it's substitution is now
+ // complete.
+ CurrentInstantiationScope->ResetPartiallySubstitutedPack();
+ } else {
+ Builder.push_back(TemplateArgument::getEmptyPack());
+ }
continue;
}
@@ -2884,7 +2880,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
/// described in C++ [temp.deduct.call].
///
/// \returns true if the caller should not attempt to perform any template
-/// argument deduction based on this P/A pair.
+/// argument deduction based on this P/A pair because the argument is an
+/// overloaded function set that could not be resolved.
static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
TemplateParameterList *TemplateParams,
QualType &ParamType,
@@ -2900,7 +2897,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (ParamRefType) {
QualType PointeeType = ParamRefType->getPointeeType();
- // If the argument has incomplete array type, try to complete it's type.
+ // If the argument has incomplete array type, try to complete its type.
if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
ArgType = Arg->getType();
@@ -2998,8 +2995,8 @@ static bool hasDeducibleTemplateParameters(Sema &S,
/// \brief Perform template argument deduction by matching a parameter type
/// against a single expression, where the expression is an element of
-/// an initializer list that was originally matched against the argument
-/// type.
+/// an initializer list that was originally matched against a parameter
+/// of type \c initializer_list\<ParamType\>.
static Sema::TemplateDeductionResult
DeduceTemplateArgumentByListElement(Sema &S,
TemplateParameterList *TemplateParams,
@@ -3028,8 +3025,10 @@ DeduceTemplateArgumentByListElement(Sema &S,
// For all other cases, just match by type.
QualType ArgType = Arg->getType();
if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType,
- ArgType, Arg, TDF))
+ ArgType, Arg, TDF)) {
+ Info.Expression = Arg;
return Sema::TDK_FailedOverloadResolution;
+ }
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
}
@@ -3045,11 +3044,6 @@ DeduceTemplateArgumentByListElement(Sema &S,
///
/// \param Args the function call arguments
///
-/// \param Name the name of the function being called. This is only significant
-/// when the function template is a conversion function template, in which
-/// case this routine will also perform template argument deduction based on
-/// the function to which
-///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
/// template argument deduction.
@@ -3372,7 +3366,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// specialization, template argument deduction fails.
if (!ArgFunctionType.isNull() &&
!Context.hasSameType(ArgFunctionType, Specialization->getType()))
- return TDK_NonDeducedMismatch;
+ return TDK_MiscellaneousDeductionFailure;
return TDK_Success;
}
@@ -3772,15 +3766,15 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// first argument of the free function, which seems to match
// existing practice.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = !S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2)
+ unsigned Skip1 = !S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1;
+ if (S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2)
AddImplicitObjectParameterType(S.Context, Method1, Args1);
Args1.insert(Args1.end(),
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
SmallVector<QualType, 4> Args2;
- Skip2 = !S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1)
+ Skip2 = !S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2;
+ if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1)
AddImplicitObjectParameterType(S.Context, Method2, Args2);
Args2.insert(Args2.end(),
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
@@ -3849,7 +3843,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
unsigned NumParams = std::min(NumCallArguments,
std::min(Proto1->getNumArgs(),
Proto2->getNumArgs()));
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
+ if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !IsNonStatic1)
::MarkUsedTemplateParameters(S.Context, Method2->getThisType(S.Context),
false,
TemplateParams->getDepth(), UsedParameters);
@@ -4052,10 +4046,6 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// in this diagnostic should be unbound, which will correspond to the string
/// describing the template arguments for the function template specialization.
///
-/// \param Index if non-NULL and the result of this function is non-nULL,
-/// receives the index corresponding to the resulting function template
-/// specialization.
-///
/// \returns the most specialized function template specialization, if
/// found. Otherwise, returns SpecEnd.
///
@@ -4618,7 +4608,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
/// call to the given function template.
void
Sema::MarkDeducedTemplateParameters(ASTContext &Ctx,
- FunctionTemplateDecl *FunctionTemplate,
+ const FunctionTemplateDecl *FunctionTemplate,
llvm::SmallBitVector &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 665dd07b8f85..f755b8ca452d 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -12,16 +12,16 @@
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/Basic/LangOptions.h"
using namespace clang;
using namespace sema;
@@ -182,7 +182,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
+ Inst.Entity = Entity;
Inst.TemplateArgs = 0;
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
@@ -205,7 +205,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
+ Inst.Entity = Entity;
Inst.TemplateArgs = 0;
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
@@ -230,7 +230,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind
= ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Template);
+ Inst.Entity = Template;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -255,7 +255,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = Kind;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate);
+ Inst.Entity = FunctionTemplate;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = &DeductionInfo;
@@ -283,7 +283,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+ Inst.Entity = PartialSpec;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = &DeductionInfo;
@@ -308,7 +308,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind
= ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -332,7 +332,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -356,7 +356,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -380,7 +380,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -454,7 +454,7 @@ void Sema::PrintInstantiationStack() {
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
- Decl *D = reinterpret_cast<Decl *>(Active->Entity);
+ Decl *D = Active->Entity;
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
unsigned DiagID = diag::note_template_member_class_here;
if (isa<ClassTemplateSpecializationDecl>(Record))
@@ -491,22 +491,23 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: {
- TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity);
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateDecl *Template = cast<TemplateDecl>(Active->Entity);
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ Template->printName(OS);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
Active->TemplateArgs,
Active->NumTemplateArgs,
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_arg_instantiation_here)
- << (Template->getNameAsString() + TemplateArgsStr)
+ << OS.str()
<< Active->InstantiationRange;
break;
}
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: {
- FunctionTemplateDecl *FnTmpl
- = cast<FunctionTemplateDecl>((Decl *)Active->Entity);
+ FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>(Active->Entity);
Diags.Report(Active->PointOfInstantiation,
diag::note_explicit_template_arg_substitution_here)
<< FnTmpl
@@ -518,9 +519,8 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
- if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(
- (Decl *)Active->Entity)) {
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(Active->Entity)) {
Diags.Report(Active->PointOfInstantiation,
diag::note_partial_spec_deduct_instantiation_here)
<< Context.getTypeDeclType(PartialSpec)
@@ -531,7 +531,7 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
} else {
FunctionTemplateDecl *FnTmpl
- = cast<FunctionTemplateDecl>((Decl *)Active->Entity);
+ = cast<FunctionTemplateDecl>(Active->Entity);
Diags.Report(Active->PointOfInstantiation,
diag::note_function_template_deduction_instantiation_here)
<< FnTmpl
@@ -543,23 +543,25 @@ void Sema::PrintInstantiationStack() {
break;
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: {
- ParmVarDecl *Param = cast<ParmVarDecl>((Decl *)Active->Entity);
+ ParmVarDecl *Param = cast<ParmVarDecl>(Active->Entity);
FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ FD->printName(OS);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
Active->TemplateArgs,
Active->NumTemplateArgs,
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_function_arg_instantiation_here)
- << (FD->getNameAsString() + TemplateArgsStr)
+ << OS.str()
<< Active->InstantiationRange;
break;
}
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: {
- NamedDecl *Parm = cast<NamedDecl>((Decl *)Active->Entity);
+ NamedDecl *Parm = cast<NamedDecl>(Active->Entity);
std::string Name;
if (!Parm->getName().empty())
Name = std::string(" '") + Parm->getName().str() + "'";
@@ -603,16 +605,16 @@ void Sema::PrintInstantiationStack() {
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
Diags.Report(Active->PointOfInstantiation,
diag::note_template_exception_spec_instantiation_here)
- << cast<FunctionDecl>((Decl *)Active->Entity)
+ << cast<FunctionDecl>(Active->Entity)
<< Active->InstantiationRange;
break;
}
}
}
-llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
+Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
- return llvm::Optional<TemplateDeductionInfo *>(0);
+ return Optional<TemplateDeductionInfo *>(0);
for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
@@ -624,13 +626,13 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case ActiveTemplateInstantiation::TemplateInstantiation:
// An instantiation of an alias template may or may not be a SFINAE
// context, depending on what else is on the stack.
- if (isa<TypeAliasTemplateDecl>(reinterpret_cast<Decl *>(Active->Entity)))
+ if (isa<TypeAliasTemplateDecl>(Active->Entity))
break;
// Fall through.
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
// This is a template instantiation, so there is no SFINAE.
- return llvm::Optional<TemplateDeductionInfo *>();
+ return None;
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
@@ -649,7 +651,7 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
}
}
- return llvm::Optional<TemplateDeductionInfo *>();
+ return None;
}
/// \brief Retrieve the depth and index of a parameter pack.
@@ -709,7 +711,7 @@ namespace {
llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand,
bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions) {
+ Optional<unsigned> &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
TemplateArgs,
@@ -829,7 +831,7 @@ namespace {
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
/// \brief Transforms a template type parameter type by performing
@@ -1267,7 +1269,7 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
// Transform each of the parameter expansions into the corresponding
// parameters in the instantiation of the function decl.
- llvm::SmallVector<Decl*, 8> Parms;
+ SmallVector<Decl *, 8> Parms;
Parms.reserve(E->getNumExpansions());
for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
I != End; ++I) {
@@ -1365,7 +1367,7 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
NumExpansions, ExpectParameterPack);
@@ -1568,10 +1570,10 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
return true;
TypeLoc TL = T->getTypeLoc().IgnoreParens();
- if (!isa<FunctionProtoTypeLoc>(TL))
+ if (!TL.getAs<FunctionProtoTypeLoc>())
return false;
- FunctionProtoTypeLoc FP = cast<FunctionProtoTypeLoc>(TL);
+ FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>();
for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
ParmVarDecl *P = FP.getArg(I);
@@ -1615,9 +1617,9 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
TLB.reserve(TL.getFullDataSize());
QualType Result;
-
- if (FunctionProtoTypeLoc *Proto = dyn_cast<FunctionProtoTypeLoc>(&TL)) {
- Result = Instantiator.TransformFunctionProtoType(TLB, *Proto, ThisContext,
+
+ if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
+ Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext,
ThisTypeQuals);
} else {
Result = Instantiator.TransformType(TLB, TL);
@@ -1631,15 +1633,14 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
TypeLoc OldTL = OldDI->getTypeLoc();
- if (isa<PackExpansionTypeLoc>(OldTL)) {
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
-
+ if (PackExpansionTypeLoc ExpansionTL = OldTL.getAs<PackExpansionTypeLoc>()) {
+
// We have a function parameter pack. Substitute into the pattern of the
// expansion.
NewDI = SubstType(ExpansionTL.getPatternLoc(), TemplateArgs,
@@ -1681,8 +1682,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
OldParm->getLocation(),
OldParm->getIdentifier(),
NewDI->getType(), NewDI,
- OldParm->getStorageClass(),
- OldParm->getStorageClassAsWritten());
+ OldParm->getStorageClass());
if (!NewParm)
return 0;
@@ -1715,7 +1715,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
-
+
+ InstantiateAttrs(TemplateArgs, OldParm, NewParm);
+
return NewParm;
}
@@ -1767,7 +1769,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(),
Base->getSourceRange(),
Unexpanded,
@@ -2047,6 +2049,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CheckCompletedCXXClass(Instantiation);
// Attach any in-class member initializers now the class is complete.
+ // FIXME: We are supposed to defer instantiating these until they are needed.
if (!FieldsWithMemberInitializers.empty()) {
// C++11 [expr.prim.general]p4:
// Otherwise, if a member-declarator declares a non-static data member
@@ -2583,12 +2586,21 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformExpr(E);
}
+ExprResult Sema::SubstInitializer(Expr *Init,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool CXXDirectInit) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformInitializer(Init, CXXDirectInit);
+}
+
bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
SmallVectorImpl<Expr *> &Outputs) {
if (NumExprs == 0)
return false;
-
+
TemplateInstantiator Instantiator(*this, TemplateArgs,
SourceLocation(),
DeclarationName());
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 19c46ab9c97f..33e83d07d634 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -10,9 +10,6 @@
//
//===----------------------------------------------------------------------===/
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/PrettyDeclStackTrace.h"
-#include "clang/Sema/Template.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
@@ -22,6 +19,9 @@
#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"
using namespace clang;
@@ -60,6 +60,64 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
// Include attribute instantiation code.
#include "clang/Sema/AttrTemplateInstantiate.inc"
+static void instantiateDependentAlignedAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AlignedAttr *Aligned, Decl *New, bool IsPackExpansion) {
+ if (Aligned->isAlignmentExpr()) {
+ // The alignment expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
+ if (!Result.isInvalid())
+ S.AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
+ Aligned->getSpellingListIndex(), IsPackExpansion);
+ } else {
+ TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
+ TemplateArgs, Aligned->getLocation(),
+ DeclarationName());
+ if (Result)
+ S.AddAlignedAttr(Aligned->getLocation(), New, Result,
+ Aligned->getSpellingListIndex(), IsPackExpansion);
+ }
+}
+
+static void instantiateDependentAlignedAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AlignedAttr *Aligned, Decl *New) {
+ if (!Aligned->isPackExpansion()) {
+ instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
+ return;
+ }
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ if (Aligned->isAlignmentExpr())
+ S.collectUnexpandedParameterPacks(Aligned->getAlignmentExpr(),
+ Unexpanded);
+ else
+ S.collectUnexpandedParameterPacks(Aligned->getAlignmentType()->getTypeLoc(),
+ Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether we can expand this attribute pack yet.
+ bool Expand = true, RetainExpansion = false;
+ Optional<unsigned> NumExpansions;
+ // FIXME: Use the actual location of the ellipsis.
+ SourceLocation EllipsisLoc = Aligned->getLocation();
+ if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
+ Unexpanded, TemplateArgs, Expand,
+ RetainExpansion, NumExpansions))
+ return;
+
+ if (!Expand) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, -1);
+ instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, true);
+ } else {
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, I);
+ instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
+ }
+ }
+}
+
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
@@ -69,31 +127,13 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *TmplAttr = *i;
// FIXME: This should be generalized to more than just the AlignedAttr.
- if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) {
- if (Aligned->isAlignmentDependent()) {
- if (Aligned->isAlignmentExpr()) {
- // The alignment expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(*this,
- Sema::ConstantEvaluated);
-
- ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
- TemplateArgs);
- if (!Result.isInvalid())
- AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
- Aligned->getIsMSDeclSpec());
- } else {
- TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
- TemplateArgs,
- Aligned->getLocation(),
- DeclarationName());
- if (Result)
- AddAlignedAttr(Aligned->getLocation(), New, Result,
- Aligned->getIsMSDeclSpec());
- }
- continue;
- }
+ const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
+ if (Aligned && Aligned->isAlignmentDependent()) {
+ instantiateDependentAlignedAttr(*this, TemplateArgs, Aligned, 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.
@@ -189,9 +229,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
// tag decl, re-establish that relationship for the new typedef.
if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) {
TagDecl *oldTag = oldTagType->getDecl();
- if (oldTag->getTypedefNameForAnonDecl() == D) {
+ if (oldTag->getTypedefNameForAnonDecl() == D && !Invalid) {
TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl();
- assert(!newTag->getIdentifier() && !newTag->getTypedefNameForAnonDecl());
+ assert(!newTag->hasNameForLinkage());
newTag->setTypedefNameForAnonDecl(Typedef);
}
}
@@ -245,8 +285,8 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TypeAliasTemplateDecl *PrevAliasTemplate = 0;
if (Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
- if (Found.first != Found.second) {
- PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
+ if (!Found.empty()) {
+ PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Found.front());
}
}
@@ -298,8 +338,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
D->getInnerLocStart(),
D->getLocation(), D->getIdentifier(),
DI->getType(), DI,
- D->getStorageClass(),
- D->getStorageClassAsWritten());
+ D->getStorageClass());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setInitStyle(D->getInitStyle());
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
@@ -322,6 +361,11 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setReferenced(D->isReferenced());
}
+ SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
+
+ if (Var->hasAttrs())
+ SemaRef.CheckAlignasUnderalignment(Var);
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
// FIXME: having to fake up a LookupResult is dumb.
@@ -345,7 +389,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
if (Owner->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
}
- SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
// Link instantiations of static data members back to the template from
// which they were instantiated.
@@ -459,6 +502,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
+ if (Field->hasAttrs())
+ SemaRef.CheckAlignasUnderalignment(Field);
+
if (Invalid)
Field->setInvalidDecl();
@@ -745,8 +791,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (!isFriend && Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
- if (Found.first != Found.second) {
- PrevClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first);
+ if (!Found.empty()) {
+ PrevClassTemplate = dyn_cast<ClassTemplateDecl>(Found.front());
if (PrevClassTemplate)
PrevDecl = PrevClassTemplate->getTemplatedDecl();
}
@@ -911,11 +957,11 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
// of the class template and return that.
DeclContext::lookup_result Found
= Owner->lookup(ClassTemplate->getDeclName());
- if (Found.first == Found.second)
+ if (Found.empty())
return 0;
ClassTemplateDecl *InstClassTemplate
- = dyn_cast<ClassTemplateDecl>(*Found.first);
+ = dyn_cast<ClassTemplateDecl>(Found.front());
if (!InstClassTemplate)
return 0;
@@ -1043,8 +1089,8 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
NewEPI.ExtInfo = OrigFunc->getExtInfo();
return Context.getFunctionType(NewFunc->getResultType(),
- NewFunc->arg_type_begin(),
- NewFunc->getNumArgs(),
+ ArrayRef<QualType>(NewFunc->arg_type_begin(),
+ NewFunc->getNumArgs()),
NewEPI);
}
@@ -1116,10 +1162,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getNameInfo(), T, TInfo,
- D->getStorageClass(), D->getStorageClassAsWritten(),
+ D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
D->isConstexpr());
+ if (D->isInlined())
+ Function->setImplicitlyInline();
+
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@@ -1287,7 +1336,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
//
// 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().CPlusPlus0x ||
+ if ((!SemaRef.getLangOpts().CPlusPlus11 ||
SemaRef.Diags.getDiagnosticLevel(
diag::warn_cxx98_compat_friend_redefinition,
Function->getLocation())
@@ -1298,11 +1347,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
SemaRef.Diag(Function->getLocation(),
- SemaRef.getLangOpts().CPlusPlus0x ?
+ SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_redefinition :
diag::err_redefinition) << Function->getDeclName();
SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
- if (!SemaRef.getLangOpts().CPlusPlus0x)
+ if (!SemaRef.getLangOpts().CPlusPlus11)
Function->setInvalidDecl();
}
// Check for redefinitions due to other instantiations of this or
@@ -1314,7 +1363,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
continue;
switch (R->getFriendObjectKind()) {
case Decl::FOK_None:
- if (!SemaRef.getLangOpts().CPlusPlus0x &&
+ if (!SemaRef.getLangOpts().CPlusPlus11 &&
!queuedInstantiation && R->isUsed(false)) {
if (MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo()) {
@@ -1333,12 +1382,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
= R->getTemplateInstantiationPattern())
if (RPattern->isDefined(RPattern)) {
SemaRef.Diag(Function->getLocation(),
- SemaRef.getLangOpts().CPlusPlus0x ?
+ SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_redefinition :
diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
- if (!SemaRef.getLangOpts().CPlusPlus0x)
+ if (!SemaRef.getLangOpts().CPlusPlus11)
Function->setInvalidDecl();
break;
}
@@ -1479,12 +1528,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
- D->isStatic(),
- D->getStorageClassAsWritten(),
+ D->getStorageClass(),
D->isInlineSpecified(),
D->isConstexpr(), D->getLocEnd());
}
+ if (D->isInlined())
+ Method->setImplicitlyInline();
+
if (QualifierLoc)
Method->setQualifierInfo(QualifierLoc);
@@ -1581,10 +1632,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
SemaRef.CheckOverrideControl(Method);
// If a function is defined as defaulted or deleted, mark it as such now.
- if (D->isDefaulted())
- Method->setDefaulted();
+ if (D->isExplicitlyDefaulted())
+ SemaRef.SetDeclDefaulted(Method, Method->getLocation());
if (D->isDeletedAsWritten())
- Method->setDeletedAsWritten();
+ SemaRef.SetDeclDeleted(Method, Method->getLocation());
// If there's a function template, let our caller handle it.
if (FunctionTemplate) {
@@ -1610,13 +1661,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Owner->addDecl(Method);
}
- if (D->isExplicitlyDefaulted()) {
- SemaRef.SetDeclDefaulted(Method, Method->getLocation());
- } else {
- assert(!D->isDefaulted() &&
- "should not implicitly default uninstantiated function");
- }
-
return Method;
}
@@ -1633,9 +1677,8 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
- llvm::Optional<unsigned>(),
- /*ExpectParameterPack=*/false);
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, None,
+ /*ExpectParameterPack=*/ false);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@@ -1701,7 +1744,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// The non-type template parameter pack's type is a pack expansion of types.
// Determine whether we need to expand this parameter pack into separate
// types.
- PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL);
+ PackExpansionTypeLoc Expansion = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = Expansion.getPatternLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
@@ -1710,9 +1753,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
+ Optional<unsigned> OrigNumExpansions
= Expansion.getTypePtr()->getNumExpansions();
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
Pattern.getSourceRange(),
Unexpanded,
@@ -1867,7 +1910,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
TempParams->getSourceRange(),
Unexpanded,
@@ -2069,7 +2112,7 @@ Decl * TemplateDeclInstantiator
SS.Adopt(QualifierLoc);
// Since NameInfo refers to a typename, it cannot be a C++ special name.
- // Hence, no tranformation is required for it.
+ // Hence, no transformation is required for it.
DeclarationNameInfo NameInfo(D->getDeclName(), D->getLocation());
NamedDecl *UD =
SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
@@ -2138,6 +2181,23 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
return NewFD;
}
+Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
+ OMPThreadPrivateDecl *D) {
+ SmallVector<DeclRefExpr *, 5> Vars;
+ for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take();
+ assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr");
+ Vars.push_back(cast<DeclRefExpr>(Var));
+ }
+
+ OMPThreadPrivateDecl *TD =
+ SemaRef.CheckOMPThreadPrivateDecl(D->getLocation(), Vars);
+
+ return TD;
+}
+
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
@@ -2330,18 +2390,17 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (NewTInfo != OldTInfo) {
// Get parameters from the new type info.
TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
- if (FunctionProtoTypeLoc *OldProtoLoc
- = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
+ if (FunctionProtoTypeLoc OldProtoLoc =
+ OldTL.getAs<FunctionProtoTypeLoc>()) {
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
- FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
- assert(NewProtoLoc && "Missing prototype?");
+ FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
unsigned NewIdx = 0;
- for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs();
+ for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumArgs();
OldIdx != NumOldParams; ++OldIdx) {
- ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx);
+ ParmVarDecl *OldParam = OldProtoLoc.getArg(OldIdx);
LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
- llvm::Optional<unsigned> NumArgumentsInExpansion;
+ Optional<unsigned> NumArgumentsInExpansion;
if (OldParam->isParameterPack())
NumArgumentsInExpansion =
SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
@@ -2349,14 +2408,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.getArg(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.getArg(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocalPackArg(OldParam, NewParam);
}
@@ -2368,10 +2427,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
// substitution occurred. However, we still need to instantiate
// the function parameters themselves.
TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
- if (FunctionProtoTypeLoc *OldProtoLoc
- = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
- for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) {
- ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i));
+ if (FunctionProtoTypeLoc OldProtoLoc =
+ OldTL.getAs<FunctionProtoTypeLoc>()) {
+ for (unsigned i = 0, i_end = OldProtoLoc.getNumArgs(); i != i_end; ++i) {
+ ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc.getArg(i));
if (!Parm)
return 0;
Params.push_back(Parm);
@@ -2403,7 +2462,7 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- llvm::Optional<unsigned> NumArgumentsInExpansion
+ Optional<unsigned> NumArgumentsInExpansion
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
assert(NumArgumentsInExpansion &&
"should only be called when all template arguments are known");
@@ -2434,7 +2493,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
ThisTypeQuals = Method->getTypeQualifiers();
}
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
- SemaRef.getLangOpts().CPlusPlus0x);
+ SemaRef.getLangOpts().CPlusPlus11);
// The function has an exception specification or a "noreturn"
// attribute. Substitute into each of the exception types.
@@ -2452,7 +2511,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
bool Expand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions
+ Optional<unsigned> NumExpansions
= PackExpansion->getNumExpansions();
if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
SourceRange(),
@@ -2541,8 +2600,8 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
EPI.NoexceptExpr = NoexceptExpr;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
EPI));
}
@@ -2560,8 +2619,8 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_None;
Decl->setType(Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
EPI));
return;
}
@@ -2605,12 +2664,12 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) {
+ = dyn_cast<FunctionTemplateDecl>(ActiveInst.Entity)) {
assert(FunTmpl->getTemplatedDecl() == Tmpl &&
"Deduction from the wrong function template?");
(void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
- ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
+ ActiveInst.Entity = New;
}
}
@@ -2622,7 +2681,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
// DR1330: In C++11, defer instantiation of a non-trivial
// exception specification.
- if (SemaRef.getLangOpts().CPlusPlus0x &&
+ if (SemaRef.getLangOpts().CPlusPlus11 &&
EPI.ExceptionSpecType != EST_None &&
EPI.ExceptionSpecType != EST_DynamicNone &&
EPI.ExceptionSpecType != EST_BasicNoexcept) {
@@ -2641,8 +2700,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpecDecl = New;
EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
EPI));
} else {
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
@@ -2770,6 +2829,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
!PatternDecl->isInlined())
return;
+ if (PatternDecl->isInlined())
+ Function->setImplicitlyInline();
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
@@ -2789,7 +2851,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
EnterExpressionEvaluationContext EvalContext(*this,
Sema::PotentiallyEvaluated);
- ActOnStartOfFunctionDef(0, Function);
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
@@ -2801,21 +2862,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
LocalInstantiationScope Scope(*this, MergeWithParentScope);
- // Enter the scope of this instantiation. We don't use
- // PushDeclContext because we don't have a scope.
- Sema::ContextRAII savedContext(*this, Function);
+ if (PatternDecl->isDefaulted())
+ SetDeclDefaulted(Function, PatternDecl->getLocation());
+ else {
+ ActOnStartOfFunctionDef(0, Function);
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ Sema::ContextRAII savedContext(*this, Function);
- addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
- TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
- if (PatternDecl->isDefaulted()) {
- ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
+ addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
+ TemplateArgs);
- SetDeclDefaulted(Function, PatternDecl->getLocation());
- } else {
// If this is a constructor, instantiate the member initializers.
if (const CXXConstructorDecl *Ctor =
dyn_cast<CXXConstructorDecl>(PatternDecl)) {
@@ -2831,11 +2892,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnFinishFunctionBody(Function, Body.get(),
/*IsInstantiation=*/true);
- }
- PerformDependentDiagnostics(PatternDecl, TemplateArgs);
+ PerformDependentDiagnostics(PatternDecl, TemplateArgs);
- savedContext.pop();
+ savedContext.pop();
+ }
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
@@ -2928,7 +2989,18 @@ void Sema::InstantiateStaticDataMemberDefinition(
if (TSK == TSK_ExplicitInstantiationDeclaration)
return;
- Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+ // Make sure to pass the instantiated variable to the consumer at the end.
+ struct PassToConsumerRAII {
+ ASTConsumer &Consumer;
+ VarDecl *Var;
+
+ PassToConsumerRAII(ASTConsumer &Consumer, VarDecl *Var)
+ : Consumer(Consumer), Var(Var) { }
+
+ ~PassToConsumerRAII() {
+ Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+ }
+ } PassToConsumerRAII(Consumer, Var);
// If we already have a definition, we're done.
if (VarDecl *Def = Var->getDefinition()) {
@@ -2965,12 +3037,11 @@ void Sema::InstantiateStaticDataMemberDefinition(
previousContext.pop();
if (Var) {
+ PassToConsumerRAII.Var = Var;
MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation());
- DeclGroupRef DG(Var);
- Consumer.HandleTopLevelDecl(DG);
}
Local.Exit();
@@ -3024,7 +3095,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
Unexpanded,
@@ -3142,49 +3213,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
ActOnMemInitializers(New,
/*FIXME: ColonLoc */
SourceLocation(),
- NewInits.data(), NewInits.size(),
+ NewInits,
AnyErrors);
}
-ExprResult Sema::SubstInitializer(Expr *Init,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool CXXDirectInit) {
- // Initializers are instantiated like expressions, except that various outer
- // layers are stripped.
- if (!Init)
- return Owned(Init);
-
- if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
- Init = ExprTemp->getSubExpr();
-
- while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
- Init = Binder->getSubExpr();
-
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
- Init = ICE->getSubExprAsWritten();
-
- // If this is a direct-initializer, we take apart CXXConstructExprs.
- // Everything else is passed through.
- CXXConstructExpr *Construct;
- if (!CXXDirectInit || !(Construct = dyn_cast<CXXConstructExpr>(Init)) ||
- isa<CXXTemporaryObjectExpr>(Construct))
- return SubstExpr(Init, TemplateArgs);
-
- SmallVector<Expr*, 8> NewArgs;
- if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
- TemplateArgs, NewArgs))
- return ExprError();
-
- // Treat an empty initializer like none.
- if (NewArgs.empty())
- return Owned((Expr*)0);
-
- // Build a ParenListExpr to represent anything else.
- // FIXME: Fake locations!
- SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart());
- return ActOnParenListExpr(Loc, Loc, NewArgs);
-}
-
// TODO: this could be templated if the various decl types used the
// same method name.
static bool isInstantiationOf(ClassTemplateDecl *Pattern,
@@ -3539,7 +3571,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
NamedDecl *Result = 0;
if (D->getDeclName()) {
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
- Result = findInstantiationOf(Context, D, Found.first, Found.second);
+ Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 6147d63ef44b..c0ad2be6d40e 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -10,14 +10,14 @@
//===----------------------------------------------------------------------===/
#include "clang/Sema/Sema.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/TypeLoc.h"
using namespace clang;
@@ -443,17 +443,16 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
if (!TSInfo)
return true;
- TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc,
- llvm::Optional<unsigned>());
+ TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None);
if (!TSResult)
return true;
return CreateParsedType(TSResult->getType(), TSResult);
}
-TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
- SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+TypeSourceInfo *
+Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
+ Optional<unsigned> NumExpansions) {
// Create the pack expansion type and source-location information.
QualType Result = CheckPackExpansion(Pattern->getType(),
Pattern->getTypeLoc().getSourceRange(),
@@ -462,7 +461,8 @@ TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
return 0;
TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result);
- PackExpansionTypeLoc TL = cast<PackExpansionTypeLoc>(TSResult->getTypeLoc());
+ PackExpansionTypeLoc TL =
+ TSResult->getTypeLoc().castAs<PackExpansionTypeLoc>();
TL.setEllipsisLoc(EllipsisLoc);
// Copy over the source-location information from the type.
@@ -472,10 +472,9 @@ TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
return TSResult;
}
-QualType Sema::CheckPackExpansion(QualType Pattern,
- SourceRange PatternRange,
+QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
// C++0x [temp.variadic]p5:
// The pattern of a pack expansion shall name one or more
// parameter packs that are not expanded by a nested pack
@@ -490,11 +489,11 @@ QualType Sema::CheckPackExpansion(QualType Pattern,
}
ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
- return CheckPackExpansion(Pattern, EllipsisLoc, llvm::Optional<unsigned>());
+ return CheckPackExpansion(Pattern, EllipsisLoc, None);
}
ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
if (!Pattern)
return ExprError();
@@ -526,13 +525,11 @@ getDepthAndIndex(NamedDecl *ND) {
return std::make_pair(TTP->getDepth(), TTP->getIndex());
}
-bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
- SourceRange PatternRange,
- ArrayRef<UnexpandedParameterPack> Unexpanded,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool &ShouldExpand,
- bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions) {
+bool Sema::CheckParameterPacksForExpansion(
+ SourceLocation EllipsisLoc, SourceRange PatternRange,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
+ const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
+ bool &RetainExpansion, Optional<unsigned> &NumExpansions) {
ShouldExpand = true;
RetainExpansion = false;
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
@@ -636,13 +633,13 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
return false;
}
-llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
+Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs) {
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
- llvm::Optional<unsigned> Result;
+ Optional<unsigned> Result;
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
// Compute the depth and index for this parameter pack.
unsigned Depth;
@@ -664,7 +661,7 @@ llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
if (Instantiation->is<Decl*>())
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
- return llvm::Optional<unsigned>();
+ return None;
unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
assert((!Result || *Result == Size) && "inconsistent pack sizes");
@@ -678,7 +675,7 @@ llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
!TemplateArgs.hasTemplateArgument(Depth, Index))
// The pattern refers to an unknown template argument. We're not ready to
// expand this pack yet.
- return llvm::Optional<unsigned>();
+ return None;
// Determine the size of the argument pack.
unsigned Size = TemplateArgs(Depth, Index).pack_size();
@@ -731,6 +728,14 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_class:
case TST_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;
}
@@ -837,7 +842,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
return ExprError();
}
- MarkAnyDeclReferenced(OpLoc, ParameterPack);
+ MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
ParameterPack, NameLoc, RParenLoc);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4b23167951aa..7169eeab9b93 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -11,18 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Template.h"
-#include "clang/Basic/OpenCL.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
-#include "clang/AST/Expr.h"
+#include "clang/Basic/OpenCL.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -30,7 +28,10 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -106,7 +107,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_Pascal: \
case AttributeList::AT_Regparm: \
case AttributeList::AT_Pcs: \
- case AttributeList::AT_PnaclCall \
+ case AttributeList::AT_PnaclCall: \
+ case AttributeList::AT_IntelOclBicc \
namespace {
/// An object which stores processing state for the entire
@@ -149,6 +151,10 @@ namespace {
return declarator;
}
+ bool isProcessingDeclSpec() const {
+ return chunkIndex == declarator.getNumTypeObjects();
+ }
+
unsigned getCurrentChunkIndex() const {
return chunkIndex;
}
@@ -159,8 +165,7 @@ namespace {
}
AttributeList *&getCurrentAttrListRef() const {
- assert(chunkIndex <= declarator.getNumTypeObjects());
- if (chunkIndex == declarator.getNumTypeObjects())
+ if (isProcessingDeclSpec())
return getMutableDeclSpec().getAttributes().getListRef();
return declarator.getTypeObject(chunkIndex).getAttrListRef();
}
@@ -269,8 +274,18 @@ static void moveAttrFromListToList(AttributeList &attr,
spliceAttrIntoList(attr, toList);
}
+/// The location of a type attribute.
+enum TypeAttrLocation {
+ /// The attribute is in the decl-specifier-seq.
+ TAL_DeclSpec,
+ /// The attribute is part of a DeclaratorChunk.
+ TAL_DeclChunk,
+ /// The attribute is immediately after the declaration's name.
+ TAL_DeclName
+};
+
static void processTypeAttrs(TypeProcessingState &state,
- QualType &type, bool isDeclSpec,
+ QualType &type, TypeAttrLocation TAL,
AttributeList *attrs);
static bool handleFunctionTypeAttr(TypeProcessingState &state,
@@ -291,6 +306,66 @@ static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
return handleObjCOwnershipTypeAttr(state, attr, type);
}
+/// Given the index of a declarator chunk, check whether that chunk
+/// directly specifies the return type of a function and, if so, find
+/// an appropriate place for it.
+///
+/// \param i - a notional index which the search will start
+/// immediately inside
+static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
+ unsigned i) {
+ assert(i <= declarator.getNumTypeObjects());
+
+ DeclaratorChunk *result = 0;
+
+ // First, look inwards past parens for a function declarator.
+ for (; i != 0; --i) {
+ DeclaratorChunk &fnChunk = declarator.getTypeObject(i-1);
+ switch (fnChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+
+ // If we find anything except a function, bail out.
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ return result;
+
+ // If we do find a function declarator, scan inwards from that,
+ // looking for a block-pointer declarator.
+ case DeclaratorChunk::Function:
+ for (--i; i != 0; --i) {
+ DeclaratorChunk &blockChunk = declarator.getTypeObject(i-1);
+ switch (blockChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ continue;
+ case DeclaratorChunk::BlockPointer:
+ result = &blockChunk;
+ goto continue_outer;
+ }
+ llvm_unreachable("bad declarator chunk kind");
+ }
+
+ // If we run out of declarators doing that, we're done.
+ return result;
+ }
+ llvm_unreachable("bad declarator chunk kind");
+
+ // Okay, reconsider from our new point.
+ continue_outer: ;
+ }
+
+ // Ran out of chunks, bail out.
+ return result;
+}
+
/// Given that an objc_gc attribute was written somewhere on a
/// declaration *other* than on the declarator itself (for which, use
/// distributeObjCPointerTypeAttrFromDeclarator), and given that it
@@ -300,22 +375,44 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state,
AttributeList &attr,
QualType type) {
Declarator &declarator = state.getDeclarator();
+
+ // Move it to the outermost normal or block pointer declarator.
for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) {
DeclaratorChunk &chunk = declarator.getTypeObject(i-1);
switch (chunk.Kind) {
case DeclaratorChunk::Pointer:
- case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::BlockPointer: {
+ // But don't move an ARC ownership attribute to the return type
+ // of a block.
+ DeclaratorChunk *destChunk = 0;
+ if (state.isProcessingDeclSpec() &&
+ attr.getKind() == AttributeList::AT_ObjCOwnership)
+ destChunk = maybeMovePastReturnType(declarator, i - 1);
+ if (!destChunk) destChunk = &chunk;
+
moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
- chunk.getAttrListRef());
+ destChunk->getAttrListRef());
return;
+ }
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
continue;
+ // We may be starting at the return type of a block.
+ case DeclaratorChunk::Function:
+ if (state.isProcessingDeclSpec() &&
+ attr.getKind() == AttributeList::AT_ObjCOwnership) {
+ if (DeclaratorChunk *dest = maybeMovePastReturnType(declarator, i)) {
+ moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
+ dest->getAttrListRef());
+ return;
+ }
+ }
+ goto error;
+
// Don't walk through these.
case DeclaratorChunk::Reference:
- case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
goto error;
}
@@ -452,6 +549,15 @@ distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
QualType &declSpecType) {
state.saveDeclSpecAttrs();
+ // C++11 attributes before the decl specifiers actually appertain to
+ // the declarators. Move them straight there. We don't support the
+ // 'put them wherever you like' semantics we allow for GNU attributes.
+ if (attr.isCXX11Attribute()) {
+ moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
+ state.getDeclarator().getAttrListRef());
+ return;
+ }
+
// Try to distribute to the innermost.
if (distributeFunctionTypeAttrToInnermost(state, attr,
state.getCurrentAttrListRef(),
@@ -501,6 +607,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
do {
next = attr->getNext();
+ // Do not distribute C++11 attributes. They have strict rules for what
+ // they appertain to.
+ if (attr->isCXX11Attribute())
+ continue;
+
switch (attr->getKind()) {
OBJC_POINTER_TYPE_ATTRS_CASELIST:
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
@@ -712,7 +823,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (!S.getLangOpts().C99) {
if (S.getLangOpts().CPlusPlus)
S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
@@ -731,7 +842,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (!S.getLangOpts().C99) {
if (S.getLangOpts().CPlusPlus)
S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
@@ -742,6 +853,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
}
case DeclSpec::TST_int128:
+ if (!S.PP.getTargetInfo().hasInt128Type())
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_int128_unsupported);
if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned)
Result = Context.UnsignedInt128Ty;
else
@@ -901,6 +1014,38 @@ 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);
@@ -936,57 +1081,27 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// list of type attributes to be temporarily saved while the type
// attributes are pushed around.
if (AttributeList *attrs = DS.getAttributes().getList())
- processTypeAttrs(state, Result, true, attrs);
+ processTypeAttrs(state, Result, TAL_DeclSpec, attrs);
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
- // Enforce C99 6.7.3p2: "Types other than pointer types derived from object
- // or incomplete types shall not be restrict-qualified." C++ also allows
- // restrict-qualified references.
- if (TypeQuals & DeclSpec::TQ_restrict) {
- if (Result->isAnyPointerType() || Result->isReferenceType()) {
- QualType EltTy;
- if (Result->isObjCObjectPointerType())
- EltTy = Result;
- else
- EltTy = Result->isPointerType() ?
- Result->getAs<PointerType>()->getPointeeType() :
- Result->getAs<ReferenceType>()->getPointeeType();
-
- // If we have a pointer or reference, the pointee must have an object
- // incomplete type.
- if (!EltTy->isIncompleteOrObjectType()) {
- S.Diag(DS.getRestrictSpecLoc(),
- diag::err_typecheck_invalid_restrict_invalid_pointee)
- << EltTy << DS.getSourceRange();
- TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
- }
- } else {
- S.Diag(DS.getRestrictSpecLoc(),
- diag::err_typecheck_invalid_restrict_not_pointer)
- << Result << DS.getSourceRange();
- TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
- }
- }
-
// Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
// of a function type includes any type qualifiers, the behavior is
// undefined."
if (Result->isFunctionType() && TypeQuals) {
- // Get some location to point at, either the C or V location.
- SourceLocation Loc;
if (TypeQuals & DeclSpec::TQ_const)
- Loc = DS.getConstSpecLoc();
+ S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers)
+ << Result << DS.getSourceRange();
else if (TypeQuals & DeclSpec::TQ_volatile)
- Loc = DS.getVolatileSpecLoc();
+ S.Diag(DS.getVolatileSpecLoc(), diag::warn_typecheck_function_qualifiers)
+ << Result << DS.getSourceRange();
else {
- assert((TypeQuals & DeclSpec::TQ_restrict) &&
- "Has CVR quals but not C, V, or R?");
- Loc = DS.getRestrictSpecLoc();
+ assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) &&
+ "Has CVRA quals but not C, V, R, or A?");
+ // No diagnostic; we'll diagnose 'restrict' or '_Atomic' applied to a
+ // function type later, in BuildQualifiedType.
}
- S.Diag(Loc, diag::warn_typecheck_function_qualifiers)
- << Result << DS.getSourceRange();
}
// C++ [dcl.ref]p1:
@@ -999,6 +1114,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
TypeQuals && Result->isReferenceType()) {
TypeQuals &= ~DeclSpec::TQ_const;
TypeQuals &= ~DeclSpec::TQ_volatile;
+ TypeQuals &= ~DeclSpec::TQ_atomic;
}
// C90 6.5.3 constraints: "The same type qualifier shall not appear more
@@ -1016,12 +1132,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
<< "volatile";
}
- // C90 doesn't have restrict, so it doesn't force us to produce a warning
- // in this case.
+ // C90 doesn't have restrict nor _Atomic, so it doesn't force us to
+ // produce a warning in this case.
}
- Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals);
- Result = Context.getQualifiedType(Result, Quals);
+ QualType Qualified = S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS);
+
+ // If adding qualifiers fails, just use the unqualified type.
+ if (Qualified.isNull())
+ declarator.setInvalidType(true);
+ else
+ Result = Qualified;
}
return Result;
@@ -1035,37 +1156,36 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
}
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
- Qualifiers Qs) {
+ Qualifiers Qs, const DeclSpec *DS) {
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
if (Qs.hasRestrict()) {
unsigned DiagID = 0;
QualType ProblemTy;
- const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
- if (const ReferenceType *RTy = dyn_cast<ReferenceType>(Ty)) {
- if (!RTy->getPointeeType()->isIncompleteOrObjectType()) {
- DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- ProblemTy = T->getAs<ReferenceType>()->getPointeeType();
- }
- } else if (const PointerType *PTy = dyn_cast<PointerType>(Ty)) {
- if (!PTy->getPointeeType()->isIncompleteOrObjectType()) {
- DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- ProblemTy = T->getAs<PointerType>()->getPointeeType();
- }
- } else if (const MemberPointerType *PTy = dyn_cast<MemberPointerType>(Ty)) {
- if (!PTy->getPointeeType()->isIncompleteOrObjectType()) {
+ if (T->isAnyPointerType() || T->isReferenceType() ||
+ T->isMemberPointerType()) {
+ QualType EltTy;
+ if (T->isObjCObjectPointerType())
+ EltTy = T;
+ else if (const MemberPointerType *PTy = T->getAs<MemberPointerType>())
+ EltTy = PTy->getPointeeType();
+ else
+ EltTy = T->getPointeeType();
+
+ // If we have a pointer or reference, the pointee must have an object
+ // incomplete type.
+ if (!EltTy->isIncompleteOrObjectType()) {
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- ProblemTy = T->getAs<PointerType>()->getPointeeType();
+ ProblemTy = EltTy;
}
- } else if (!Ty->isDependentType()) {
- // FIXME: this deserves a proper diagnostic
- DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
+ } else if (!T->isDependentType()) {
+ DiagID = diag::err_typecheck_invalid_restrict_not_pointer;
ProblemTy = T;
}
if (DiagID) {
- Diag(Loc, DiagID) << ProblemTy;
+ Diag(DS ? DS->getRestrictSpecLoc() : Loc, DiagID) << ProblemTy;
Qs.removeRestrict();
}
}
@@ -1073,6 +1193,39 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
return Context.getQualifiedType(T, Qs);
}
+QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
+ unsigned CVRA, const DeclSpec *DS) {
+ // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic.
+ unsigned CVR = CVRA & ~DeclSpec::TQ_atomic;
+
+ // C11 6.7.3/5:
+ // If the same qualifier appears more than once in the same
+ // specifier-qualifier-list, either directly or via one or more typedefs,
+ // the behavior is the same as if it appeared only once.
+ //
+ // It's not specified what happens when the _Atomic qualifier is applied to
+ // a type specified with the _Atomic specifier, but we assume that this
+ // should be treated as if the _Atomic qualifier appeared multiple times.
+ if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) {
+ // C11 6.7.3/5:
+ // If other qualifiers appear along with the _Atomic qualifier in a
+ // specifier-qualifier-list, the resulting type is the so-qualified
+ // atomic type.
+ //
+ // Don't need to worry about array types here, since _Atomic can't be
+ // applied to such types.
+ SplitQualType Split = T.getSplitUnqualifiedType();
+ T = BuildAtomicType(QualType(Split.Ty, 0),
+ DS ? DS->getAtomicSpecLoc() : Loc);
+ if (T.isNull())
+ return T;
+ Split.Quals.addCVRQualifiers(CVR);
+ return BuildQualifiedType(T, Loc, Split.Quals);
+ }
+
+ return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS);
+}
+
/// \brief Build a paren type including \p T.
QualType Sema::BuildParenType(QualType T) {
return Context.getParenType(T);
@@ -1338,7 +1491,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
// C99 6.7.5.2p1: The size expression shall have integer type.
// C++11 allows contextual conversions to such types.
- if (!getLangOpts().CPlusPlus0x &&
+ if (!getLangOpts().CPlusPlus11 &&
ArraySize && !ArraySize->isTypeDependent() &&
!ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
@@ -1359,7 +1512,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
isArraySizeVLA(*this, ArraySize, ConstVal)) {
// Even in C++11, don't allow contextual conversions in the array bound
// of a VLA.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
!ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
<< ArraySize->getType() << ArraySize->getSourceRange();
@@ -1409,6 +1562,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
}
+
+ // OpenCL v1.2 s6.9.d: variable length arrays are not supported.
+ if (getLangOpts().OpenCL && T->isVariableArrayType()) {
+ Diag(Loc, diag::err_opencl_vla);
+ return QualType();
+ }
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOpts().C99) {
if (T->isVariableArrayType()) {
@@ -1435,6 +1594,11 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
: diag::ext_c99_array_usage) << ASM;
}
+ if (T->isVariableArrayType()) {
+ // Warn about VLAs for -Wvla.
+ Diag(Loc, diag::warn_vla_used);
+ }
+
return T;
}
@@ -1475,45 +1639,10 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
}
-/// \brief Build a function type.
-///
-/// This routine checks the function type according to C++ rules and
-/// under the assumption that the result type and parameter types have
-/// just been instantiated from a template. It therefore duplicates
-/// some of the behavior of GetTypeForDeclarator, but in a much
-/// simpler form that is only suitable for this narrow use case.
-///
-/// \param T The return type of the function.
-///
-/// \param ParamTypes The parameter types of the function. This array
-/// will be modified to account for adjustments to the types of the
-/// function parameters.
-///
-/// \param NumParamTypes The number of parameter types in ParamTypes.
-///
-/// \param Variadic Whether this is a variadic function type.
-///
-/// \param HasTrailingReturn Whether this function has a trailing return type.
-///
-/// \param Quals The cvr-qualifiers to be applied to the function type.
-///
-/// \param Loc The location of the entity whose type involves this
-/// function type or, if there is no such entity, the location of the
-/// type that will have function type.
-///
-/// \param Entity The name of the entity that involves the function
-/// type, if known.
-///
-/// \returns A suitable function type, if there are no
-/// errors. Otherwise, returns a NULL type.
QualType Sema::BuildFunctionType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
+ llvm::MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info) {
+ const FunctionProtoType::ExtProtoInfo &EPI) {
if (T->isArrayType() || T->isFunctionType()) {
Diag(Loc, diag::err_func_returning_array_function)
<< T->isFunctionType() << T;
@@ -1528,7 +1657,7 @@ QualType Sema::BuildFunctionType(QualType T,
}
bool Invalid = false;
- for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
+ for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
// FIXME: Loc is too inprecise here, should use proper locations for args.
QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
if (ParamType->isVoidType()) {
@@ -1547,14 +1676,7 @@ QualType Sema::BuildFunctionType(QualType T,
if (Invalid)
return QualType();
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.Variadic = Variadic;
- EPI.HasTrailingReturn = HasTrailingReturn;
- EPI.TypeQuals = Quals;
- EPI.RefQualifier = RefQualifier;
- EPI.ExtInfo = Info;
-
- return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI);
+ return Context.getFunctionType(T, ParamTypes, EPI);
}
/// \brief Build a member pointer type \c T Class::*.
@@ -1601,13 +1723,33 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- // In the Microsoft ABI, the class is allowed to be an incomplete
- // type. In such cases, the compiler makes a worst-case assumption.
- // We make no such assumption right now, so emit an error if the
- // class isn't a complete type.
- if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
- RequireCompleteType(Loc, Class, diag::err_incomplete_type))
- 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));
+ }
+ }
+ }
+ }
return Context.getMemberPointerType(T, Class.getTypePtr());
}
@@ -1754,50 +1896,118 @@ static void inferARCWriteback(TypeProcessingState &state,
// TODO: mark whether we did this inference?
}
-static void DiagnoseIgnoredQualifiers(unsigned Quals,
- SourceLocation ConstQualLoc,
- SourceLocation VolatileQualLoc,
- SourceLocation RestrictQualLoc,
- Sema& S) {
- std::string QualStr;
+static void diagnoseIgnoredQualifiers(
+ Sema &S, unsigned Quals,
+ SourceLocation FallbackLoc,
+ SourceLocation ConstQualLoc = SourceLocation(),
+ SourceLocation VolatileQualLoc = SourceLocation(),
+ SourceLocation RestrictQualLoc = SourceLocation(),
+ SourceLocation AtomicQualLoc = SourceLocation()) {
+ if (!Quals)
+ return;
+
+ const SourceManager &SM = S.getSourceManager();
+
+ struct Qual {
+ unsigned Mask;
+ const char *Name;
+ SourceLocation Loc;
+ } const QualKinds[4] = {
+ { DeclSpec::TQ_const, "const", ConstQualLoc },
+ { DeclSpec::TQ_volatile, "volatile", VolatileQualLoc },
+ { DeclSpec::TQ_restrict, "restrict", RestrictQualLoc },
+ { DeclSpec::TQ_atomic, "_Atomic", AtomicQualLoc }
+ };
+
+ llvm::SmallString<32> QualStr;
unsigned NumQuals = 0;
SourceLocation Loc;
+ FixItHint FixIts[4];
+
+ // Build a string naming the redundant qualifiers.
+ for (unsigned I = 0; I != 4; ++I) {
+ if (Quals & QualKinds[I].Mask) {
+ if (!QualStr.empty()) QualStr += ' ';
+ QualStr += QualKinds[I].Name;
+
+ // If we have a location for the qualifier, offer a fixit.
+ SourceLocation QualLoc = QualKinds[I].Loc;
+ if (!QualLoc.isInvalid()) {
+ FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc);
+ if (Loc.isInvalid() || SM.isBeforeInTranslationUnit(QualLoc, Loc))
+ Loc = QualLoc;
+ }
- FixItHint ConstFixIt;
- FixItHint VolatileFixIt;
- FixItHint RestrictFixIt;
+ ++NumQuals;
+ }
+ }
- const SourceManager &SM = S.getSourceManager();
+ S.Diag(Loc.isInvalid() ? FallbackLoc : Loc, diag::warn_qual_return_type)
+ << 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) {
+ if (D.getTypeObject(FunctionChunkIndex).Fun.hasTrailingReturnType()) {
+ // FIXME: TypeSourceInfo doesn't preserve location information for
+ // qualifiers.
+ diagnoseIgnoredQualifiers(S, RetTy.getLocalCVRQualifiers(),
+ D.getIdentifierLoc());
+ return;
+ }
+
+ for (unsigned OuterChunkIndex = FunctionChunkIndex + 1,
+ End = D.getNumTypeObjects();
+ OuterChunkIndex != End; ++OuterChunkIndex) {
+ DeclaratorChunk &OuterChunk = D.getTypeObject(OuterChunkIndex);
+ switch (OuterChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+
+ case DeclaratorChunk::Pointer: {
+ DeclaratorChunk::PointerTypeInfo &PTI = OuterChunk.Ptr;
+ diagnoseIgnoredQualifiers(
+ S, PTI.TypeQuals,
+ SourceLocation(),
+ SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc));
+ return;
+ }
+
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::MemberPointer:
+ // 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());
+ return;
+ }
+
+ llvm_unreachable("unknown declarator chunk kind");
+ }
+
+ // If the qualifiers come from a conversion function type, don't diagnose
+ // them -- they're not necessarily redundant, since such a conversion
+ // operator can be explicitly called as "x.operator const int()".
+ if (D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId)
+ return;
- // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to
- // find a range and grow it to encompass all the qualifiers, regardless of
- // the order in which they textually appear.
- if (Quals & Qualifiers::Const) {
- ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc);
- QualStr = "const";
- ++NumQuals;
- if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc))
- Loc = ConstQualLoc;
- }
- if (Quals & Qualifiers::Volatile) {
- VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc);
- QualStr += (NumQuals == 0 ? "volatile" : " volatile");
- ++NumQuals;
- if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc))
- Loc = VolatileQualLoc;
- }
- if (Quals & Qualifiers::Restrict) {
- RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc);
- QualStr += (NumQuals == 0 ? "restrict" : " restrict");
- ++NumQuals;
- if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc))
- Loc = RestrictQualLoc;
- }
-
- assert(NumQuals > 0 && "No known qualifiers?");
-
- S.Diag(Loc, diag::warn_qual_return_type)
- << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
+ // 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());
}
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
@@ -1832,7 +2042,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// "void" instead.
T = SemaRef.Context.VoidTy;
if (AttributeList *attrs = D.getDeclSpec().getAttributes().getList())
- processTypeAttrs(state, T, true, attrs);
+ processTypeAttrs(state, T, TAL_DeclSpec, attrs);
break;
case UnqualifiedId::IK_ConversionFunctionId:
@@ -1851,7 +2061,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- (!SemaRef.getLangOpts().CPlusPlus0x || !D.isFunctionDeclarator())) {
+ (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1;
switch (D.getContext()) {
@@ -1917,7 +2127,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
- if (SemaRef.getLangOpts().CPlusPlus0x && Error != -1) {
+ if (SemaRef.getLangOpts().CPlusPlus11 && Error != -1) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
@@ -1969,6 +2179,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_alias_template)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
break;
case Declarator::TypeNameContext:
case Declarator::TemplateParamContext:
@@ -1979,6 +2190,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_type_specifier)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
break;
case Declarator::PrototypeContext:
case Declarator::ObjCParameterContext:
@@ -1989,6 +2201,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_param_type)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
break;
case Declarator::ConditionContext:
// C++ 6.4p2:
@@ -1996,6 +2209,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// a new class or enumeration.
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_condition);
+ D.setInvalidType(true);
break;
}
}
@@ -2087,7 +2301,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
if (!D.isFunctionDeclarator() ||
D.getFunctionDefinitionKind() != FDK_Declaration ||
!S.CurContext->isFunctionOrMethod() ||
- D.getDeclSpec().getStorageClassSpecAsWritten()
+ D.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_unspecified)
return;
@@ -2150,7 +2364,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
<< FixItHint::CreateRemoval(ParenRange);
else {
std::string Init = S.getFixItZeroInitializerForType(RT);
- if (Init.empty() && S.LangOpts.CPlusPlus0x)
+ if (Init.empty() && S.LangOpts.CPlusPlus11)
Init = "{}";
if (!Init.empty())
S.Diag(DeclType.Loc, diag::note_empty_parens_zero_initialize)
@@ -2376,38 +2590,61 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Do not allow returning half FP value.
// FIXME: This really should be in BuildFunctionType.
if (T->isHalfType()) {
- S.Diag(D.getIdentifierLoc(),
- diag::err_parameters_retval_cannot_have_fp16_type) << 1
- << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
- D.setInvalidType(true);
+ if (S.getLangOpts().OpenCL) {
+ if (!S.getOpenCLOptions().cl_khr_fp16) {
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T;
+ D.setInvalidType(true);
+ }
+ } else {
+ S.Diag(D.getIdentifierLoc(),
+ diag::err_parameters_retval_cannot_have_fp16_type) << 1;
+ D.setInvalidType(true);
+ }
}
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
- if (isa<PointerType>(T) && T.getLocalCVRQualifiers() &&
- (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) &&
- (!LangOpts.CPlusPlus || !T->isDependentType())) {
- assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?");
- DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
- assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer);
-
- DeclaratorChunk::PointerTypeInfo &PTI = ReturnTypeChunk.Ptr;
-
- DiagnoseIgnoredQualifiers(PTI.TypeQuals,
- SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
- SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
- SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
- S);
-
- } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
- (!LangOpts.CPlusPlus ||
- (!T->isDependentType() && !T->isRecordType()))) {
-
- DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(),
- D.getDeclSpec().getConstSpecLoc(),
- D.getDeclSpec().getVolatileSpecLoc(),
- D.getDeclSpec().getRestrictSpecLoc(),
- S);
+ if ((T.getCVRQualifiers() || T->isAtomicType()) &&
+ !(S.getLangOpts().CPlusPlus &&
+ (T->isDependentType() || T->isRecordType())))
+ diagnoseIgnoredFunctionQualifiers(S, T, D, chunkIndex);
+
+ // Objective-C ARC ownership qualifiers are ignored on the function
+ // return type (by type canonicalization). Complain if this attribute
+ // was written here.
+ if (T.getQualifiers().hasObjCLifetime()) {
+ SourceLocation AttrLoc;
+ if (chunkIndex + 1 < D.getNumTypeObjects()) {
+ DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
+ for (const AttributeList *Attr = ReturnTypeChunk.getAttrs();
+ Attr; Attr = Attr->getNext()) {
+ if (Attr->getKind() == AttributeList::AT_ObjCOwnership) {
+ AttrLoc = Attr->getLoc();
+ break;
+ }
+ }
+ }
+ if (AttrLoc.isInvalid()) {
+ for (const AttributeList *Attr
+ = D.getDeclSpec().getAttributes().getList();
+ Attr; Attr = Attr->getNext()) {
+ if (Attr->getKind() == AttributeList::AT_ObjCOwnership) {
+ AttrLoc = Attr->getLoc();
+ break;
+ }
+ }
+ }
+
+ if (AttrLoc.isValid()) {
+ // The ownership attributes are almost always written via
+ // the predefined
+ // __strong/__weak/__autoreleasing/__unsafe_unretained.
+ if (AttrLoc.isMacroID())
+ AttrLoc = S.SourceMgr.getImmediateExpansionRange(AttrLoc).first;
+
+ S.Diag(AttrLoc, diag::warn_arc_lifetime_result_type)
+ << T.getQualifiers().getObjCLifetime();
+ }
}
if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
@@ -2457,6 +2694,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// definition.
S.Diag(FTI.ArgInfo[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);
break;
}
@@ -2514,10 +2753,18 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (ArgTy->isHalfType()) {
// Disallow half FP arguments.
// FIXME: This really should be in BuildFunctionType.
- S.Diag(Param->getLocation(),
- diag::err_parameters_retval_cannot_have_fp16_type) << 0
- << FixItHint::CreateInsertion(Param->getLocation(), "*");
- D.setInvalidType();
+ if (S.getLangOpts().OpenCL) {
+ if (!S.getOpenCLOptions().cl_khr_fp16) {
+ S.Diag(Param->getLocation(),
+ diag::err_opencl_half_argument) << ArgTy;
+ D.setInvalidType();
+ Param->setInvalidDecl();
+ }
+ } else {
+ S.Diag(Param->getLocation(),
+ diag::err_parameters_retval_cannot_have_fp16_type) << 0;
+ D.setInvalidType();
+ }
} else if (!FTI.hasPrototype) {
if (ArgTy->isPromotableIntegerType()) {
ArgTy = Context.getPromotedIntegerType(ArgTy);
@@ -2568,7 +2815,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI);
- T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);
+ T = Context.getFunctionType(T, ArgTys, EPI);
}
break;
@@ -2634,7 +2881,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// See if there are any attributes on this declarator chunk.
if (AttributeList *attrs = const_cast<AttributeList*>(DeclType.getAttrs()))
- processTypeAttrs(state, T, false, attrs);
+ processTypeAttrs(state, T, TAL_DeclChunk, attrs);
}
if (LangOpts.CPlusPlus && T->isFunctionType()) {
@@ -2659,30 +2906,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FreeFunction = (DC && !DC->isRecord());
}
- // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
- // function that is not a constructor declares that function to be const.
- // FIXME: This should be deferred until we know whether this is a static
- // member function (for an out-of-class definition, we don't know
- // this until we perform redeclaration lookup).
- if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
- D.getName().getKind() != UnqualifiedId::IK_ConstructorName &&
- D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId &&
- !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) {
- // Rebuild function type adding a 'const' qualifier.
- FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
- EPI.TypeQuals |= DeclSpec::TQ_const;
- T = Context.getFunctionType(FnTy->getResultType(),
- FnTy->arg_type_begin(),
- FnTy->getNumArgs(), EPI);
- // Rebuild any parens around the identifier in the function type.
- for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
- if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)
- break;
- T = S.BuildParenType(T);
- }
- }
-
// C++11 [dcl.fct]p6 (w/DR1417):
// An attempt to specify a function type with a cv-qualifier-seq or a
// ref-qualifier (including by typedef-name) is ill-formed unless it is:
@@ -2732,8 +2955,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
EPI.RefQualifier = RQ_None;
T = Context.getFunctionType(FnTy->getResultType(),
- FnTy->arg_type_begin(),
- FnTy->getNumArgs(), EPI);
+ ArrayRef<QualType>(FnTy->arg_type_begin(),
+ FnTy->getNumArgs()),
+ EPI);
// Rebuild any parens around the identifier in the function type.
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)
@@ -2746,7 +2970,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Apply any undistributed attributes from the declarator.
if (!T.isNull())
if (AttributeList *attrs = D.getAttributes())
- processTypeAttrs(state, T, false, attrs);
+ processTypeAttrs(state, T, TAL_DeclName, attrs);
// Diagnose any ignored type attributes.
if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T);
@@ -2782,7 +3006,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
} else {
- T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
+ T = Context.getPackExpansionType(T, None);
}
break;
@@ -2796,10 +3020,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// parameter packs in the type of the non-type template parameter, then
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
- T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
+ T = Context.getPackExpansionType(T, None);
else
S.Diag(D.getEllipsisLoc(),
- LangOpts.CPlusPlus0x
+ LangOpts.CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
break;
@@ -3006,6 +3230,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_Pcs;
case AttributedType::attr_pnaclcall:
return AttributeList::AT_PnaclCall;
+ case AttributedType::attr_inteloclbicc:
+ return AttributeList::AT_IntelOclBicc;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -3099,13 +3325,13 @@ namespace {
TypeLoc OldTL = TInfo->getTypeLoc();
if (TInfo->getType()->getAs<ElaboratedType>()) {
- ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(OldTL);
- TemplateSpecializationTypeLoc NamedTL =
- cast<TemplateSpecializationTypeLoc>(ElabTL.getNamedTypeLoc());
+ ElaboratedTypeLoc ElabTL = OldTL.castAs<ElaboratedTypeLoc>();
+ TemplateSpecializationTypeLoc NamedTL = ElabTL.getNamedTypeLoc()
+ .castAs<TemplateSpecializationTypeLoc>();
TL.copy(NamedTL);
}
else
- TL.copy(cast<TemplateSpecializationTypeLoc>(OldTL));
+ TL.copy(OldTL.castAs<TemplateSpecializationTypeLoc>());
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
@@ -3153,7 +3379,7 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
if (TInfo) {
- TL.copy(cast<ElaboratedTypeLoc>(TInfo->getTypeLoc()));
+ TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>());
return;
}
}
@@ -3169,7 +3395,7 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
- TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc()));
+ TL.copy(TInfo->getTypeLoc().castAs<DependentNameTypeLoc>());
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
@@ -3177,19 +3403,29 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
- TL.copy(cast<DependentTemplateSpecializationTypeLoc>(
- TInfo->getTypeLoc()));
+ TL.copy(
+ TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());
}
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
void VisitAtomicTypeLoc(AtomicTypeLoc TL) {
- TL.setKWLoc(DS.getTypeSpecTypeLoc());
- TL.setParensRange(DS.getTypeofParensRange());
+ // An AtomicTypeLoc can come from either an _Atomic(...) type specifier
+ // or an _Atomic qualifier.
+ if (DS.getTypeSpecType() == DeclSpec::TST_atomic) {
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
- TypeSourceInfo *TInfo = 0;
- Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ assert(TInfo);
+ TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ } else {
+ TL.setKWLoc(DS.getAtomicSpecLoc());
+ // No parens, to indicate this was spelled as an _Atomic qualifier.
+ TL.setParensRange(SourceRange());
+ Visit(TL.getValueLoc());
+ }
}
void VisitTypeLoc(TypeLoc TL) {
@@ -3239,7 +3475,7 @@ namespace {
case NestedNameSpecifier::Identifier:
assert(isa<DependentNameType>(ClsTy) && "Unexpected TypeLoc");
{
- DependentNameTypeLoc DNTLoc = cast<DependentNameTypeLoc>(ClsTL);
+ DependentNameTypeLoc DNTLoc = ClsTL.castAs<DependentNameTypeLoc>();
DNTLoc.setElaboratedKeywordLoc(SourceLocation());
DNTLoc.setQualifierLoc(NNSLoc.getPrefix());
DNTLoc.setNameLoc(NNSLoc.getLocalBeginLoc());
@@ -3249,7 +3485,7 @@ namespace {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
if (isa<ElaboratedType>(ClsTy)) {
- ElaboratedTypeLoc ETLoc = *cast<ElaboratedTypeLoc>(&ClsTL);
+ ElaboratedTypeLoc ETLoc = ClsTL.castAs<ElaboratedTypeLoc>();
ETLoc.setElaboratedKeywordLoc(SourceLocation());
ETLoc.setQualifierLoc(NNSLoc.getPrefix());
TypeLoc NamedTL = ETLoc.getNamedTypeLoc();
@@ -3312,6 +3548,29 @@ namespace {
};
}
+static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
+ SourceLocation Loc;
+ switch (Chunk.Kind) {
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Paren:
+ llvm_unreachable("cannot be _Atomic qualified");
+
+ case DeclaratorChunk::Pointer:
+ Loc = SourceLocation::getFromRawEncoding(Chunk.Ptr.AtomicQualLoc);
+ break;
+
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ // FIXME: Provide a source location for the _Atomic keyword.
+ break;
+ }
+
+ ATL.setKWLoc(Loc);
+ ATL.setParensRange(SourceRange());
+}
+
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
@@ -3328,13 +3587,19 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
// Handle parameter packs whose type is a pack expansion.
if (isa<PackExpansionType>(T)) {
- cast<PackExpansionTypeLoc>(CurrTL).setEllipsisLoc(D.getEllipsisLoc());
+ CurrTL.castAs<PackExpansionTypeLoc>().setEllipsisLoc(D.getEllipsisLoc());
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
- while (isa<AttributedTypeLoc>(CurrTL)) {
- AttributedTypeLoc TL = cast<AttributedTypeLoc>(CurrTL);
+ // An AtomicTypeLoc might be produced by an atomic qualifier in this
+ // declarator chunk.
+ if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) {
+ fillAtomicQualLoc(ATL, D.getTypeObject(i));
+ CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
+ }
+
+ while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs());
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
}
@@ -3389,7 +3654,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// Make sure there are no unused decl attributes on the declarator.
// We don't want to do this for ObjC parameters because we're going
// to apply them to the actual parameter declaration.
- if (D.getContext() != Declarator::ObjCParameterContext)
+ // Likewise, we don't want to do this for alias declarations, because
+ // we are actually going to build a declaration from this eventually.
+ if (D.getContext() != Declarator::ObjCParameterContext &&
+ D.getContext() != Declarator::AliasDeclContext &&
+ D.getContext() != Declarator::AliasTemplateContext)
checkUnusedDeclAttributes(D);
if (getLangOpts().CPlusPlus) {
@@ -3524,6 +3793,14 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
} else if (!type->isObjCRetainableType()) {
return false;
}
+
+ // Don't accept an ownership attribute in the declspec if it would
+ // just be the return type of a block pointer.
+ if (state.isProcessingDeclSpec()) {
+ Declarator &D = state.getDeclarator();
+ if (maybeMovePastReturnType(D, D.getNumTypeObjects()))
+ return false;
+ }
}
Sema &S = state.getSema();
@@ -3630,10 +3907,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Forbid __weak for class objects marked as
// objc_arc_weak_reference_unavailable
if (lifetime == Qualifiers::OCL_Weak) {
- QualType T = type;
- while (const PointerType *ptr = T->getAs<PointerType>())
- T = ptr->getPointeeType();
- if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *ObjT =
+ type->getAs<ObjCObjectPointerType>()) {
if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) {
if (Class->isArcWeakrefUnavailable()) {
S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
@@ -4141,7 +4416,7 @@ static void HandleNeonVectorTypeAttr(QualType& CurType,
}
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
- bool isDeclSpec, AttributeList *attrs) {
+ TypeAttrLocation TAL, AttributeList *attrs) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they
@@ -4156,10 +4431,45 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (attr.isInvalid())
continue;
+ if (attr.isCXX11Attribute()) {
+ // [[gnu::...]] attributes are treated as declaration attributes, so may
+ // not appertain to a DeclaratorChunk, even if we handle them as type
+ // attributes.
+ if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) {
+ if (TAL == TAL_DeclChunk) {
+ state.getSema().Diag(attr.getLoc(),
+ diag::warn_cxx11_gnu_attribute_on_type)
+ << attr.getName();
+ continue;
+ }
+ } else if (TAL != TAL_DeclChunk) {
+ // Otherwise, only consider type processing for a C++11 attribute if
+ // it's actually been applied to a type.
+ continue;
+ }
+ }
+
// If this is an attribute we can handle, do so now,
// otherwise, add it to the FnAttrs list for rechaining.
switch (attr.getKind()) {
- default: break;
+ default:
+ // A C++11 attribute on a declarator chunk must appertain to a type.
+ if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) {
+ state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr)
+ << attr.getName();
+ attr.setUsedAsTypeAttr();
+ }
+ break;
+
+ case AttributeList::UnknownAttribute:
+ if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk)
+ state.getSema().Diag(attr.getLoc(),
+ diag::warn_unknown_attribute_ignored)
+ << attr.getName();
+ break;
+
+ case AttributeList::IgnoredAttribute:
+ break;
case AttributeList::AT_MayAlias:
// FIXME: This attribute needs to actually be handled, but if we ignore
@@ -4180,9 +4490,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_ExtVectorType:
- if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_typedef)
- HandleExtVectorTypeAttr(type, attr, state.getSema());
+ HandleExtVectorTypeAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_NeonVectorType:
@@ -4204,13 +4512,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_Win64:
case AttributeList::AT_Ptr32:
case AttributeList::AT_Ptr64:
- // FIXME: don't ignore these
+ // FIXME: Don't ignore these. We have partial handling for them as
+ // declaration attributes in SemaDeclAttr.cpp; that should be moved here.
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_NSReturnsRetained:
if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
+ break;
// fallthrough into the function attrs
FUNCTION_TYPE_ATTRS_CASELIST:
@@ -4218,7 +4527,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// Never process function type attributes as part of the
// declaration-specifiers.
- if (isDeclSpec)
+ if (TAL == TAL_DeclSpec)
distributeFunctionTypeAttrFromDeclSpec(state, attr, type);
// Otherwise, handle the possible delays.
@@ -4359,9 +4668,14 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
// repeating the diagnostic.
// FIXME: Add a Fix-It that imports the corresponding module or includes
// the header.
- if (isSFINAEContext() || HiddenDefinitions.insert(Def)) {
- Diag(Loc, diag::err_module_private_definition) << T;
- Diag(Def->getLocation(), diag::note_previous_definition);
+ Module *Owner = Def->getOwningModule();
+ Diag(Loc, diag::err_module_private_definition)
+ << T << Owner->getFullModuleName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+
+ if (!isSFINAEContext()) {
+ // Recover by implicitly importing this module.
+ createImplicitModuleImport(Loc, Owner);
}
}
@@ -4562,6 +4876,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
diag::note_non_literal_user_provided_dtor :
diag::note_non_literal_nontrivial_dtor) << RD;
+ if (!Dtor->isUserProvided())
+ SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true);
}
return true;
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index 25ace950e077..2f7701227da6 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "TargetAttributesSema.h"
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/Triple.h"
using namespace clang;
@@ -151,7 +151,8 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
S.Context));
}
-DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range) {
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
if (D->hasAttr<DLLExportAttr>()) {
Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
return NULL;
@@ -160,7 +161,8 @@ DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range) {
if (D->hasAttr<DLLImportAttr>())
return NULL;
- return ::new (Context) DLLImportAttr(Range, Context);
+ return ::new (Context) DLLImportAttr(Range, Context,
+ AttrSpellingListIndex);
}
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -189,12 +191,14 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange());
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
if (NewAttr)
D->addAttr(NewAttr);
}
-DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range) {
+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>();
@@ -203,7 +207,8 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range) {
if (D->hasAttr<DLLExportAttr>())
return NULL;
- return ::new (Context) DLLExportAttr(Range, Context);
+ return ::new (Context) DLLExportAttr(Range, Context,
+ AttrSpellingListIndex);
}
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -229,7 +234,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange());
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -262,6 +268,57 @@ namespace {
};
}
+static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 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.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 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;
@@ -275,6 +332,9 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const {
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/TreeTransform.h b/lib/Sema/TreeTransform.h
index 294d74244673..bdd68a7bde90 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -14,11 +14,7 @@
#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
#define LLVM_CLANG_SEMA_TREETRANSFORM_H
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Sema/ScopeInfo.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -28,12 +24,16 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
-#include "clang/Sema/Ownership.h"
-#include "clang/Sema/Designator.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Designator.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
-#include "TypeLocBuilder.h"
#include <algorithm>
namespace clang {
@@ -247,10 +247,10 @@ public:
/// must be set.
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand,
bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions) {
+ Optional<unsigned> &NumExpansions) {
ShouldExpand = false;
return false;
}
@@ -323,6 +323,15 @@ public:
/// \returns the transformed expression.
ExprResult TransformExpr(Expr *E);
+ /// \brief Transform the given initializer.
+ ///
+ /// By default, this routine transforms an initializer by stripping off the
+ /// semantic nodes added by initialization, then passing the result to
+ /// TransformExpr or TransformExprs.
+ ///
+ /// \returns the transformed initializer.
+ ExprResult TransformInitializer(Expr *Init, bool CXXDirectInit);
+
/// \brief Transform the given list of expressions.
///
/// This routine transforms a list of expressions by invoking
@@ -563,7 +572,7 @@ public:
/// scope index; can be negative
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -704,12 +713,8 @@ public:
/// By default, performs semantic analysis when building the function type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildFunctionProtoType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info);
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI);
/// \brief Build a new unprototyped function type.
QualType RebuildFunctionNoProtoType(QualType ResultType);
@@ -941,7 +946,7 @@ public:
QualType RebuildPackExpansionType(QualType Pattern,
SourceRange PatternRange,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc,
NumExpansions);
}
@@ -2113,6 +2118,7 @@ public:
bool IsElidable,
MultiExprArg Args,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
@@ -2124,6 +2130,7 @@ public:
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
ConvertedArgs,
HadMultipleCandidates,
+ ListInitialization,
RequiresZeroInit, ConstructKind,
ParenRange);
}
@@ -2214,7 +2221,7 @@ public:
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc,
SourceLocation RParenLoc,
- llvm::Optional<unsigned> Length) {
+ Optional<unsigned> Length) {
if (Length)
return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
OperatorLoc, Pack, PackLoc,
@@ -2382,13 +2389,14 @@ 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) {
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,
- /*FIME:*/IsaLoc,
+ OpLoc,
SS, 0, false);
if (Result.isInvalid() || Base.isInvalid())
return ExprError();
@@ -2397,7 +2405,7 @@ public:
return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
- /*FIXME:*/IsaLoc, IsArrow,
+ OpLoc, IsArrow,
SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
R,
@@ -2416,10 +2424,10 @@ public:
= SemaRef.Context.Idents.get("__builtin_shufflevector");
TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl();
DeclContext::lookup_result Lookup = TUDecl->lookup(DeclarationName(&Name));
- assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?");
+ assert(!Lookup.empty() && "No __builtin_shufflevector?");
// Build a reference to the __builtin_shufflevector builtin
- FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
+ FunctionDecl *Builtin = cast<FunctionDecl>(Lookup.front());
Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false,
SemaRef.Context.BuiltinFnTy,
VK_RValue, BuiltinLoc);
@@ -2445,7 +2453,7 @@ public:
/// different behavior.
TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
switch (Pattern.getArgument().getKind()) {
case TemplateArgument::Expression: {
ExprResult Result
@@ -2492,7 +2500,7 @@ public:
/// for an expression. Subclasses may override this routine to provide
/// different behavior.
ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
}
@@ -2549,7 +2557,7 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
if (E.isInvalid())
return StmtError();
- return getSema().ActOnExprStmt(getSema().MakeFullExpr(E.take()));
+ return getSema().ActOnExprStmt(E);
}
}
@@ -2575,6 +2583,65 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
}
template<typename Derived>
+ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
+ bool CXXDirectInit) {
+ // Initializers are instantiated like expressions, except that various outer
+ // layers are stripped.
+ if (!Init)
+ return SemaRef.Owned(Init);
+
+ if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
+ Init = ExprTemp->getSubExpr();
+
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = Binder->getSubExpr();
+
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
+ Init = ICE->getSubExprAsWritten();
+
+ // If this is not a direct-initializer, 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()))
+ return getDerived().TransformExpr(Init);
+
+ // Revert value-initialization back to empty parens.
+ if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) {
+ SourceRange Parens = VIE->getSourceRange();
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), MultiExprArg(),
+ Parens.getEnd());
+ }
+
+ // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization.
+ if (isa<ImplicitValueInitExpr>(Init))
+ return getDerived().RebuildParenListExpr(SourceLocation(), MultiExprArg(),
+ SourceLocation());
+
+ // Revert initialization by constructor back to a parenthesized or braced list
+ // of expressions. Any other form of initializer can just be reused directly.
+ if (!Construct || isa<CXXTemporaryObjectExpr>(Construct))
+ return getDerived().TransformExpr(Init);
+
+ SmallVector<Expr*, 8> NewArgs;
+ bool ArgChanged = false;
+ if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
+ /*IsCall*/true, NewArgs, &ArgChanged))
+ return ExprError();
+
+ // If this was list initialization, revert to list form.
+ if (Construct->isListInitialization())
+ return getDerived().RebuildInitList(Construct->getLocStart(), NewArgs,
+ Construct->getLocEnd(),
+ Construct->getType());
+
+ // Build a ParenListExpr to represent anything else.
+ SourceRange Parens = Construct->getParenRange();
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), NewArgs,
+ Parens.getEnd());
+}
+
+template<typename Derived>
bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
unsigned NumInputs,
bool IsCall,
@@ -2600,9 +2667,8 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
- = Expansion->getNumExpansions();
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions();
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -2656,7 +2722,9 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
continue;
}
- ExprResult Result = getDerived().TransformExpr(Inputs[I]);
+ ExprResult Result =
+ IsCall ? getDerived().TransformInitializer(Inputs[I], /*DirectInit*/false)
+ : getDerived().TransformExpr(Inputs[I]);
if (Result.isInvalid())
return true;
@@ -2732,7 +2800,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
return NestedNameSpecifierLoc();
if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
- (SemaRef.getLangOpts().CPlusPlus0x &&
+ (SemaRef.getLangOpts().CPlusPlus11 &&
TL.getType()->isEnumeralType())) {
assert(!TL.getType().hasLocalQualifiers() &&
"Can't get cv-qualifiers here");
@@ -2745,8 +2813,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
}
// If the nested-name-specifier is an invalid type def, don't emit an
// error because a previous error should have already been emitted.
- TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL);
- if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) {
+ TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>();
+ if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) {
SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
<< TL.getType() << SS.getRange();
}
@@ -3119,7 +3187,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
// We have a pack expansion, for which we will be substituting into
// the pattern.
SourceLocation Ellipsis;
- llvm::Optional<unsigned> OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern
= In.getPackExpansionPattern(Ellipsis, OrigNumExpansions,
getSema().Context);
@@ -3132,7 +3200,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
Unexpanded,
@@ -3254,9 +3322,10 @@ QualType
TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
switch (T.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- case TypeLoc::CLASS: \
- return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T));
+#define TYPELOC(CLASS, PARENT) \
+ case TypeLoc::CLASS: \
+ return getDerived().Transform##CLASS##Type(TLB, \
+ T.castAs<CLASS##TypeLoc>());
#include "clang/AST/TypeLocNodes.def"
}
@@ -3293,6 +3362,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
// Objective-C ARC:
// A lifetime qualifier applied to a substituted template parameter
// overrides the lifetime qualifier from the template argument.
+ const AutoType *AutoTy;
if (const SubstTemplateTypeParmType *SubstTypeParam
= dyn_cast<SubstTemplateTypeParmType>(Result)) {
QualType Replacement = SubstTypeParam->getReplacementType();
@@ -3305,6 +3375,15 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
SubstTypeParam->getReplacedParameter(),
Replacement);
TLB.TypeWasModifiedSafely(Result);
+ } else if ((AutoTy = dyn_cast<AutoType>(Result)) && AutoTy->isDeduced()) {
+ // 'auto' types behave the same way as template parameters.
+ QualType Deduced = AutoTy->getDeducedType();
+ Qualifiers Qs = Deduced.getQualifiers();
+ Qs.removeObjCLifetime();
+ Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
+ Qs);
+ Result = SemaRef.Context.getAutoType(Deduced);
+ TLB.TypeWasModifiedSafely(Result);
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
@@ -3318,7 +3397,9 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
}
if (!Quals.empty()) {
Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals);
- TLB.push<QualifiedTypeLoc>(Result);
+ // BuildQualifiedType might not add qualifiers if they are invalid.
+ if (Result.hasLocalQualifiers())
+ TLB.push<QualifiedTypeLoc>(Result);
// No location information to preserve.
}
@@ -3339,8 +3420,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
QualType Result;
if (isa<TemplateSpecializationType>(T)) {
- TemplateSpecializationTypeLoc SpecTL
- = cast<TemplateSpecializationTypeLoc>(TL);
+ TemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<TemplateSpecializationTypeLoc>();
TemplateName Template =
getDerived().TransformTemplateName(SS,
@@ -3353,8 +3434,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
- DependentTemplateSpecializationTypeLoc SpecTL
- = cast<DependentTemplateSpecializationTypeLoc>(TL);
+ DependentTemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<DependentTemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().RebuildTemplateName(SS,
@@ -3396,8 +3477,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
TypeLoc TL = TSInfo->getTypeLoc();
if (isa<TemplateSpecializationType>(T)) {
- TemplateSpecializationTypeLoc SpecTL
- = cast<TemplateSpecializationTypeLoc>(TL);
+ TemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<TemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().TransformTemplateName(SS,
@@ -3410,8 +3491,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
- DependentTemplateSpecializationTypeLoc SpecTL
- = cast<DependentTemplateSpecializationTypeLoc>(TL);
+ DependentTemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<DependentTemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().RebuildTemplateName(SS,
@@ -3864,12 +3945,10 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
return Result;
}
-template<typename Derived>
-ParmVarDecl *
-TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
- int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
+template <typename Derived>
+ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
+ ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
@@ -3877,7 +3956,7 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
// If we're substituting into a pack expansion type and we know the
// length we want to expand to, just substitute for the pattern.
TypeLoc OldTL = OldDI->getTypeLoc();
- PackExpansionTypeLoc OldExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
+ PackExpansionTypeLoc OldExpansionTL = OldTL.castAs<PackExpansionTypeLoc>();
TypeLocBuilder TLB;
TypeLoc NewTL = OldDI->getTypeLoc();
@@ -3915,7 +3994,6 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
NewDI->getType(),
NewDI,
OldParm->getStorageClass(),
- OldParm->getStorageClassAsWritten(),
/* DefArg */ NULL);
newParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
@@ -3935,7 +4013,7 @@ bool TreeTransform<Derived>::
if (ParmVarDecl *OldParm = Params[i]) {
assert(OldParm->getFunctionScopeIndex() == i);
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
ParmVarDecl *NewParm = 0;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
@@ -3943,7 +4021,7 @@ bool TreeTransform<Derived>::
// Find the parameter packs that could be expanded.
TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL);
+ PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = ExpansionTL.getPatternLoc();
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
@@ -3951,8 +4029,8 @@ bool TreeTransform<Derived>::
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
- = ExpansionTL.getTypePtr()->getNumExpansions();
+ Optional<unsigned> OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
Pattern.getSourceRange(),
@@ -4017,10 +4095,8 @@ bool TreeTransform<Derived>::
NumExpansions,
/*ExpectParameterPack=*/true);
} else {
- NewParm = getDerived().TransformFunctionTypeParam(OldParm,
- indexAdjustment,
- llvm::Optional<unsigned>(),
- /*ExpectParameterPack=*/false);
+ NewParm = getDerived().TransformFunctionTypeParam(
+ OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
}
if (!NewParm)
@@ -4036,7 +4112,7 @@ bool TreeTransform<Derived>::
// declaration for this parameter.
QualType OldType = ParamTypes[i];
bool IsPackExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
QualType NewType;
if (const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(OldType)) {
@@ -4188,14 +4264,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
ResultType != T->getResultType() ||
T->getNumArgs() != ParamTypes.size() ||
!std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) {
- Result = getDerived().RebuildFunctionProtoType(ResultType,
- ParamTypes.data(),
- ParamTypes.size(),
- T->isVariadic(),
- T->hasTrailingReturn(),
- T->getTypeQuals(),
- T->getRefQualifier(),
- T->getExtInfo());
+ Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
+ T->getExtProtoInfo());
if (Result.isNull())
return QualType();
}
@@ -4561,7 +4631,6 @@ QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB,
return Result;
}
-namespace {
/// \brief Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
///
@@ -4625,7 +4694,6 @@ namespace {
return !(X == Y);
}
};
-}
template <typename Derived>
@@ -5379,7 +5447,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (Inc.isInvalid())
return StmtError();
- Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc.get()));
+ Sema::FullExprArg FullInc(getSema().MakeFullDiscardedValueExpr(Inc.get()));
if (S->getInc() && !FullInc.get())
return StmtError();
@@ -6946,17 +7014,13 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
Type == E->getTypeInfoAsWritten() &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E);
-
- // FIXME: Poor source location information here.
- SourceLocation FakeLAngleLoc
- = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
- SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
- FakeLAngleLoc,
+ E->getAngleBrackets().getBegin(),
Type,
- FakeRAngleLoc,
- FakeRAngleLoc,
+ E->getAngleBrackets().getEnd(),
+ // FIXME. this should be '(' location
+ E->getAngleBrackets().getEnd(),
SubExpr.get(),
E->getRParenLoc());
}
@@ -7105,9 +7169,14 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
QualType T;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
T = MD->getThisType(getSema().Context);
- else
+ else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
T = getSema().Context.getPointerType(
- getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
+ getSema().Context.getRecordType(Record));
+ } else {
+ assert(SemaRef.Context.getDiagnostics().hasErrorOccurred() &&
+ "this in the wrong scope?");
+ return ExprError();
+ }
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
// Make sure that we capture 'this'.
@@ -7387,7 +7456,9 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
TypeSourceInfo *ScopeTypeInfo = 0;
if (E->getScopeTypeInfo()) {
- ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo());
+ CXXScopeSpec EmptySS;
+ ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
+ E->getScopeTypeInfo(), ObjectType, 0, EmptySS);
if (!ScopeTypeInfo)
return ExprError();
}
@@ -7524,11 +7595,11 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
bool ArgChanged = false;
- llvm::SmallVector<TypeSourceInfo *, 4> Args;
+ SmallVector<TypeSourceInfo *, 4> Args;
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
TypeSourceInfo *From = E->getArg(I);
TypeLoc FromTL = From->getTypeLoc();
- if (!isa<PackExpansionTypeLoc>(FromTL)) {
+ if (!FromTL.getAs<PackExpansionTypeLoc>()) {
TypeLocBuilder TLB;
TLB.reserve(FromTL.getFullDataSize());
QualType To = getDerived().TransformType(TLB, FromTL);
@@ -7547,7 +7618,7 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
ArgChanged = true;
// We have a pack expansion. Instantiate it.
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(FromTL);
+ PackExpansionTypeLoc ExpansionTL = FromTL.castAs<PackExpansionTypeLoc>();
TypeLoc PatternTL = ExpansionTL.getPatternLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(PatternTL, Unexpanded);
@@ -7556,9 +7627,9 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
- = ExpansionTL.getTypePtr()->getNumExpansions();
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
PatternTL.getSourceRange(),
Unexpanded,
@@ -7747,10 +7818,13 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
- // CXXConstructExprs are always implicit, so when we have a
- // 1-argument construction we just transform that argument.
- if (E->getNumArgs() == 1 ||
- (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1))))
+ // CXXConstructExprs other than for list-initialization and
+ // CXXTemporaryObjectExpr are always implicit, so when we have
+ // a 1-argument construction we just transform that argument.
+ if ((E->getNumArgs() == 1 ||
+ (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
+ (!getDerived().DropCallArgument(E->getArg(0))) &&
+ !E->isListInitialization())
return getDerived().TransformExpr(E->getArg(0));
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
@@ -7786,6 +7860,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
Constructor, E->isElidable(),
Args,
E->hadMultipleCandidates(),
+ E->isListInitialization(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
E->getParenRange());
@@ -7843,6 +7918,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return SemaRef.MaybeBindToTemporary(E);
}
+ // FIXME: Pass in E->isListInitialization().
return getDerived().RebuildCXXTemporaryObjectExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
Args,
@@ -7867,8 +7943,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
// Transform lambda parameters.
- llvm::SmallVector<QualType, 4> ParamTypes;
- llvm::SmallVector<ParmVarDecl *, 4> Params;
+ SmallVector<QualType, 4> ParamTypes;
+ SmallVector<ParmVarDecl *, 4> Params;
if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
E->getCallOperator()->param_begin(),
E->getCallOperator()->param_size(),
@@ -7931,7 +8007,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
C->getLocation(),
Unexpanded,
@@ -8274,7 +8350,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
Unexpanded,
ShouldExpand, RetainExpansion,
@@ -8360,7 +8436,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCArrayLiteral(ObjCArrayLiteral *E) {
// Transform each of the elements.
- llvm::SmallVector<Expr *, 8> Elements;
+ SmallVector<Expr *, 8> Elements;
bool ArgChanged = false;
if (getDerived().TransformExprs(E->getElements(), E->getNumElements(),
/*IsCall=*/false, Elements, &ArgChanged))
@@ -8379,7 +8455,7 @@ ExprResult
TreeTransform<Derived>::TransformObjCDictionaryLiteral(
ObjCDictionaryLiteral *E) {
// Transform each of the elements.
- llvm::SmallVector<ObjCDictionaryElement, 8> Elements;
+ SmallVector<ObjCDictionaryElement, 8> Elements;
bool ArgChanged = false;
for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
ObjCDictionaryElement OrigElement = E->getKeyValueElement(I);
@@ -8395,8 +8471,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
// and should be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
SourceRange PatternRange(OrigElement.Key->getLocStart(),
OrigElement.Value->getLocEnd());
if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
@@ -8483,7 +8559,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
ArgChanged = true;
ObjCDictionaryElement Element = {
- Key.get(), Value.get(), SourceLocation(), llvm::Optional<unsigned>()
+ Key.get(), Value.get(), SourceLocation(), None
};
Elements.push_back(Element);
}
@@ -8712,6 +8788,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
return SemaRef.Owned(E);
return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(),
+ E->getOpLoc(),
E->isArrow());
}
@@ -8758,7 +8835,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- const FunctionType *exprFunctionType = E->getFunctionType();
+ const FunctionProtoType *exprFunctionType = E->getFunctionType();
QualType exprResultType =
getDerived().TransformType(exprFunctionType->getResultType());
@@ -8771,13 +8848,9 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- QualType functionType = getDerived().RebuildFunctionProtoType(
- exprResultType,
- paramTypes.data(),
- paramTypes.size(),
- oldBlock->isVariadic(),
- false, 0, RQ_None,
- exprFunctionType->getExtInfo());
+ QualType functionType =
+ getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
+ exprFunctionType->getExtProtoInfo());
blockScope->FunctionType = functionType;
// Set the parameters on the block decl.
@@ -8993,19 +9066,14 @@ TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
}
template<typename Derived>
-QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic,
- bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info) {
- return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- HasTrailingReturn, Quals, RefQualifier,
+QualType TreeTransform<Derived>::RebuildFunctionProtoType(
+ QualType T,
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI) {
+ return SemaRef.BuildFunctionType(T, ParamTypes,
getDerived().getBaseLocation(),
getDerived().getBaseEntity(),
- Info);
+ EPI);
}
template<typename Derived>
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 7a5e43e25dc9..f36ec9f3e209 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -15,8 +15,8 @@
#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
-#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/TypeLoc.h"
namespace clang {
@@ -75,7 +75,7 @@ class TypeLocBuilder {
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
- return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
+ return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
}
/// Resets this builder to the newly-initialized state.
@@ -97,8 +97,8 @@ 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) {
- size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
- return cast<TyLocType>(pushImpl(T, LocalSize));
+ size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
+ return pushImpl(T, LocalSize).castAs<TyLocType>();
}
/// Creates a TypeSourceInfo for the given type.
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 0ec03cfe1e68..7bbe6b18f91a 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -12,8 +12,9 @@
//===----------------------------------------------------------------------===//
#include "ASTCommon.h"
-#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -60,6 +61,14 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
+ case BuiltinType::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break;
+ case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break;
+ case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break;
+ case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break;
+ case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break;
+ case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break;
+ case BuiltinType::OCLSampler: ID = PREDEF_TYPE_SAMPLER_ID; break;
+ case BuiltinType::OCLEvent: ID = PREDEF_TYPE_EVENT_ID; break;
case BuiltinType::BuiltinFn:
ID = PREDEF_TYPE_BUILTIN_FN; break;
@@ -78,3 +87,126 @@ unsigned serialization::ComputeHash(Selector Sel) {
R = llvm::HashString(II->getName(), R);
return R;
}
+
+const DeclContext *
+serialization::getDefinitiveDeclContext(const DeclContext *DC) {
+ switch (DC->getDeclKind()) {
+ // These entities may have multiple definitions.
+ case Decl::TranslationUnit:
+ case Decl::Namespace:
+ case Decl::LinkageSpec:
+ return 0;
+
+ // 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;
+
+ // 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;
+
+ // Each function, method, and block declaration is its own DeclContext.
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::ObjCMethod:
+ case Decl::Block:
+ // Objective C categories, category implementations, and class
+ // implementations can only be defined in one place.
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ return DC;
+
+ case Decl::ObjCProtocol:
+ if (const ObjCProtocolDecl *Def
+ = cast<ObjCProtocolDecl>(DC)->getDefinition())
+ return Def;
+ return 0;
+
+ // 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;
+
+ default:
+ llvm_unreachable("Unhandled DeclContext in AST reader");
+ }
+
+ llvm_unreachable("Unhandled decl kind");
+}
+
+bool serialization::isRedeclarableDeclKind(unsigned Kind) {
+ switch (static_cast<Decl::Kind>(Kind)) {
+ case Decl::TranslationUnit: // Special case of a "merged" declaration.
+ case Decl::Namespace:
+ case Decl::NamespaceAlias: // FIXME: Not yet redeclarable, but will be.
+ case Decl::Typedef:
+ case Decl::TypeAlias:
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::Var:
+ case Decl::FunctionTemplate:
+ case Decl::ClassTemplate:
+ case Decl::TypeAliasTemplate:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCInterface:
+ case Decl::Empty:
+ return true;
+
+ // Never redeclarable.
+ case Decl::UsingDirective:
+ case Decl::Label:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::TemplateTypeParm:
+ case Decl::EnumConstant:
+ case Decl::UnresolvedUsingValue:
+ case Decl::IndirectField:
+ case Decl::Field:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ case Decl::NonTypeTemplateParm:
+ case Decl::TemplateTemplateParm:
+ case Decl::Using:
+ case Decl::UsingShadow:
+ case Decl::ObjCMethod:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCProperty:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::FileScopeAsm:
+ case Decl::AccessSpec:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::StaticAssert:
+ case Decl::Block:
+ case Decl::ClassScopeFunctionSpecialization:
+ case Decl::Import:
+ case Decl::OMPThreadPrivate:
+ return false;
+ }
+
+ llvm_unreachable("Unhandled declaration kind");
+}
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index eacb39d86ea4..76ef9040461c 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
#define LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
-#include "clang/Serialization/ASTBitCodes.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Serialization/ASTBitCodes.h"
namespace clang {
@@ -58,6 +58,21 @@ TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) {
unsigned ComputeHash(Selector Sel);
+/// \brief Retrieve the "definitive" declaration that provides all of the
+/// visible entries for the given declaration context, if there is one.
+///
+/// The "definitive" declaration is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive declarations
+/// associated with them. C++ namespaces, on the other hand, can have
+/// multiple definitions.
+const DeclContext *getDefinitiveDeclContext(const DeclContext *DC);
+
+/// \brief Determine whether the given declaration kind is redeclarable.
+bool isRedeclarableDeclKind(unsigned Kind);
+
} // namespace serialization
} // namespace clang
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index deba302e2138..d9844152b740 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1,4 +1,4 @@
-//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===//
+//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,13 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTDeserializationListener.h"
-#include "clang/Serialization/ModuleManager.h"
-#include "clang/Serialization/SerializationDiagnostic.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/Scope.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
@@ -27,37 +22,42 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/SerializationDiagnostic.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
-#include <iterator>
#include <cstdio>
-#include <sys/stat.h>
+#include <iterator>
using namespace clang;
using namespace clang::serialization;
using namespace clang::serialization::reader;
+using llvm::BitstreamCursor;
//===----------------------------------------------------------------------===//
// PCH validator implementation
@@ -109,6 +109,14 @@ static bool checkLanguageOptions(const LangOptions &LangOpts,
return true;
}
+ if (ExistingLangOpts.CommentOpts.BlockCommandNames !=
+ LangOpts.CommentOpts.BlockCommandNames) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
+ << "block command names";
+ return true;
+ }
+
return false;
}
@@ -440,22 +448,32 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
return Result;
}
-unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) {
- return llvm::HashString(StringRef(a.first, a.second));
+unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(a);
}
std::pair<unsigned, unsigned>
-ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) {
using namespace clang::io;
unsigned DataLen = ReadUnalignedLE16(d);
unsigned KeyLen = ReadUnalignedLE16(d);
return std::make_pair(KeyLen, DataLen);
}
-std::pair<const char*, unsigned>
-ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) {
+ASTIdentifierLookupTraitBase::internal_key_type
+ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
assert(n >= 2 && d[n-1] == '\0');
- return std::make_pair((const char*) d, n-1);
+ return StringRef((const char*) d, n-1);
+}
+
+/// \brief Whether the given identifier is "interesting".
+static bool isInterestingIdentifier(IdentifierInfo &II) {
+ return II.isPoisoned() ||
+ II.isExtensionToken() ||
+ II.getObjCOrBuiltinID() ||
+ II.hasRevertedTokenIDToIdentifier() ||
+ II.hadMacroDefinition() ||
+ II.getFETokenInfo<void>();
}
IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
@@ -474,12 +492,17 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// and associate it with the persistent ID.
IdentifierInfo *II = KnownII;
if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ II = &Reader.getIdentifierTable().getOwn(k);
KnownII = II;
}
Reader.SetIdentifierInfo(ID, II);
- II->setIsFromAST();
- Reader.markIdentifierUpToDate(II);
+ if (!II->isFromAST()) {
+ bool WasInteresting = isInterestingIdentifier(*II);
+ II->setIsFromAST();
+ if (WasInteresting)
+ II->setChangedSinceDeserialization();
+ }
+ Reader.markIdentifierUpToDate(II);
return II;
}
@@ -493,6 +516,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
Bits >>= 1;
bool ExtensionToken = Bits & 0x01;
Bits >>= 1;
+ bool hasSubmoduleMacros = Bits & 0x01;
+ Bits >>= 1;
bool hadMacroDefinition = Bits & 0x01;
Bits >>= 1;
@@ -503,15 +528,20 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// the new IdentifierInfo.
IdentifierInfo *II = KnownII;
if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k));
KnownII = II;
}
Reader.markIdentifierUpToDate(II);
- II->setIsFromAST();
+ if (!II->isFromAST()) {
+ bool WasInteresting = isInterestingIdentifier(*II);
+ II->setIsFromAST();
+ if (WasInteresting)
+ II->setChangedSinceDeserialization();
+ }
// Set or check the various bits in the IdentifierInfo structure.
// Token IDs are read-only.
- if (HasRevertedTokenIDToIdentifier)
+ if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier)
II->RevertTokenIDToIdentifier();
II->setObjCOrBuiltinID(ObjCOrBuiltinID);
assert(II->isExtensionToken() == ExtensionToken &&
@@ -526,13 +556,26 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// If this identifier is a macro, deserialize the macro
// definition.
if (hadMacroDefinition) {
- SmallVector<MacroID, 4> MacroIDs;
- while (uint32_t LocalID = ReadUnalignedLE32(d)) {
- MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID));
+ uint32_t MacroDirectivesOffset = ReadUnalignedLE32(d);
+ DataLen -= 4;
+ SmallVector<uint32_t, 8> LocalMacroIDs;
+ if (hasSubmoduleMacros) {
+ while (uint32_t LocalMacroID = ReadUnalignedLE32(d)) {
+ DataLen -= 4;
+ LocalMacroIDs.push_back(LocalMacroID);
+ }
DataLen -= 4;
}
- DataLen -= 4;
- Reader.setIdentifierIsMacro(II, MacroIDs);
+
+ if (F.Kind == MK_Module) {
+ 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);
+ }
+ } else {
+ Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset);
+ }
}
Reader.SetIdentifierInfo(ID, II);
@@ -656,12 +699,13 @@ ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
unsigned DataLen) {
using namespace clang::io;
unsigned NumDecls = ReadUnalignedLE16(d);
- LE32DeclID *Start = (LE32DeclID *)d;
+ LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
+ const_cast<unsigned char *>(d));
return std::make_pair(Start, Start + NumDecls);
}
bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
- llvm::BitstreamCursor &Cursor,
+ BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
DeclContextInfo &Info) {
SavedStreamPosition SavedPosition(Cursor);
@@ -670,17 +714,16 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
Cursor.JumpToBit(Offsets.first);
RecordData Record;
- const char *Blob;
- unsigned BlobLen;
+ StringRef Blob;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
if (RecCode != DECL_CONTEXT_LEXICAL) {
Error("Expected lexical block");
return true;
}
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
- Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data());
+ Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair);
}
// Now the lookup table.
@@ -688,18 +731,17 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
Cursor.JumpToBit(Offsets.second);
RecordData Record;
- const char *Blob;
- unsigned BlobLen;
+ StringRef Blob;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
if (RecCode != DECL_CONTEXT_VISIBLE) {
Error("Expected visible lookup table block");
return true;
}
Info.NameLookupTableData
= ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob + Record[0],
- (const unsigned char *)Blob,
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data(),
ASTDeclContextNameLookupTrait(*this, M));
}
@@ -773,7 +815,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
- llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
+ BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
// Set the source-location entry cursor to the current position in
// the stream. This cursor will be used to read the contents of the
@@ -795,35 +837,24 @@ bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
RecordData Record;
while (true) {
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (SLocEntryCursor.ReadBlockEnd()) {
- Error("error at end of Source Manager block in AST file");
- return true;
- }
+ llvm::BitstreamEntry E = SLocEntryCursor.advanceSkippingSubblocks();
+
+ switch (E.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return true;
+ case llvm::BitstreamEntry::EndBlock:
return false;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- SLocEntryCursor.ReadSubBlockID();
- if (SLocEntryCursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- SLocEntryCursor.ReadAbbrevRecord();
- continue;
- }
-
+
// Read a record.
- const char *BlobStart;
- unsigned BlobLen;
Record.clear();
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
@@ -880,22 +911,19 @@ bool ASTReader::ReadSLocEntry(int ID) {
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
- llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+ BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
unsigned BaseOffset = F->SLocEntryBaseOffset;
++NumSLocEntriesRead;
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
+ llvm::BitstreamEntry Entry = SLocEntryCursor.advance();
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
Error("incorrectly-formatted source location entry in AST file");
return true;
}
-
+
RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) {
default:
Error("incorrectly-formatted source location entry in AST file");
return true;
@@ -905,10 +933,13 @@ bool ASTReader::ReadSLocEntry(int ID) {
// we will also try to fail gracefully by setting up the SLocEntry.
unsigned InputID = Record[4];
InputFile IF = getInputFile(*F, InputID);
- const FileEntry *File = IF.getPointer();
- bool OverriddenBuffer = IF.getInt();
+ const FileEntry *File = IF.getFile();
+ bool OverriddenBuffer = IF.isOverridden();
- if (!IF.getPointer())
+ // Note that we only check if a File was returned. If it was out-of-date
+ // we have complained but we will continue creating a FileID to recover
+ // gracefully.
+ if (!File)
return true;
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
@@ -941,8 +972,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
ContentCache->ContentsEntry == ContentCache->OrigEntry) {
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
- unsigned RecCode
- = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
@@ -950,8 +980,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- File->getName());
+ = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName());
SourceMgr.overrideFileContents(File, Buffer);
}
@@ -959,15 +988,18 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
case SM_SLOC_BUFFER_ENTRY: {
- const char *Name = BlobStart;
+ const char *Name = Blob.data();
unsigned Offset = Record[0];
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
+ IncludeLoc = getImportLocation(F);
+ }
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode
- = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ = SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
@@ -975,8 +1007,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Name);
+ = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
BaseOffset + Offset, IncludeLoc);
break;
@@ -997,6 +1028,25 @@ bool ASTReader::ReadSLocEntry(int ID) {
return false;
}
+std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
+ if (ID == 0)
+ return std::make_pair(SourceLocation(), "");
+
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
+ Error("source location entry ID out-of-range for AST file");
+ return std::make_pair(SourceLocation(), "");
+ }
+
+ // Find which module file this entry lands in.
+ ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
+ if (M->Kind != MK_Module)
+ return std::make_pair(SourceLocation(), "");
+
+ // 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));
+}
+
/// \brief Find the location where the module F is imported.
SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
if (F->ImportLoc.isValid())
@@ -1019,8 +1069,7 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
/// specified cursor. Read the abbreviations that are at the top of the block
/// and then leave the cursor pointing into the block.
-bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
- unsigned BlockID) {
+bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
if (Cursor.EnterSubBlock(BlockID)) {
Error("malformed block record in AST file");
return Failure;
@@ -1039,9 +1088,8 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
}
-void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
- MacroInfo *Hint) {
- llvm::BitstreamCursor &Stream = F.MacroCursor;
+MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
+ BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this macro.
@@ -1052,95 +1100,53 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
SmallVector<IdentifierInfo*, 16> MacroArgs;
MacroInfo *Macro = 0;
- // RAII object to add the loaded macro information once we're done
- // adding tokens.
- struct AddLoadedMacroInfoRAII {
- Preprocessor &PP;
- MacroInfo *Hint;
- MacroInfo *MI;
- IdentifierInfo *II;
-
- AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint)
- : PP(PP), Hint(Hint), MI(), II() { }
- ~AddLoadedMacroInfoRAII( ) {
- if (MI) {
- // Finally, install the macro.
- PP.addLoadedMacroInfo(II, MI, Hint);
- }
- }
- } AddLoadedMacroInfo(PP, Hint);
-
while (true) {
- unsigned Code = Stream.ReadCode();
- switch (Code) {
- case llvm::bitc::END_BLOCK:
- return;
-
- case llvm::bitc::ENTER_SUBBLOCK:
- // No known subblocks, always skip them.
- Stream.ReadSubBlockID();
- if (Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
-
- case llvm::bitc::DEFINE_ABBREV:
- Stream.ReadAbbrevRecord();
- continue;
- default: break;
+ // Advance to the next record, but if we get to the end of the block, don't
+ // pop it (removing all the abbreviations from the cursor) since we want to
+ // be able to reseek within the block and read entries.
+ unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd;
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(Flags);
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return Macro;
+ case llvm::BitstreamEntry::EndBlock:
+ return Macro;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
// Read a record.
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
Record.clear();
PreprocessorRecordTypes RecType =
- (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart,
- BlobLen);
+ (PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record);
switch (RecType) {
+ case PP_MACRO_DIRECTIVE_HISTORY:
+ return Macro;
+
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE: {
// If we already have a macro, that means that we've hit the end
// of the definition of the macro we were looking for. We're
// done.
if (Macro)
- return;
+ return Macro;
- IdentifierInfo *II = getLocalIdentifier(F, Record[0]);
- if (II == 0) {
- Error("macro must have a name in AST file");
- return;
- }
-
- unsigned GlobalID = getGlobalMacroID(F, Record[1]);
-
- // If this macro has already been loaded, don't do so again.
- if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS])
- return;
-
- SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]);
- unsigned NextIndex = 3;
+ unsigned NextIndex = 1; // Skip identifier ID.
+ SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
- MacroInfo *MI = PP.AllocateMacroInfo(Loc);
-
- // Record this macro.
- MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI;
-
- SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex);
- if (UndefLoc.isValid())
- MI->setUndefLoc(UndefLoc);
-
+ MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
+ MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
- MI->setIsFromAST();
-
- bool IsPublic = Record[NextIndex++];
- MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex));
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
bool isC99VarArgs = Record[NextIndex++];
bool isGNUVarArgs = Record[NextIndex++];
+ bool hasCommaPasting = Record[NextIndex++];
MacroArgs.clear();
unsigned NumArgs = Record[NextIndex++];
for (unsigned i = 0; i != NumArgs; ++i)
@@ -1150,65 +1156,11 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
MI->setIsFunctionLike();
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
+ if (hasCommaPasting) MI->setHasCommaPasting();
MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
PP.getPreprocessorAllocator());
}
- if (DeserializationListener)
- DeserializationListener->MacroRead(GlobalID, MI);
-
- // If an update record marked this as undefined, do so now.
- // FIXME: Only if the submodule this update came from is visible?
- MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID);
- if (Update != MacroUpdates.end()) {
- if (MI->getUndefLoc().isInvalid()) {
- for (unsigned I = 0, N = Update->second.size(); I != N; ++I) {
- bool Hidden = false;
- if (unsigned SubmoduleID = Update->second[I].first) {
- if (Module *Owner = getSubmodule(SubmoduleID)) {
- if (Owner->NameVisibility == Module::Hidden) {
- // Note that this #undef is hidden.
- Hidden = true;
-
- // Record this hiding for later.
- HiddenNamesMap[Owner].push_back(
- HiddenName(II, MI, Update->second[I].second.UndefLoc));
- }
- }
- }
-
- if (!Hidden) {
- MI->setUndefLoc(Update->second[I].second.UndefLoc);
- if (PPMutationListener *Listener = PP.getPPMutationListener())
- Listener->UndefinedMacro(MI);
- break;
- }
- }
- }
- MacroUpdates.erase(Update);
- }
-
- // Determine whether this macro definition is visible.
- bool Hidden = !MI->isPublic();
- if (!Hidden && GlobalSubmoduleID) {
- if (Module *Owner = getSubmodule(GlobalSubmoduleID)) {
- 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, MI));
- }
- }
- }
- MI->setHidden(Hidden);
-
- // Make sure we install the macro once we're done.
- AddLoadedMacroInfo.MI = MI;
- AddLoadedMacroInfo.II = II;
-
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
Macro = MI;
@@ -1219,8 +1171,12 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
PreprocessedEntityID
GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]);
PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
- PPRec.RegisterMacroDefinition(Macro,
- PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true));
+ PreprocessingRecord::PPEntityID
+ PPID = PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true);
+ MacroDefinition *PPDef =
+ cast_or_null<MacroDefinition>(PPRec.getPreprocessedEntity(PPID));
+ if (PPDef)
+ PPRec.RegisterMacroDefinition(Macro, PPDef);
}
++NumMacrosRead;
@@ -1257,37 +1213,49 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const
return LocalID + I->second;
}
-unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
- return llvm::HashString(llvm::sys::path::filename(path));
+unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
+ return llvm::hash_combine(ikey.Size, ikey.ModTime);
}
HeaderFileInfoTrait::internal_key_type
-HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
+HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
+ internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
+ FE->getName() };
+ return ikey;
+}
-bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
- if (strcmp(a, b) == 0)
- return true;
-
- if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
+bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
+ if (a.Size != b.Size || a.ModTime != b.ModTime)
return false;
- // Determine whether the actual files are equivalent.
- bool Result = false;
- if (llvm::sys::fs::equivalent(a, b, Result))
- return false;
+ if (strcmp(a.Filename, b.Filename) == 0)
+ return true;
- return Result;
+ // Determine whether the actual files are equivalent.
+ FileManager &FileMgr = Reader.getFileManager();
+ const FileEntry *FEA = FileMgr.getFile(a.Filename);
+ const FileEntry *FEB = FileMgr.getFile(b.Filename);
+ return (FEA && FEA == FEB);
}
std::pair<unsigned, unsigned>
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
-
+
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
+ internal_key_type ikey;
+ ikey.Size = off_t(clang::io::ReadUnalignedLE64(d));
+ ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d));
+ ikey.Filename = (const char *)d;
+ return ikey;
+}
+
HeaderFileInfoTrait::data_type
-HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
+HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
unsigned DataLen) {
const unsigned char *End = d + DataLen;
using namespace clang::io;
@@ -1308,6 +1276,21 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
}
+ if (d != End) {
+ uint32_t LocalSMID = ReadUnalignedLE32(d);
+ if (LocalSMID) {
+ // This header is part of a module. Associate it with the module to enable
+ // implicit module import.
+ SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
+ Module *Mod = Reader.getSubmodule(GlobalSMID);
+ HFI.isModuleHeader = true;
+ FileManager &FileMgr = Reader.getFileManager();
+ ModuleMap &ModMap =
+ Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), /*Excluded=*/false);
+ }
+ }
+
assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
(void)End;
@@ -1316,10 +1299,19 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
return HFI;
}
-void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){
- II->setHadMacroDefinition(true);
+void ASTReader::addPendingMacroFromModule(IdentifierInfo *II,
+ ModuleFile *M,
+ GlobalMacroID GMacID,
+ SourceLocation ImportLoc) {
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
- PendingMacroIDs[II].append(IDs.begin(), IDs.end());
+ PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, ImportLoc));
+}
+
+void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II,
+ ModuleFile *M,
+ uint64_t MacroDirectivesOffset) {
+ assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
+ PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset));
}
void ASTReader::ReadDefinedMacros() {
@@ -1328,54 +1320,46 @@ void ASTReader::ReadDefinedMacros() {
for (ModuleReverseIterator I = ModuleMgr.rbegin(),
E = ModuleMgr.rend(); I != E; ++I) {
- llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
+ BitstreamCursor &MacroCursor = (*I)->MacroCursor;
// If there was no preprocessor block, skip this file.
if (!MacroCursor.getBitStreamReader())
continue;
- llvm::BitstreamCursor Cursor = MacroCursor;
+ BitstreamCursor Cursor = MacroCursor;
Cursor.JumpToBit((*I)->MacroStartOffset);
RecordData Record;
while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK)
- break;
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
+ llvm::BitstreamEntry E = Cursor.advanceSkippingSubblocks();
+
+ switch (E.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return;
+ case llvm::BitstreamEntry::EndBlock:
+ goto NextCursor;
+
+ case llvm::BitstreamEntry::Record:
+ Record.clear();
+ switch (Cursor.readRecord(E.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case PP_MACRO_OBJECT_LIKE:
+ case PP_MACRO_FUNCTION_LIKE:
+ getLocalIdentifier(**I, Record[0]);
+ break;
+
+ case PP_TOKEN:
+ // Ignore tokens.
+ break;
}
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
- }
-
- // Read a record.
- const char *BlobStart;
- unsigned BlobLen;
- Record.clear();
- switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default: // Default behavior: ignore.
- break;
-
- case PP_MACRO_OBJECT_LIKE:
- case PP_MACRO_FUNCTION_LIKE:
- getLocalIdentifier(**I, Record[0]);
- break;
-
- case PP_TOKEN:
- // Ignore tokens.
break;
}
}
+ NextCursor: ;
}
}
@@ -1384,10 +1368,20 @@ namespace {
class IdentifierLookupVisitor {
StringRef Name;
unsigned PriorGeneration;
+ unsigned &NumIdentifierLookups;
+ unsigned &NumIdentifierLookupHits;
IdentifierInfo *Found;
+
public:
- IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
- : Name(Name), PriorGeneration(PriorGeneration), Found() { }
+ IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration,
+ unsigned &NumIdentifierLookups,
+ unsigned &NumIdentifierLookupHits)
+ : Name(Name), PriorGeneration(PriorGeneration),
+ NumIdentifierLookups(NumIdentifierLookups),
+ NumIdentifierLookupHits(NumIdentifierLookupHits),
+ Found()
+ {
+ }
static bool visit(ModuleFile &M, void *UserData) {
IdentifierLookupVisitor *This
@@ -1396,7 +1390,7 @@ namespace {
// If we've already searched this module file, skip it now.
if (M.Generation <= This->PriorGeneration)
return true;
-
+
ASTIdentifierLookupTable *IdTable
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
if (!IdTable)
@@ -1404,16 +1398,15 @@ namespace {
ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
M, This->Found);
-
- std::pair<const char*, unsigned> Key(This->Name.begin(),
- This->Name.size());
- ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait);
+ ++This->NumIdentifierLookups;
+ ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait);
if (Pos == IdTable->end())
return false;
// Dereferencing the iterator has the effect of building the
// IdentifierInfo node and populating it with the various
// declarations it needs.
+ ++This->NumIdentifierLookupHits;
This->Found = *Pos;
return true;
}
@@ -1431,9 +1424,21 @@ void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
unsigned PriorGeneration = 0;
if (getContext().getLangOpts().Modules)
PriorGeneration = IdentifierGeneration[&II];
-
- IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+
+ // 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;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+
+ IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration,
+ NumIdentifierLookups,
+ NumIdentifierLookupHits);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
markIdentifierUpToDate(&II);
}
@@ -1448,27 +1453,196 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
IdentifierGeneration[II] = CurrentGeneration;
}
-llvm::PointerIntPair<const FileEntry *, 1, bool>
-ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
+void ASTReader::resolvePendingMacro(IdentifierInfo *II,
+ const PendingMacroInfo &PMInfo) {
+ assert(II);
+
+ if (PMInfo.M->Kind != MK_Module) {
+ installPCHMacroDirectives(II, *PMInfo.M,
+ PMInfo.PCHMacroData.MacroDirectivesOffset);
+ return;
+ }
+
+ // Module Macro.
+
+ GlobalMacroID GMacID = PMInfo.ModuleMacroData.GMacID;
+ SourceLocation ImportLoc =
+ SourceLocation::getFromRawEncoding(PMInfo.ModuleMacroData.ImportLoc);
+
+ assert(GMacID);
+ // If this macro has already been loaded, don't do so again.
+ if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS])
+ 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));
+ }
+ }
+ }
+
+ if (!Hidden)
+ installImportedMacro(II, MD, Owner);
+}
+
+void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
+ ModuleFile &M, uint64_t Offset) {
+ assert(M.Kind != MK_Module);
+
+ BitstreamCursor &Cursor = M.MacroCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Offset);
+
+ llvm::BitstreamEntry Entry =
+ Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Error("malformed block record in AST file");
+ return;
+ }
+
+ RecordData Record;
+ PreprocessorRecordTypes RecType =
+ (PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record);
+ if (RecType != PP_MACRO_DIRECTIVE_HISTORY) {
+ Error("malformed block record in AST file");
+ return;
+ }
+
+ // Deserialize the macro directives history in reverse source-order.
+ MacroDirective *Latest = 0, *Earliest = 0;
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ MacroDirective *MD = 0;
+ SourceLocation Loc = ReadSourceLocation(M, Record, Idx);
+ MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++];
+ switch (K) {
+ case MacroDirective::MD_Define: {
+ GlobalMacroID GMacID = getGlobalMacroID(M, Record[Idx++]);
+ MacroInfo *MI = getMacro(GMacID);
+ bool isImported = Record[Idx++];
+ bool isAmbiguous = Record[Idx++];
+ DefMacroDirective *DefMD =
+ PP.AllocateDefMacroDirective(MI, Loc, isImported);
+ DefMD->setAmbiguous(isAmbiguous);
+ MD = DefMD;
+ break;
+ }
+ case MacroDirective::MD_Undefine:
+ MD = PP.AllocateUndefMacroDirective(Loc);
+ break;
+ case MacroDirective::MD_Visibility: {
+ bool isPublic = Record[Idx++];
+ MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic);
+ break;
+ }
+ }
+
+ if (!Latest)
+ Latest = MD;
+ if (Earliest)
+ Earliest->setPrevious(MD);
+ Earliest = MD;
+ }
+
+ PP.setLoadedMacroDirective(II, Latest);
+}
+
+/// \brief For the given macro definitions, check if they are both in system
+/// modules and if one of the two is in the clang builtin headers.
+static bool isSystemAndClangMacro(MacroInfo *PrevMI, MacroInfo *NewMI,
+ Module *NewOwner, ASTReader &Reader) {
+ assert(PrevMI && NewMI);
+ if (!NewOwner)
+ return false;
+ Module *PrevOwner = 0;
+ if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
+ PrevOwner = Reader.getSubmodule(PrevModID);
+ if (!PrevOwner)
+ return false;
+ if (PrevOwner == NewOwner)
+ return false;
+ if (!PrevOwner->IsSystem || !NewOwner->IsSystem)
+ return false;
+
+ SourceManager &SM = Reader.getSourceManager();
+ FileID PrevFID = SM.getFileID(PrevMI->getDefinitionLoc());
+ FileID NewFID = SM.getFileID(NewMI->getDefinitionLoc());
+ const FileEntry *PrevFE = SM.getFileEntryForID(PrevFID);
+ const FileEntry *NewFE = SM.getFileEntryForID(NewFID);
+ if (PrevFE == 0 || NewFE == 0)
+ return false;
+
+ Preprocessor &PP = Reader.getPreprocessor();
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ const DirectoryEntry *BuiltinDir = ModMap.getBuiltinIncludeDir();
+
+ return (PrevFE->getDir() == BuiltinDir) != (NewFE->getDir() == BuiltinDir);
+}
+
+void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD,
+ Module *Owner) {
+ assert(II && MD);
+
+ DefMacroDirective *DefMD = cast<DefMacroDirective>(MD);
+ 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
+ // the system macro uses a not identical definition compared to a macro
+ // from the clang headers. For example:
+ // #define LONG_MAX __LONG_MAX__ (clang's limits.h)
+ // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h)
+ // in which case don't mark them to avoid the "ambiguous macro expansion"
+ // warning.
+ // FIXME: This should go away if the system headers get "fixed" to use
+ // identical definitions.
+ if (!isSystemAndClangMacro(PrevMI, NewMI, Owner, *this)) {
+ PrevDef.getDirective()->setAmbiguous(true);
+ DefMD->setAmbiguous(true);
+ }
+ }
+ }
+
+ PP.appendMacroDirective(II, MD);
+}
+
+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())
return InputFile();
// If we've already loaded this input file, return it.
- if (F.InputFilesLoaded[ID-1].getPointer())
+ if (F.InputFilesLoaded[ID-1].getFile())
return F.InputFilesLoaded[ID-1];
// Go find this input file.
- llvm::BitstreamCursor &Cursor = F.InputFilesCursor;
+ BitstreamCursor &Cursor = F.InputFilesCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
unsigned Code = Cursor.ReadCode();
RecordData Record;
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
case INPUT_FILE: {
unsigned StoredID = Record[0];
assert(ID == StoredID && "Bogus stored ID or offset");
@@ -1478,7 +1652,7 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
bool Overridden = (bool)Record[3];
// Get the file entry for this input file.
- StringRef OrigFilename(BlobStart, BlobLen);
+ StringRef OrigFilename = Blob;
std::string Filename = OrigFilename;
MaybeAddSystemRootToFilename(F, Filename);
const FileEntry *File
@@ -1511,17 +1685,15 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
}
return InputFile();
}
-
- // Note that we've loaded this input file.
- F.InputFilesLoaded[ID-1] = InputFile(File, Overridden);
-
+
// 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)) {
- Error(diag::err_fe_pch_file_overridden, Filename);
+ 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);
@@ -1532,33 +1704,29 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
StoredSize, StoredTime);
}
- // For an overridden file, there is nothing to validate.
- if (Overridden)
- return InputFile(File, Overridden);
-
- // The stat info from the FileEntry came from the cached stat
- // info of the PCH, so we cannot trust it.
- struct stat StatBuf;
- if (::stat(File->getName(), &StatBuf) != 0) {
- StatBuf.st_size = File->getSize();
- StatBuf.st_mtime = File->getModificationTime();
- }
+ bool IsOutOfDate = false;
- if ((StoredSize != StatBuf.st_size
+ // 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 != StatBuf.st_mtime
+ || StoredTime != File->getModificationTime()
#endif
)) {
- if (Complain)
- Error(diag::err_fe_pch_file_modified, Filename);
-
- return InputFile();
+ if (Complain) {
+ Error(diag::err_fe_pch_file_modified, Filename, F.FileName);
+ }
+
+ IsOutOfDate = true;
}
- return InputFile(File, Overridden);
+ InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = IF;
+ return IF;
}
}
@@ -1609,9 +1777,9 @@ void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
- llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ SmallVectorImpl<ImportedModule> &Loaded,
unsigned ClientLoadCapabilities) {
- llvm::BitstreamCursor &Stream = F.Stream;
+ BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error("malformed block record in AST file");
@@ -1620,27 +1788,29 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// Read all of the records and blocks in the control block.
RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Error("error at end of control block in AST file");
- return Failure;
- }
-
- // Validate all of the input files.
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ 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) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
- for (unsigned I = 0, N = Record[0]; I < N; ++I)
- if (!getInputFile(F, I+1, Complain).getPointer())
+ // 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) {
+ InputFile IF = getInputFile(F, I+1, Complain);
+ if (!IF.getFile() || IF.isOutOfDate())
return OutOfDate;
+ }
}
-
return Success;
- }
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- switch (Stream.ReadSubBlockID()) {
+
+ case llvm::BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
case INPUT_FILES_BLOCK_ID:
F.InputFilesCursor = Stream;
if (Stream.SkipBlock() || // Skip with the main cursor
@@ -1650,28 +1820,24 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return Failure;
}
continue;
-
+
default:
- if (!Stream.SkipBlock())
- continue;
- break;
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
}
-
- Error("malformed block record in AST file");
- return Failure;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
// Read and process a record.
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
case METADATA: {
if (Record[0] != VERSION_MAJOR && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
@@ -1689,7 +1855,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.RelocatablePCH = Record[4];
const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
+ StringRef ASTBranch = Blob;
if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
@@ -1704,16 +1870,25 @@ ASTReader::ReadControlBlock(ModuleFile &F,
while (Idx < N) {
// Read information about the AST file.
ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
+ // The import location will be the local one for now; we will adjust
+ // all import locations of module imports after the global source
+ // location info are setup.
+ SourceLocation ImportLoc =
+ SourceLocation::getFromRawEncoding(Record[Idx++]);
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)Record[Idx++];
unsigned Length = Record[Idx++];
SmallString<128> ImportedFile(Record.begin() + Idx,
Record.begin() + Idx + Length);
Idx += Length;
// Load the AST file.
- switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded,
+ switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
+ StoredSize, StoredModTime,
ClientLoadCapabilities)) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
+ case Missing:
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
@@ -1781,28 +1956,29 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case ORIGINAL_FILE:
F.OriginalSourceFileID = FileID::get(Record[0]);
- F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen);
+ F.ActualOriginalSourceFileName = Blob;
F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
break;
+ case ORIGINAL_FILE_ID:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ break;
+
case ORIGINAL_PCH_DIR:
- F.OriginalDir.assign(BlobStart, BlobLen);
+ F.OriginalDir = Blob;
break;
case INPUT_FILE_OFFSETS:
- F.InputFileOffsets = (const uint32_t *)BlobStart;
+ F.InputFileOffsets = (const uint32_t *)Blob.data();
F.InputFilesLoaded.resize(Record[0]);
break;
}
}
-
- Error("premature end of bitstream in AST file");
- return Failure;
}
bool ASTReader::ReadASTBlock(ModuleFile &F) {
- llvm::BitstreamCursor &Stream = F.Stream;
+ BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
Error("malformed block record in AST file");
@@ -1811,23 +1987,28 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// Read all of the records and blocks for the AST file.
RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Error("error at end of module block in AST file");
- return true;
- }
-
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Error("error at end of module block in AST file");
+ return true;
+ 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
+ // contains any declarations lexically within it (which it always does!).
+ // This usually has no cost, since we very rarely need the lookup map for
+ // the translation unit outside C++.
DeclContext *DC = Context.getTranslationUnitDecl();
- if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ if (DC->hasExternalLexicalStorage() &&
+ !getContext().getLangOpts().CPlusPlus)
DC->setMustBuildLookupTable();
-
+
return false;
}
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- switch (Stream.ReadSubBlockID()) {
+ case llvm::BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
case DECLTYPES_BLOCK_ID:
// We lazily load the decls block, but we want to set up the
// DeclsCursor cursor to point into it. Clone our current bitcode
@@ -1841,19 +2022,19 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
return true;
}
break;
-
+
case DECL_UPDATES_BLOCK_ID:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
return true;
}
break;
-
+
case PREPROCESSOR_BLOCK_ID:
F.MacroCursor = Stream;
if (!PP.getExternalSource())
PP.setExternalSource(this);
-
+
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
@@ -1861,20 +2042,20 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
-
+
case PREPROCESSOR_DETAIL_BLOCK_ID:
F.PreprocessorDetailCursor = Stream;
if (Stream.SkipBlock() ||
- ReadBlockAbbrevs(F.PreprocessorDetailCursor,
+ ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID)) {
- Error("malformed preprocessor detail record in AST file");
- return true;
- }
+ Error("malformed preprocessor detail record in AST file");
+ return true;
+ }
F.PreprocessorDetailStartOffset
- = F.PreprocessorDetailCursor.GetCurrentBitNo();
-
+ = F.PreprocessorDetailCursor.GetCurrentBitNo();
+
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
+ PP.createPreprocessingRecord();
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
break;
@@ -1883,14 +2064,14 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (ReadSourceManagerBlock(F))
return true;
break;
-
+
case SUBMODULE_BLOCK_ID:
if (ReadSubmoduleBlock(F))
return true;
break;
-
+
case COMMENTS_BLOCK_ID: {
- llvm::BitstreamCursor C = Stream;
+ BitstreamCursor C = Stream;
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
Error("malformed comments block in AST file");
@@ -1899,27 +2080,25 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
CommentsCursors.push_back(std::make_pair(C, &F));
break;
}
-
+
default:
- if (!Stream.SkipBlock())
- break;
- Error("malformed block record in AST file");
- return true;
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ break;
}
continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
// Read and process a record.
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
@@ -1928,7 +2107,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate TYPE_OFFSET record in AST file");
return true;
}
- F.TypeOffsets = (const uint32_t *)BlobStart;
+ F.TypeOffsets = (const uint32_t *)Blob.data();
F.LocalNumTypes = Record[0];
unsigned LocalBaseTypeIndex = Record[1];
F.BaseTypeIndex = getTotalNumTypes();
@@ -1952,7 +2131,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate DECL_OFFSET record in AST file");
return true;
}
- F.DeclOffsets = (const DeclOffset *)BlobStart;
+ F.DeclOffsets = (const DeclOffset *)Blob.data();
F.LocalNumDecls = Record[0];
unsigned LocalBaseDeclID = Record[1];
F.BaseDeclID = getTotalNumDecls();
@@ -1980,9 +2159,9 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case TU_UPDATE_LEXICAL: {
DeclContext *TU = Context.getTranslationUnitDecl();
DeclContextInfo &Info = F.DeclContextInfos[TU];
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart);
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data());
Info.NumLexicalDecls
- = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair));
+ = static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair));
TU->setHasExternalLexicalStorage(true);
break;
}
@@ -1992,8 +2171,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
ASTDeclContextNameLookupTable *Table =
ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)BlobStart + Record[Idx++],
- (const unsigned char *)BlobStart,
+ (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();
@@ -2005,7 +2184,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
case IDENTIFIER_TABLE:
- F.IdentifierTableData = BlobStart;
+ F.IdentifierTableData = Blob.data();
if (Record[0]) {
F.IdentifierLookupTable
= ASTIdentifierLookupTable::Create(
@@ -2022,7 +2201,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
return true;
}
- F.IdentifierOffsets = (const uint32_t *)BlobStart;
+ F.IdentifierOffsets = (const uint32_t *)Blob.data();
F.LocalNumIdentifiers = Record[0];
unsigned LocalBaseIdentifierID = Record[1];
F.BaseIdentifierID = getTotalNumIdentifiers();
@@ -2051,8 +2230,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case SPECIAL_TYPES:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
+ if (SpecialTypes.empty()) {
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
+ break;
+ }
+
+ if (SpecialTypes.size() != Record.size()) {
+ Error("invalid special-types record");
+ return true;
+ }
+
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ serialization::TypeID ID = getGlobalTypeID(F, Record[I]);
+ if (!SpecialTypes[I])
+ SpecialTypes[I] = ID;
+ // FIXME: If ID && SpecialTypes[I] != ID, do we need a separate
+ // merge step?
+ }
break;
case STATISTICS:
@@ -2094,13 +2289,13 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
break;
- case LOCALLY_SCOPED_EXTERNAL_DECLS:
+ case LOCALLY_SCOPED_EXTERN_C_DECLS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
- LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I]));
+ LocallyScopedExternCDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
case SELECTOR_OFFSETS: {
- F.SelectorOffsets = (const uint32_t *)BlobStart;
+ F.SelectorOffsets = (const uint32_t *)Blob.data();
F.LocalNumSelectors = Record[0];
unsigned LocalBaseSelectorID = Record[1];
F.BaseSelectorID = getTotalNumSelectors();
@@ -2122,7 +2317,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
case METHOD_POOL:
- F.SelectorLookupTableData = (const unsigned char *)BlobStart;
+ F.SelectorLookupTableData = (const unsigned char *)Blob.data();
if (Record[0])
F.SelectorLookupTable
= ASTSelectorLookupTable::Create(
@@ -2149,12 +2344,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case FILE_SORTED_DECLS:
- F.FileSortedDecls = (const DeclID *)BlobStart;
+ F.FileSortedDecls = (const DeclID *)Blob.data();
F.NumFileSortedDecls = Record[0];
break;
case SOURCE_LOCATION_OFFSETS: {
- F.SLocEntryOffsets = (const uint32_t *)BlobStart;
+ F.SLocEntryOffsets = (const uint32_t *)Blob.data();
F.LocalNumSLocEntries = Record[0];
unsigned SLocSpaceSize = Record[1];
llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
@@ -2187,8 +2382,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case MODULE_OFFSET_MAP: {
// Additional remapping information.
- const unsigned char *Data = (const unsigned char*)BlobStart;
- const unsigned char *DataEnd = Data + BlobLen;
+ const unsigned char *Data = (const unsigned char*)Blob.data();
+ const unsigned char *DataEnd = Data + Blob.size();
// Continuous range maps we may be updating in our module.
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
@@ -2324,15 +2519,15 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case PPD_ENTITIES_OFFSETS: {
- F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart;
- assert(BlobLen % sizeof(PPEntityOffset) == 0);
- F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset);
+ F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data();
+ assert(Blob.size() % sizeof(PPEntityOffset) == 0);
+ F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset);
unsigned LocalBasePreprocessedEntityID = Record[0];
unsigned StartingID;
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
+ PP.createPreprocessingRecord();
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
StartingID
@@ -2384,7 +2579,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.LocalNumObjCCategoriesInMap = Record[0];
- F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart;
+ F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data();
break;
}
@@ -2399,7 +2594,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.LocalNumCXXBaseSpecifiers = Record[0];
- F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart;
+ F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data();
NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
break;
}
@@ -2421,9 +2616,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case HEADER_SEARCH_TABLE: {
- F.HeaderFileInfoTableData = BlobStart;
+ F.HeaderFileInfoTableData = Blob.data();
F.LocalNumHeaderFileInfos = Record[1];
- F.HeaderFileFrameworkStrings = BlobStart + Record[2];
if (Record[0]) {
F.HeaderFileInfoTable
= HeaderFileInfoLookupTable::Create(
@@ -2431,7 +2625,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
(const unsigned char *)F.HeaderFileInfoTableData,
HeaderFileInfoTrait(*this, F,
&PP.getHeaderSearchInfo(),
- BlobStart + Record[2]));
+ Blob.data() + Record[2]));
PP.getHeaderSearchInfo().SetExternalSource(this);
if (!PP.getHeaderSearchInfo().getExternalLookup())
@@ -2459,7 +2653,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
for (unsigned I = 0, N = Record.size(); I != N; ++I)
KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
break;
-
+
+ case UNDEFINED_BUT_USED:
+ if (UndefinedButUsed.size() % 2 != 0) {
+ Error("Invalid existing UndefinedButUsed");
+ return true;
+ }
+
+ if (Record.size() % 2 != 0) {
+ Error("invalid undefined-but-used record");
+ return true;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
+ UndefinedButUsed.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ }
+ break;
+
case IMPORTED_MODULES: {
if (F.Kind != MK_Module) {
// If we aren't loading a module (which has its own exports), make
@@ -2485,7 +2696,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.LocalNumRedeclarationsInMap = Record[0];
- F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data();
break;
}
@@ -2504,7 +2715,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate MACRO_OFFSET record in AST file");
return true;
}
- F.MacroOffsets = (const uint32_t *)BlobStart;
+ F.MacroOffsets = (const uint32_t *)Blob.data();
F.LocalNumMacros = Record[0];
unsigned LocalBaseMacroID = Record[1];
F.BaseMacroID = getTotalNumMacros();
@@ -2523,60 +2734,73 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
}
- case MACRO_UPDATES: {
- for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
- MacroID ID = getGlobalMacroID(F, Record[I++]);
- if (I == N)
- break;
-
- SourceLocation UndefLoc = ReadSourceLocation(F, Record, I);
- SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);;
- MacroUpdate Update;
- Update.UndefLoc = UndefLoc;
- MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update));
- }
+ case MACRO_TABLE: {
+ // FIXME: Not used yet.
break;
}
}
}
- Error("premature end of bitstream in AST file");
- return true;
}
-void ASTReader::makeNamesVisible(const HiddenNames &Names) {
- for (unsigned I = 0, N = Names.size(); I != N; ++I) {
- switch (Names[I].getKind()) {
- case HiddenName::Declaration:
- Names[I].getDecl()->Hidden = false;
- break;
+/// \brief Move the given method to the back of the global list of methods.
+static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
+ // Find the entry for this selector in the method pool.
+ Sema::GlobalMethodPool::iterator Known
+ = S.MethodPool.find(Method->getSelector());
+ if (Known == S.MethodPool.end())
+ return;
- case HiddenName::MacroVisibility: {
- std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
- Macro.second->setHidden(!Macro.second->isPublic());
- if (Macro.second->isDefined()) {
- PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ // Retrieve the appropriate method list.
+ ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first
+ : Known->second.second;
+ bool Found = false;
+ for (ObjCMethodList *List = &Start; List; List = List->Next) {
+ if (!Found) {
+ if (List->Method == Method) {
+ Found = true;
+ } else {
+ // Keep searching.
+ continue;
}
- break;
}
- case HiddenName::MacroUndef: {
- std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
- if (Macro.second->isDefined()) {
- Macro.second->setUndefLoc(Names[I].getMacroUndefLoc());
- if (PPMutationListener *Listener = PP.getPPMutationListener())
- Listener->UndefinedMacro(Macro.second);
- PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ if (List->Next)
+ List->Method = List->Next->Method;
+ else
+ List->Method = 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;
+
+ 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;
+ }
}
}
}
void ASTReader::makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind NameVisibility) {
+ Module::NameVisibilityKind NameVisibility,
+ SourceLocation ImportLoc,
+ bool Complain) {
llvm::SmallPtrSet<Module *, 4> Visited;
- llvm::SmallVector<Module *, 4> Stack;
+ SmallVector<Module *, 4> Stack;
Stack.push_back(Mod);
while (!Stack.empty()) {
Mod = Stack.back();
@@ -2600,7 +2824,7 @@ void ASTReader::makeModuleVisible(Module *Mod,
// mark them as visible.
HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
if (Hidden != HiddenNamesMap.end()) {
- makeNamesVisible(Hidden->second);
+ makeNamesVisible(Hidden->second, Hidden->first);
HiddenNamesMap.erase(Hidden);
}
@@ -2614,80 +2838,86 @@ void ASTReader::makeModuleVisible(Module *Mod,
}
// Push any exported modules onto the stack to be marked as visible.
- bool AnyWildcard = false;
- bool UnrestrictedWildcard = false;
- llvm::SmallVector<Module *, 4> WildcardRestrictions;
- for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
- Module *Exported = Mod->Exports[I].getPointer();
- if (!Mod->Exports[I].getInt()) {
- // Export a named module directly; no wildcards involved.
- if (Visited.insert(Exported))
- Stack.push_back(Exported);
-
- continue;
- }
-
- // Wildcard export: export all of the imported modules that match
- // the given pattern.
- AnyWildcard = true;
- if (UnrestrictedWildcard)
- continue;
-
- if (Module *Restriction = Mod->Exports[I].getPointer())
- WildcardRestrictions.push_back(Restriction);
- else {
- WildcardRestrictions.clear();
- UnrestrictedWildcard = true;
- }
- }
-
- // If there were any wildcards, push any imported modules that were
- // re-exported by the wildcard restriction.
- if (!AnyWildcard)
- continue;
-
- for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
- Module *Imported = Mod->Imports[I];
- if (!Visited.insert(Imported))
- continue;
-
- bool Acceptable = UnrestrictedWildcard;
- if (!Acceptable) {
- // Check whether this module meets one of the restrictions.
- for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
- Module *Restriction = WildcardRestrictions[R];
- if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) {
- Acceptable = true;
- break;
- }
+ SmallVector<Module *, 16> Exports;
+ Mod->getExportedModules(Exports);
+ for (SmallVectorImpl<Module *>::iterator
+ I = Exports.begin(), E = Exports.end(); I != E; ++I) {
+ Module *Exported = *I;
+ if (Visited.insert(Exported))
+ Stack.push_back(Exported);
+ }
+
+ // Detect any conflicts.
+ if (Complain) {
+ assert(ImportLoc.isValid() && "Missing import location");
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ if (Mod->Conflicts[I].Other->NameVisibility >= NameVisibility) {
+ Diag(ImportLoc, diag::warn_module_conflict)
+ << Mod->getFullModuleName()
+ << Mod->Conflicts[I].Other->getFullModuleName()
+ << Mod->Conflicts[I].Message;
+ // FIXME: Need note where the other module was imported.
}
}
-
- if (!Acceptable)
- continue;
-
- Stack.push_back(Imported);
}
}
}
+bool ASTReader::loadGlobalIndex() {
+ if (GlobalIndex)
+ return false;
+
+ if (TriedLoadingGlobalIndex || !UseGlobalIndex ||
+ !Context.getLangOpts().Modules)
+ return true;
+
+ // Try to load the global index.
+ TriedLoadingGlobalIndex = true;
+ StringRef ModuleCachePath
+ = getPreprocessor().getHeaderSearchInfo().getModuleCachePath();
+ std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result
+ = GlobalModuleIndex::readIndex(ModuleCachePath);
+ if (!Result.first)
+ return true;
+
+ GlobalIndex.reset(Result.first);
+ ModuleMgr.setGlobalIndex(GlobalIndex.get());
+ return false;
+}
+
+bool ASTReader::isGlobalIndexUnavailable() const {
+ return Context.getLangOpts().Modules && UseGlobalIndex &&
+ !hasGlobalIndex() && TriedLoadingGlobalIndex;
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
+ SourceLocation ImportLoc,
unsigned ClientLoadCapabilities) {
// Bump the generation number.
unsigned PreviousGeneration = CurrentGeneration++;
unsigned NumModules = ModuleMgr.size();
- llvm::SmallVector<ModuleFile *, 4> Loaded;
- switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type,
+ SmallVector<ImportedModule, 4> Loaded;
+ switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
/*ImportedBy=*/0, Loaded,
+ 0, 0,
ClientLoadCapabilities)) {
case Failure:
+ case Missing:
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
case HadErrors:
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
+ Context.getLangOpts().Modules
+ ? &PP.getHeaderSearchInfo().getModuleMap()
+ : 0);
+
+ // 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);
return ReadResult;
case Success:
@@ -2697,10 +2927,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// Here comes stuff that we only do once the entire chain is loaded.
// Load the AST blocks of all of the modules that we loaded.
- for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(),
- MEnd = Loaded.end();
+ for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
M != MEnd; ++M) {
- ModuleFile &F = **M;
+ ModuleFile &F = *M->Mod;
// Read the AST block.
if (ReadASTBlock(F))
@@ -2723,6 +2953,24 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
}
}
+ // Setup the import locations and notify the module manager that we've
+ // committed to these module files.
+ for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = *M->Mod;
+
+ ModuleMgr.moduleFileAccepted(&F);
+
+ // Set the import location.
+ F.DirectImportLoc = ImportLoc;
+ if (!M->ImportedBy)
+ F.ImportLoc = M->ImportLoc;
+ else
+ F.ImportLoc = ReadSourceLocation(*M->ImportedBy,
+ M->ImportLoc.getRawEncoding());
+ }
+
// Mark all of the identifiers in the identifier table as being out of date,
// so that various accessors know to check the loaded modules when the
// identifier is used.
@@ -2732,22 +2980,34 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
Id->second->setOutOfDate(true);
// Resolve any unresolved module exports.
- for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
- UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
+ for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) {
+ UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I];
SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
Module *ResolvedMod = getSubmodule(GlobalID);
-
- if (Unresolved.IsImport) {
+
+ switch (Unresolved.Kind) {
+ case UnresolvedModuleRef::Conflict:
+ if (ResolvedMod) {
+ Module::Conflict Conflict;
+ Conflict.Other = ResolvedMod;
+ Conflict.Message = Unresolved.String.str();
+ Unresolved.Mod->Conflicts.push_back(Conflict);
+ }
+ continue;
+
+ case UnresolvedModuleRef::Import:
if (ResolvedMod)
Unresolved.Mod->Imports.push_back(ResolvedMod);
continue;
- }
- if (ResolvedMod || Unresolved.IsWildcard)
- Unresolved.Mod->Exports.push_back(
- Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ case UnresolvedModuleRef::Export:
+ if (ResolvedMod || Unresolved.IsWildcard)
+ Unresolved.Mod->Exports.push_back(
+ Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ continue;
+ }
}
- UnresolvedModuleImportExports.clear();
+ UnresolvedModuleRefs.clear();
InitializeContext();
@@ -2777,35 +3037,64 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ObjCClassesLoaded[I],
PreviousGeneration);
}
-
+
return Success;
}
ASTReader::ASTReadResult
ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
+ SourceLocation ImportLoc,
ModuleFile *ImportedBy,
- llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ SmallVectorImpl<ImportedModule> &Loaded,
+ off_t ExpectedSize, time_t ExpectedModTime,
unsigned ClientLoadCapabilities) {
ModuleFile *M;
- bool NewModule;
std::string ErrorStr;
- llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
- CurrentGeneration, ErrorStr);
-
- if (!M) {
- // We couldn't load the module.
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- return Failure;
- }
+ ModuleManager::AddModuleResult AddResult
+ = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
+ CurrentGeneration, ExpectedSize, ExpectedModTime,
+ M, ErrorStr);
- if (!NewModule) {
- // We've already loaded this module.
+ switch (AddResult) {
+ case ModuleManager::AlreadyLoaded:
return Success;
+
+ case ModuleManager::NewlyLoaded:
+ // Load module file below.
+ break;
+
+ case ModuleManager::Missing:
+ // The module file was missing; if the client handle handle, that, return
+ // it.
+ if (ClientLoadCapabilities & ARR_Missing)
+ return Missing;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
+
+ case ModuleManager::OutOfDate:
+ // We couldn't load the module file because it is out-of-date. If the
+ // client can handle out-of-date, return it.
+ if (ClientLoadCapabilities & ARR_OutOfDate)
+ return OutOfDate;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
}
+ assert(M && "Missing module file");
+
// FIXME: This seems rather a hack. Should CurrentDir be part of the
// module?
if (FileName != "-") {
@@ -2814,7 +3103,7 @@ ASTReader::ReadASTCore(StringRef FileName,
}
ModuleFile &F = *M;
- llvm::BitstreamCursor &Stream = F.Stream;
+ BitstreamCursor &Stream = F.Stream;
Stream.init(F.StreamFile);
F.SizeInBits = F.Buffer->getBufferSize() * 8;
@@ -2827,18 +3116,25 @@ ASTReader::ReadASTCore(StringRef FileName,
return Failure;
}
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
+ // This is used for compatibility with older PCH formats.
+ bool HaveReadControlBlock = false;
- if (Code != llvm::bitc::ENTER_SUBBLOCK) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::EndBlock:
+ case llvm::BitstreamEntry::Record:
Error("invalid record at top-level of AST file");
return Failure;
+
+ case llvm::BitstreamEntry::SubBlock:
+ break;
}
- unsigned BlockID = Stream.ReadSubBlockID();
-
// We only know the control subblock ID.
- switch (BlockID) {
+ switch (Entry.ID) {
case llvm::bitc::BLOCKINFO_BLOCK_ID:
if (Stream.ReadBlockInfoBlock()) {
Error("malformed BlockInfoBlock in AST file");
@@ -2846,11 +3142,13 @@ ASTReader::ReadASTCore(StringRef FileName,
}
break;
case CONTROL_BLOCK_ID:
+ HaveReadControlBlock = true;
switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
case Success:
break;
case Failure: return Failure;
+ case Missing: return Missing;
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
@@ -2858,8 +3156,14 @@ ASTReader::ReadASTCore(StringRef FileName,
}
break;
case AST_BLOCK_ID:
+ if (!HaveReadControlBlock) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::warn_pch_version_too_old);
+ return VersionMismatch;
+ }
+
// Record that we've loaded this module.
- Loaded.push_back(M);
+ Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
return Success;
default:
@@ -3004,7 +3308,9 @@ void ASTReader::InitializeContext() {
// 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]))
- makeModuleVisible(Imported, Module::AllVisible);
+ makeModuleVisible(Imported, Module::AllVisible,
+ /*ImportLoc=*/SourceLocation(),
+ /*Complain=*/false);
}
ImportedModules.clear();
}
@@ -3013,11 +3319,41 @@ void ASTReader::finalizeForWriting() {
for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
HiddenEnd = HiddenNamesMap.end();
Hidden != HiddenEnd; ++Hidden) {
- makeNamesVisible(Hidden->second);
+ makeNamesVisible(Hidden->second, Hidden->first);
}
HiddenNamesMap.clear();
}
+/// SkipCursorToControlBlock - Given a cursor at the start of an AST file, scan
+/// ahead and drop the cursor into the start of the CONTROL_BLOCK, returning
+/// false on success and true on failure.
+static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Cursor.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::EndBlock:
+ return true;
+
+ case llvm::BitstreamEntry::Record:
+ // Ignore top-level records.
+ Cursor.skipRecord(Entry.ID);
+ break;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (Entry.ID == CONTROL_BLOCK_ID) {
+ if (Cursor.EnterSubBlock(CONTROL_BLOCK_ID))
+ return true;
+ // Found it!
+ return false;
+ }
+
+ if (Cursor.SkipBlock())
+ return true;
+ }
+ }
+}
+
/// \brief Retrieve the name of the original source file name
/// directly from the AST file, without actually loading the AST
/// file.
@@ -3035,7 +3371,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
// Initialize the stream
llvm::BitstreamReader StreamFile;
- llvm::BitstreamCursor Stream;
+ BitstreamCursor Stream;
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
(const unsigned char *)Buffer->getBufferEnd());
Stream.init(StreamFile);
@@ -3048,54 +3384,30 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
return std::string();
}
+
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToControlBlock(Stream)) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
+ }
+ // Scan for ORIGINAL_FILE inside the control block.
RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- unsigned BlockID = Stream.ReadSubBlockID();
-
- // We only know the AST subblock ID.
- switch (BlockID) {
- case CONTROL_BLOCK_ID:
- if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
- Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
- return std::string();
- }
- break;
-
- default:
- if (Stream.SkipBlock()) {
- Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
- return std::string();
- }
- break;
- }
- continue;
- }
-
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName;
- return std::string();
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
+ return std::string();
+
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
}
-
+
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE)
- return std::string(BlobStart, BlobLen);
+ StringRef Blob;
+ if (Stream.readRecord(Entry.ID, Record, &Blob) == ORIGINAL_FILE)
+ return Blob.str();
}
-
- return std::string();
}
namespace {
@@ -3147,7 +3459,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
// Initialize the stream
llvm::BitstreamReader StreamFile;
- llvm::BitstreamCursor Stream;
+ BitstreamCursor Stream;
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
(const unsigned char *)Buffer->getBufferEnd());
Stream.init(StreamFile);
@@ -3160,105 +3472,71 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
return true;
}
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToControlBlock(Stream))
+ return true;
+
+ // Scan for ORIGINAL_FILE inside the control block.
RecordData Record;
- bool InControlBlock = false;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- unsigned BlockID = Stream.ReadSubBlockID();
-
- // We only know the control subblock ID.
- switch (BlockID) {
- case CONTROL_BLOCK_ID:
- if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
- return true;
- } else {
- InControlBlock = true;
- }
- break;
-
- default:
- if (Stream.SkipBlock())
- return true;
- break;
- }
- continue;
- }
-
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
+ return false;
+
+ if (Entry.Kind != llvm::BitstreamEntry::Record)
+ return true;
+
+ Record.clear();
+ StringRef Blob;
+ unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
+ switch ((ControlRecordTypes)RecCode) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR)
return true;
- }
- InControlBlock = false;
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+ if (Listener.ReadFullVersionInformation(Blob))
+ return true;
+
+ break;
}
+ case LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record, false, Listener))
+ return true;
+ break;
- Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
- if (InControlBlock) {
- switch ((ControlRecordTypes)RecCode) {
- case METADATA: {
- if (Record[0] != VERSION_MAJOR) {
- return true;
- }
-
- const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
- if (StringRef(CurBranch) != ASTBranch)
- return true;
-
- break;
- }
- case LANGUAGE_OPTIONS:
- if (ParseLanguageOptions(Record, false, Listener))
- return true;
- break;
-
- case TARGET_OPTIONS:
- if (ParseTargetOptions(Record, false, Listener))
- return true;
- break;
+ case TARGET_OPTIONS:
+ if (ParseTargetOptions(Record, false, Listener))
+ return true;
+ break;
- case DIAGNOSTIC_OPTIONS:
- if (ParseDiagnosticOptions(Record, false, Listener))
- return true;
- break;
+ case DIAGNOSTIC_OPTIONS:
+ if (ParseDiagnosticOptions(Record, false, Listener))
+ return true;
+ break;
- case FILE_SYSTEM_OPTIONS:
- if (ParseFileSystemOptions(Record, false, Listener))
- return true;
- break;
+ case FILE_SYSTEM_OPTIONS:
+ if (ParseFileSystemOptions(Record, false, Listener))
+ return true;
+ break;
- case HEADER_SEARCH_OPTIONS:
- if (ParseHeaderSearchOptions(Record, false, Listener))
- return true;
- break;
+ case HEADER_SEARCH_OPTIONS:
+ if (ParseHeaderSearchOptions(Record, false, Listener))
+ return true;
+ break;
- case PREPROCESSOR_OPTIONS: {
- std::string IgnoredSuggestedPredefines;
- if (ParsePreprocessorOptions(Record, false, Listener,
- IgnoredSuggestedPredefines))
- return true;
- break;
- }
+ case PREPROCESSOR_OPTIONS: {
+ std::string IgnoredSuggestedPredefines;
+ if (ParsePreprocessorOptions(Record, false, Listener,
+ IgnoredSuggestedPredefines))
+ return true;
+ break;
+ }
- default:
- // No other validation to perform.
- break;
- }
+ default:
+ // No other validation to perform.
+ break;
}
}
-
- return false;
}
@@ -3283,35 +3561,24 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
Module *CurrentModule = 0;
RecordData Record;
while (true) {
- unsigned Code = F.Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (F.Stream.ReadBlockEnd()) {
- Error("error at end of submodule block in AST file");
- return true;
- }
- return false;
- }
+ llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks();
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- F.Stream.ReadSubBlockID();
- if (F.Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- F.Stream.ReadAbbrevRecord();
- continue;
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return true;
+ case llvm::BitstreamEntry::EndBlock:
+ return false;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
-
+
// Read a record.
- const char *BlobStart;
- unsigned BlobLen;
+ StringRef Blob;
Record.clear();
- switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ switch (F.Stream.readRecord(Entry.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
@@ -3321,12 +3588,12 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return true;
}
- if (Record.size() < 7) {
+ if (Record.size() < 8) {
Error("malformed module definition");
return true;
}
- StringRef Name(BlobStart, BlobLen);
+ StringRef Name = Blob;
SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
bool IsFramework = Record[2];
@@ -3335,7 +3602,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
bool InferSubmodules = Record[5];
bool InferExplicitSubmodules = Record[6];
bool InferExportWildcard = Record[7];
-
+ bool ConfigMacrosExhaustive = Record[8];
+
Module *ParentModule = 0;
if (Parent)
ParentModule = getSubmodule(Parent);
@@ -3351,17 +3619,39 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
Error("too many submodules");
return true;
}
+
+ if (!ParentModule) {
+ if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
+ if (CurFile != F.File) {
+ if (!Diags.isDiagnosticInFlight()) {
+ Diag(diag::err_module_file_conflict)
+ << CurrentModule->getTopLevelModuleName()
+ << CurFile->getName()
+ << F.File->getName();
+ }
+ return true;
+ }
+ }
+
+ CurrentModule->setASTFile(F.File);
+ }
- CurrentModule->setASTFile(F.File);
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
+ CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
if (DeserializationListener)
DeserializationListener->ModuleRead(GlobalID, CurrentModule);
SubmodulesLoaded[GlobalIndex] = CurrentModule;
+
+ // Clear out data that will be replaced by what is the module file.
+ CurrentModule->LinkLibraries.clear();
+ CurrentModule->ConfigMacros.clear();
+ CurrentModule->UnresolvedConflicts.clear();
+ CurrentModule->Conflicts.clear();
break;
}
@@ -3374,8 +3664,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
+ if (const FileEntry *Umbrella = PP.getFileManager().getFile(Blob)) {
if (!CurrentModule->getUmbrellaHeader())
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
@@ -3395,14 +3684,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- // FIXME: Be more lazy about this!
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
- if (std::find(CurrentModule->Headers.begin(),
- CurrentModule->Headers.end(),
- File) == CurrentModule->Headers.end())
- ModMap.addHeader(CurrentModule, File, false);
- }
+ // We lazily associate headers with their modules via the HeaderInfoTable.
+ // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
+ // of complete filenames or remove it entirely.
break;
}
@@ -3415,14 +3699,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- // FIXME: Be more lazy about this!
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
- if (std::find(CurrentModule->Headers.begin(),
- CurrentModule->Headers.end(),
- File) == CurrentModule->Headers.end())
- ModMap.addHeader(CurrentModule, File, true);
- }
+ // We lazily associate headers with their modules via the HeaderInfoTable.
+ // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
+ // of complete filenames or remove it entirely.
break;
}
@@ -3435,10 +3714,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- // FIXME: Be more lazy about this!
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *File = PP.getFileManager().getFile(FileName))
- CurrentModule->TopHeaders.insert(File);
+ CurrentModule->addTopHeaderFilename(Blob);
break;
}
@@ -3451,9 +3727,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- StringRef DirName(BlobStart, BlobLen);
if (const DirectoryEntry *Umbrella
- = PP.getFileManager().getDirectory(DirName)) {
+ = PP.getFileManager().getDirectory(Blob)) {
if (!CurrentModule->getUmbrellaDir())
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
@@ -3500,13 +3775,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
- UnresolvedModuleImportExport Unresolved;
+ UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
Unresolved.ID = Record[Idx];
- Unresolved.IsImport = true;
+ Unresolved.Kind = UnresolvedModuleRef::Import;
Unresolved.IsWildcard = false;
- UnresolvedModuleImportExports.push_back(Unresolved);
+ UnresolvedModuleRefs.push_back(Unresolved);
}
break;
}
@@ -3521,13 +3796,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
- UnresolvedModuleImportExport Unresolved;
+ UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
Unresolved.ID = Record[Idx];
- Unresolved.IsImport = false;
+ Unresolved.Kind = UnresolvedModuleRef::Export;
Unresolved.IsWildcard = Record[Idx + 1];
- UnresolvedModuleImportExports.push_back(Unresolved);
+ UnresolvedModuleRefs.push_back(Unresolved);
}
// Once we've loaded the set of exports, there's no reason to keep
@@ -3544,11 +3819,55 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- CurrentModule->addRequirement(StringRef(BlobStart, BlobLen),
- Context.getLangOpts(),
+ CurrentModule->addRequirement(Blob, Context.getLangOpts(),
Context.getTargetInfo());
break;
}
+
+ case SUBMODULE_LINK_LIBRARY:
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->LinkLibraries.push_back(
+ Module::LinkLibrary(Blob, Record[0]));
+ break;
+
+ case SUBMODULE_CONFIG_MACRO:
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->ConfigMacros.push_back(Blob.str());
+ break;
+
+ case SUBMODULE_CONFLICT: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[0];
+ Unresolved.Kind = UnresolvedModuleRef::Conflict;
+ Unresolved.IsWildcard = false;
+ Unresolved.String = Blob;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ break;
+ }
}
}
}
@@ -3570,6 +3889,8 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record,
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) LangOpts.Sanitize.ID = Record[Idx++];
+#include "clang/Basic/Sanitizers.def"
ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
@@ -3578,6 +3899,15 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record,
unsigned Length = Record[Idx++];
LangOpts.CurrentModule.assign(Record.begin() + Idx,
Record.begin() + Idx + Length);
+
+ Idx += Length;
+
+ // Comment options.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ LangOpts.CommentOpts.BlockCommandNames.push_back(
+ ReadString(Record, Idx));
+ }
+
return Listener.ReadLanguageOptions(LangOpts, Complain);
}
@@ -3637,14 +3967,10 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
std::string Path = ReadString(Record, Idx);
frontend::IncludeDirGroup Group
= static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
- bool IsUserSupplied = Record[Idx++];
bool IsFramework = Record[Idx++];
bool IgnoreSysRoot = Record[Idx++];
- bool IsInternal = Record[Idx++];
- bool ImplicitExternC = Record[Idx++];
HSOpts.UserEntries.push_back(
- HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework,
- IgnoreSysRoot, IsInternal, ImplicitExternC));
+ HeaderSearchOptions::Entry(Path, Group, IsFramework, IgnoreSysRoot));
}
// System header prefixes.
@@ -3735,41 +4061,28 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
unsigned LocalIndex = PPInfo.second;
const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
- SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
- M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
-
- unsigned Code = M.PreprocessorDetailCursor.ReadCode();
- switch (Code) {
- case llvm::bitc::END_BLOCK:
- return 0;
-
- case llvm::bitc::ENTER_SUBBLOCK:
- Error("unexpected subblock record in preprocessor detail block");
- return 0;
-
- case llvm::bitc::DEFINE_ABBREV:
- Error("unexpected abbrevation record in preprocessor detail block");
- return 0;
-
- default:
- break;
- }
-
if (!PP.getPreprocessingRecord()) {
Error("no preprocessing record");
return 0;
}
+ SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
+ M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
+
+ llvm::BitstreamEntry Entry =
+ M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
+ if (Entry.Kind != llvm::BitstreamEntry::Record)
+ return 0;
+
// Read the record.
SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
ReadSourceLocation(M, PPOffs.End));
PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
+ StringRef Blob;
RecordData Record;
PreprocessorDetailRecordTypes RecType =
- (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord(
- Code, Record, BlobStart, BlobLen);
+ (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.readRecord(
+ Entry.ID, Record, &Blob);
switch (RecType) {
case PPD_MACRO_EXPANSION: {
bool isBuiltin = Record[0];
@@ -3806,8 +4119,8 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
}
case PPD_INCLUSION_DIRECTIVE: {
- const char *FullFileNameStart = BlobStart + Record[0];
- StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]);
+ const char *FullFileNameStart = Blob.data() + Record[0];
+ StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
const FileEntry *File = 0;
if (!FullFileName.empty())
File = PP.getFileManager().getFile(FullFileName);
@@ -3817,7 +4130,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
= static_cast<InclusionDirective::InclusionKind>(Record[2]);
InclusionDirective *ID
= new (PPRec) InclusionDirective(PPRec, Kind,
- StringRef(BlobStart, Record[0]),
+ StringRef(Blob.data(), Record[0]),
Record[1], Record[3],
File,
Range);
@@ -3885,7 +4198,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
GlobalSLocOffsetMapType::const_iterator
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- BLoc.getOffset());
+ BLoc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -3933,7 +4246,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
GlobalSLocOffsetMapType::const_iterator
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- ELoc.getOffset());
+ ELoc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -3969,7 +4282,7 @@ std::pair<unsigned, unsigned>
/// \brief Optionally returns true or false if the preallocated preprocessed
/// entity with index \arg Index came from file \arg FID.
-llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
+Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
FileID FID) {
if (FID.isInvalid())
return false;
@@ -3992,32 +4305,25 @@ llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
namespace {
/// \brief Visitor used to search for information about a header file.
class HeaderFileInfoVisitor {
- ASTReader &Reader;
const FileEntry *FE;
- llvm::Optional<HeaderFileInfo> HFI;
+ Optional<HeaderFileInfo> HFI;
public:
- HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
- : Reader(Reader), FE(FE) { }
+ explicit HeaderFileInfoVisitor(const FileEntry *FE)
+ : FE(FE) { }
static bool visit(ModuleFile &M, void *UserData) {
HeaderFileInfoVisitor *This
= static_cast<HeaderFileInfoVisitor *>(UserData);
- HeaderFileInfoTrait Trait(This->Reader, M,
- &This->Reader.getPreprocessor().getHeaderSearchInfo(),
- M.HeaderFileFrameworkStrings,
- This->FE->getName());
-
HeaderFileInfoLookupTable *Table
= static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
if (!Table)
return false;
// Look in the on-disk hash table for an entry for this file name.
- HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(),
- &Trait);
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE);
if (Pos == Table->end())
return false;
@@ -4025,14 +4331,14 @@ namespace {
return true;
}
- llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
+ Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
};
}
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
- HeaderFileInfoVisitor Visitor(*this, FE);
+ HeaderFileInfoVisitor Visitor(FE);
ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
- if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
+ if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
if (Listener)
Listener->ReadHeaderFileInfo(*HFI, FE->getUID());
return *HFI;
@@ -4043,7 +4349,7 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
// FIXME: Make it work properly with modules.
- llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
+ SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
ModuleFile &F = *(*I);
unsigned Idx = 0;
@@ -4103,7 +4409,7 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
/// IDs.
QualType ASTReader::readTypeRecord(unsigned Index) {
RecordLocation Loc = TypeCursorForIndex(Index);
- llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
+ BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this type.
@@ -4118,7 +4424,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
DeclsCursor.JumpToBit(Loc.Offset);
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
- switch ((TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
+ switch ((TypeCode)DeclsCursor.readRecord(Code, Record)) {
case TYPE_EXT_QUAL: {
if (Record.size() != 2) {
Error("Incorrect encoding of extended qualifier type");
@@ -4287,8 +4593,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
} else if (EST == EST_Unevaluated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
}
- return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
- EPI);
+ return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
case TYPE_UNRESOLVED_USING: {
@@ -4392,7 +4697,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType Pattern = readType(*Loc.F, Record, Idx);
if (Pattern.isNull())
return QualType();
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (Record[1])
NumExpansions = Record[1] - 1;
return Context.getPackExpansionType(Pattern, NumExpansions);
@@ -4834,6 +5139,14 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break;
case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break;
case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break;
+ case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break;
+ case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break;
+ case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break;
+ case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break;
+ case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break;
+ case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break;
+ case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break;
+ case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break;
case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
case PREDEF_TYPE_AUTO_RREF_DEDUCT:
@@ -4957,13 +5270,13 @@ uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Recor
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
RecordLocation Loc = getLocalBitOffset(Offset);
- llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor;
+ BitstreamCursor &Cursor = Loc.F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(Loc.Offset);
ReadingKindTracker ReadingKind(Read_Decl, *this);
RecordData Record;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record);
+ unsigned RecCode = Cursor.readRecord(Code, Record);
if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
Error("Malformed AST file: missing C++ base specifiers");
return 0;
@@ -4997,7 +5310,7 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
return &M == I->second;
}
-ModuleFile *ASTReader::getOwningModuleFile(Decl *D) {
+ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
if (!D->isFromASTFile())
return 0;
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
@@ -5269,7 +5582,7 @@ namespace {
/// declaration context.
class DeclContextNameLookupVisitor {
ASTReader &Reader;
- llvm::SmallVectorImpl<const DeclContext *> &Contexts;
+ SmallVectorImpl<const DeclContext *> &Contexts;
DeclarationName Name;
SmallVectorImpl<NamedDecl *> &Decls;
@@ -5333,14 +5646,34 @@ namespace {
};
}
-DeclContext::lookup_result
+/// \brief Retrieve the "definitive" module file for the definition of the
+/// given declaration context, if there is one.
+///
+/// The "definitive" module file is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive module files
+/// associated with them. C++ namespaces, on the other hand, can have
+/// definitions in multiple different module files.
+///
+/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's
+/// NDEBUG checking.
+static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
+ ASTReader &Reader) {
+ if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
+ return Reader.getOwningModuleFile(cast<Decl>(DefDC));
+
+ return 0;
+}
+
+bool
ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
assert(DC->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
if (!Name)
- return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
- DeclContext::lookup_iterator(0));
+ return false;
SmallVector<NamedDecl *, 64> Decls;
@@ -5361,10 +5694,19 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
}
DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
- ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+
+ // If we can definitively determine which module file to look into,
+ // only look there. Otherwise, look in all module files.
+ ModuleFile *Definitive;
+ if (Contexts.size() == 1 &&
+ (Definitive = getDefinitiveModuleFileFor(DC, *this))) {
+ DeclContextNameLookupVisitor::visit(*Definitive, &Visitor);
+ } else {
+ ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+ }
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
- return const_cast<DeclContext*>(DC)->lookup(Name);
+ return !Decls.empty();
}
namespace {
@@ -5372,15 +5714,17 @@ namespace {
/// declaration context.
class DeclContextAllNamesVisitor {
ASTReader &Reader;
- llvm::SmallVectorImpl<const DeclContext *> &Contexts;
+ SmallVectorImpl<const DeclContext *> &Contexts;
llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls;
+ bool VisitAll;
public:
DeclContextAllNamesVisitor(ASTReader &Reader,
SmallVectorImpl<const DeclContext *> &Contexts,
llvm::DenseMap<DeclarationName,
- SmallVector<NamedDecl *, 8> > &Decls)
- : Reader(Reader), Contexts(Contexts), Decls(Decls) { }
+ SmallVector<NamedDecl *, 8> > &Decls,
+ bool VisitAll)
+ : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
static bool visit(ModuleFile &M, void *UserData) {
DeclContextAllNamesVisitor *This
@@ -5406,8 +5750,9 @@ namespace {
Info->second.NameLookupTableData;
bool FoundAnything = false;
for (ASTDeclContextNameLookupTable::data_iterator
- I = LookupTable->data_begin(), E = LookupTable->data_end();
- I != E; ++I) {
+ I = LookupTable->data_begin(), E = LookupTable->data_end();
+ I != E;
+ ++I) {
ASTDeclContextNameLookupTrait::data_type Data = *I;
for (; Data.first != Data.second; ++Data.first) {
NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M,
@@ -5421,7 +5766,7 @@ namespace {
}
}
- return FoundAnything;
+ return FoundAnything && !This->VisitAll;
}
};
}
@@ -5429,7 +5774,7 @@ namespace {
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
if (!DC->hasExternalVisibleStorage())
return;
- llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls;
+ llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > Decls;
// Compute the declaration contexts we need to look into. Multiple such
// declaration contexts occur when two declaration contexts from disjoint
@@ -5447,12 +5792,13 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
}
}
- DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls);
+ DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
+ /*VisitAll=*/DC->isFileContext());
ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
for (llvm::DenseMap<DeclarationName,
- llvm::SmallVector<NamedDecl*, 8> >::iterator
+ SmallVector<NamedDecl *, 8> >::iterator
I = Decls.begin(), E = Decls.end(); I != E; ++I) {
SetExternalVisibleDeclsForName(DC, I->first, I->second);
}
@@ -5576,8 +5922,31 @@ void ASTReader::PrintStats() {
NumMethodPoolEntriesRead, TotalNumMethodPoolEntries,
((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries
* 100));
- std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
}
+ if (NumMethodPoolLookups) {
+ std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n",
+ NumMethodPoolHits, NumMethodPoolLookups,
+ ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0));
+ }
+ if (NumMethodPoolTableLookups) {
+ std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n",
+ NumMethodPoolTableHits, NumMethodPoolTableLookups,
+ ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups
+ * 100.0));
+ }
+
+ if (NumIdentifierLookupHits) {
+ std::fprintf(stderr,
+ " %u / %u identifier table lookups succeeded (%f%%)\n",
+ NumIdentifierLookupHits, NumIdentifierLookups,
+ (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
+ }
+
+ if (GlobalIndex) {
+ std::fprintf(stderr, "\n");
+ GlobalIndex->printStats();
+ }
+
std::fprintf(stderr, "\n");
dump();
std::fprintf(stderr, "\n");
@@ -5646,8 +6015,8 @@ void ASTReader::InitializeSema(Sema &S) {
// Makes sure any declarations that were deserialized "too early"
// still get added to the identifier's declaration chains.
for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
- SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I],
- PreloadedDecls[I]->getDeclName());
+ NamedDecl *ND = cast<NamedDecl>(PreloadedDecls[I]->getMostRecentDecl());
+ SemaObj->pushExternalDeclIntoScope(ND, PreloadedDecls[I]->getDeclName());
}
PreloadedDecls.clear();
@@ -5678,10 +6047,21 @@ void ASTReader::InitializeSema(Sema &S) {
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
// Note that we are loading an identifier.
Deserializing AnIdentifier(this);
-
- IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
- /*PriorGeneration=*/0);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+ StringRef Name(NameStart, NameEnd - NameStart);
+
+ // 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;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(Name, Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+ IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0,
+ NumIdentifierLookups,
+ NumIdentifierLookupHits);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
IdentifierInfo *II = Visitor.getIdentifierInfo();
markIdentifierUpToDate(II);
return II;
@@ -5737,9 +6117,9 @@ StringRef ASTIdentifierIterator::Next() {
// We have any identifiers remaining in the current AST file; return
// the next one.
- std::pair<const char*, unsigned> Key = *Current;
+ StringRef Result = *Current;
++Current;
- return StringRef(Key.first, Key.second);
+ return Result;
}
IdentifierIterator *ASTReader::getIdentifiers() const {
@@ -5751,8 +6131,8 @@ namespace clang { namespace serialization {
ASTReader &Reader;
Selector Sel;
unsigned PriorGeneration;
- llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
- llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
+ SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
+ SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
public:
ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
@@ -5770,12 +6150,14 @@ namespace clang { namespace serialization {
if (M.Generation <= This->PriorGeneration)
return true;
+ ++This->Reader.NumMethodPoolTableLookups;
ASTSelectorLookupTable *PoolTable
= (ASTSelectorLookupTable*)M.SelectorLookupTable;
ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
if (Pos == PoolTable->end())
return false;
-
+
+ ++This->Reader.NumMethodPoolTableHits;
++This->Reader.NumSelectorsRead;
// FIXME: Not quite happy with the statistics here. We probably should
// disable this tracking when called via LoadSelector.
@@ -5818,15 +6200,16 @@ void ASTReader::ReadMethodPool(Selector Sel) {
Generation = CurrentGeneration;
// Search for methods defined with this selector.
+ ++NumMethodPoolLookups;
ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
if (Visitor.getInstanceMethods().empty() &&
- Visitor.getFactoryMethods().empty()) {
- ++NumMethodPoolMisses;
+ Visitor.getFactoryMethods().empty())
return;
- }
-
+
+ ++NumMethodPoolHits;
+
if (!getSema())
return;
@@ -5849,6 +6232,16 @@ void ASTReader::ReadKnownNamespaces(
}
}
+void ASTReader::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) {
+ for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(UndefinedButUsed[Idx++]));
+ SourceLocation Loc =
+ SourceLocation::getFromRawEncoding(UndefinedButUsed[Idx++]);
+ Undefined.insert(std::make_pair(D, Loc));
+ }
+}
+
void ASTReader::ReadTentativeDefinitions(
SmallVectorImpl<VarDecl *> &TentativeDefs) {
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
@@ -5902,14 +6295,14 @@ void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
}
void
-ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) {
- for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
- NamedDecl *D
- = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
+ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl *> &Decls) {
+ for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) {
+ NamedDecl *D
+ = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternCDecls[I]));
if (D)
Decls.push_back(D);
}
- LocallyScopedExternalDecls.clear();
+ LocallyScopedExternCDecls.clear();
}
void ASTReader::ReadReferencedSelectors(
@@ -6000,28 +6393,32 @@ void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
/// \param DeclIDs the set of declaration IDs with the name @p II that are
/// visible at global scope.
///
-/// \param Nonrecursive should be true to indicate that the caller knows that
-/// this call is non-recursive, and therefore the globally-visible declarations
-/// will not be placed onto the pending queue.
+/// \param Decls if non-null, this vector will be populated with the set of
+/// deserialized declarations. These declarations will not be pushed into
+/// scope.
void
ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
const SmallVectorImpl<uint32_t> &DeclIDs,
- bool Nonrecursive) {
- if (NumCurrentElementsDeserializing && !Nonrecursive) {
- PendingIdentifierInfos.push_back(PendingIdentifierInfo());
- PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
- PII.II = II;
- PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end());
+ SmallVectorImpl<Decl *> *Decls) {
+ if (NumCurrentElementsDeserializing && !Decls) {
+ PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end());
return;
}
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
if (SemaObj) {
+ // If we're simply supposed to record the declarations, do so now.
+ if (Decls) {
+ Decls->push_back(D);
+ continue;
+ }
+
// Introduce this declaration into the translation-unit scope
// and add it to the declaration chain for this identifier, so
// that (unqualified) name lookup will find it.
- SemaObj->pushExternalDeclIntoScope(D, II);
+ NamedDecl *ND = cast<NamedDecl>(D->getMostRecentDecl());
+ SemaObj->pushExternalDeclIntoScope(ND, II);
} else {
// Queue this declaration so that it will be added to the
// translation unit scope and identifier's declaration chain
@@ -6081,7 +6478,7 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
return LocalID + I->second;
}
-MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
+MacroInfo *ASTReader::getMacro(MacroID ID) {
if (ID == 0)
return 0;
@@ -6097,7 +6494,11 @@ MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
ModuleFile *M = I->second;
unsigned Index = ID - M->BaseMacroID;
- ReadMacroRecord(*M, M->MacroOffsets[Index], Hint);
+ MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]);
+
+ if (DeserializationListener)
+ DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS,
+ MacrosLoaded[ID]);
}
return MacrosLoaded[ID];
@@ -6140,7 +6541,11 @@ Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
}
-
+
+Module *ASTReader::getModule(unsigned ID) {
+ return getSubmodule(ID);
+}
+
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
return DecodeSelector(getGlobalSelectorID(M, LocalID));
}
@@ -6370,7 +6775,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
return TemplateArgument(ReadTemplateName(F, Record, Idx));
case TemplateArgument::TemplateExpansion: {
TemplateName Name = ReadTemplateName(F, Record, Idx);
- llvm::Optional<unsigned> NumTemplateExpansions;
+ Optional<unsigned> NumTemplateExpansions;
if (unsigned NumExpansions = Record[Idx++])
NumTemplateExpansions = NumExpansions - 1;
return TemplateArgument(Name, NumTemplateExpansions);
@@ -6420,13 +6825,14 @@ ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
}
/// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set,
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
+ Set.reserve(Context, NumDecls);
while (NumDecls--) {
NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
- Set.addDecl(D, AS);
+ Set.addDecl(Context, D, AS);
}
}
@@ -6656,8 +7062,10 @@ llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
}
/// \brief Read a floating-point value
-llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
- return llvm::APFloat(ReadAPInt(Record, Idx));
+llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record,
+ const llvm::fltSemantics &Sem,
+ unsigned &Idx) {
+ return llvm::APFloat(Sem, ReadAPInt(Record, Idx));
}
// \brief Read a string
@@ -6721,39 +7129,35 @@ void ASTReader::ClearSwitchCaseIDs() {
void ASTReader::ReadComments() {
std::vector<RawComment *> Comments;
- for (SmallVectorImpl<std::pair<llvm::BitstreamCursor,
+ for (SmallVectorImpl<std::pair<BitstreamCursor,
serialization::ModuleFile *> >::iterator
I = CommentsCursors.begin(),
E = CommentsCursors.end();
I != E; ++I) {
- llvm::BitstreamCursor &Cursor = I->first;
+ BitstreamCursor &Cursor = I->first;
serialization::ModuleFile &F = *I->second;
SavedStreamPosition SavedPosition(Cursor);
RecordData Record;
while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK)
+ llvm::BitstreamEntry Entry =
+ Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd);
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return;
+ case llvm::BitstreamEntry::EndBlock:
+ goto NextCursor;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
break;
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
}
// Read a record.
Record.clear();
- switch ((CommentRecordTypes) Cursor.ReadRecord(Code, Record)) {
+ switch ((CommentRecordTypes)Cursor.readRecord(Entry.ID, Record)) {
case COMMENTS_RAW_COMMENT: {
unsigned Idx = 0;
SourceRange SR = ReadSourceRange(F, Record, Idx);
@@ -6768,19 +7172,24 @@ void ASTReader::ReadComments() {
}
}
}
+ NextCursor:;
}
Context.Comments.addCommentsToFront(Comments);
}
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
- !PendingMacroIDs.empty()) {
+ !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
+ llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> > TopLevelDecls;
while (!PendingIdentifierInfos.empty()) {
- SetGloballyVisibleDecls(PendingIdentifierInfos.front().II,
- PendingIdentifierInfos.front().DeclIDs, true);
- PendingIdentifierInfos.pop_front();
+ // FIXME: std::move
+ IdentifierInfo *II = PendingIdentifierInfos.back().first;
+ SmallVector<uint32_t, 4> DeclIDs = PendingIdentifierInfos.back().second;
+ PendingIdentifierInfos.pop_back();
+
+ SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]);
}
// Load pending declaration chains.
@@ -6790,17 +7199,48 @@ void ASTReader::finishPendingActions() {
}
PendingDeclChains.clear();
+ // Make the most recent of the top-level declarations visible.
+ for (llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >::iterator
+ TLD = TopLevelDecls.begin(), TLDEnd = TopLevelDecls.end();
+ TLD != TLDEnd; ++TLD) {
+ IdentifierInfo *II = TLD->first;
+ for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) {
+ NamedDecl *ND = cast<NamedDecl>(TLD->second[I]->getMostRecentDecl());
+ SemaObj->pushExternalDeclIntoScope(ND, II);
+ }
+ }
+
// Load any pending macro definitions.
for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
- // FIXME: std::move here
- SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second;
- MacroInfo *Hint = 0;
+ IdentifierInfo *II = PendingMacroIDs.begin()[I].first;
+ 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;
++IDIdx) {
- Hint = getMacro(GlobalIDs[IDIdx], Hint);
+ 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;
+ ++IDIdx) {
+ const PendingMacroInfo &Info = GlobalIDs[IDIdx];
+ if (Info.M->Kind == MK_Module)
+ resolvePendingMacro(II, Info);
}
}
PendingMacroIDs.clear();
+
+ // Wire up the DeclContexts for Decls that we delayed setting until
+ // recursive loading is completed.
+ while (!PendingDeclContextInfos.empty()) {
+ PendingDeclContextInfo Info = PendingDeclContextInfos.front();
+ PendingDeclContextInfos.pop_front();
+ DeclContext *SemaDC = cast<DeclContext>(GetDecl(Info.SemaDC));
+ DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC));
+ Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
+ }
}
// If we deserialized any C++ or Objective-C class definitions, any
@@ -6908,18 +7348,22 @@ void ASTReader::FinishedDeserializing() {
ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
StringRef isysroot, bool DisableValidation,
- bool AllowASTWithCompilerErrors)
+ 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),
+ AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false),
CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
- NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
- TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
- NumMethodPoolMisses(0), TotalNumMethodPoolEntries(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),
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index c42944df6344..0fbdd7e5daeb 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -12,19 +12,19 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Serialization/ASTReader.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
-#include "clang/Serialization/ASTReader.h"
-#include "clang/Sema/IdentifierResolver.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace clang::serialization;
@@ -44,9 +44,6 @@ namespace clang {
unsigned &Idx;
TypeID TypeIDForTypeDecl;
- DeclID DeclContextIDForTemplateParmDecl;
- DeclID LexicalDeclContextIDForTemplateParmDecl;
-
bool HasPendingBody;
uint64_t GetCurrentCursorOffset();
@@ -116,29 +113,25 @@ namespace clang {
ASTReader &Reader;
GlobalDeclID FirstID;
mutable bool Owning;
+ Decl::Kind DeclKind;
void operator=(RedeclarableResult &) LLVM_DELETED_FUNCTION;
public:
- RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID)
- : Reader(Reader), FirstID(FirstID), Owning(true) { }
+ RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID,
+ Decl::Kind DeclKind)
+ : Reader(Reader), FirstID(FirstID), Owning(true), DeclKind(DeclKind) { }
RedeclarableResult(const RedeclarableResult &Other)
- : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning)
+ : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning) ,
+ DeclKind(Other.DeclKind)
{
Other.Owning = false;
}
~RedeclarableResult() {
- // FIXME: We want to suppress this when the declaration is local to
- // a function, since there's no reason to search other AST files
- // for redeclarations (they can't exist). However, this is hard to
- // do locally because the declaration hasn't necessarily loaded its
- // declaration context yet. Also, local externs still have the function
- // as their (semantic) declaration context, which is wrong and would
- // break this optimize.
-
- if (FirstID && Owning && Reader.PendingDeclChainsKnown.insert(FirstID))
+ if (FirstID && Owning && isRedeclarableDeclKind(DeclKind) &&
+ Reader.PendingDeclChainsKnown.insert(FirstID))
Reader.PendingDeclChains.push_back(FirstID);
}
@@ -151,7 +144,7 @@ namespace clang {
Owning = false;
}
};
-
+
/// \brief Class used to capture the result of searching for an existing
/// declaration of a specific kind and name, along with the ability
/// to update the place where this result was found (the declaration
@@ -272,6 +265,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
+ void VisitEmptyDecl(EmptyDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
@@ -295,6 +289,7 @@ namespace clang {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
};
}
@@ -333,14 +328,6 @@ void ASTDeclReader::Visit(Decl *D) {
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
}
- } else if (D->isTemplateParameter()) {
- // If we have a fully initialized template parameter, we can now
- // set its DeclContext.
- DeclContext *SemaDC = cast<DeclContext>(
- Reader.GetDecl(DeclContextIDForTemplateParmDecl));
- DeclContext *LexicalDC = cast<DeclContext>(
- Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl));
- D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
}
}
@@ -350,8 +337,11 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// parameter immediately, because the template parameter might be
// used in the formulation of its DeclContext. Use the translation
// unit DeclContext as a placeholder.
- DeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
- LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ Reader.addPendingDeclContextInfo(D,
+ SemaDCIDForTemplateParmDecl,
+ LexicalDCIDForTemplateParmDecl);
D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
} else {
DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
@@ -479,6 +469,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
RD->setHasFlexibleArrayMember(Record[Idx++]);
RD->setAnonymousStructOrUnion(Record[Idx++]);
RD->setHasObjectMember(Record[Idx++]);
+ RD->setHasVolatileMember(Record[Idx++]);
}
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
@@ -513,9 +504,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// FunctionDecl's body is handled last at ASTDeclReader::Visit,
// after everything else is read.
-
+
FD->SClass = (StorageClass)Record[Idx++];
- FD->SClassAsWritten = (StorageClass)Record[Idx++];
FD->IsInline = Record[Idx++];
FD->IsInlineSpecified = Record[Idx++];
FD->IsVirtualAsWritten = Record[Idx++];
@@ -528,6 +518,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->IsExplicitlyDefaulted = Record[Idx++];
FD->HasImplicitReturnZero = Record[Idx++];
FD->IsConstexpr = Record[Idx++];
+ FD->HasSkippedBody = Record[Idx++];
+ FD->HasCachedLinkage = true;
+ FD->CachedLinkage = Record[Idx++];
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
@@ -652,6 +645,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setPropertyAccessor(Record[Idx++]);
MD->setDefined(Record[Idx++]);
MD->IsOverriding = Record[Idx++];
+ MD->HasSkippedBody = Record[Idx++];
MD->IsRedeclaration = Record[Idx++];
MD->HasRedeclaration = Record[Idx++];
@@ -899,9 +893,8 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
RedeclarableResult Redecl = VisitRedeclarable(VD);
VisitDeclaratorDecl(VD);
-
+
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
- VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++];
VD->VarDeclBits.ThreadSpecified = Record[Idx++];
VD->VarDeclBits.InitStyle = Record[Idx++];
VD->VarDeclBits.ExceptionVar = Record[Idx++];
@@ -909,6 +902,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
VD->VarDeclBits.IsConstexpr = Record[Idx++];
+ VD->HasCachedLinkage = true;
+ VD->CachedLinkage = Record[Idx++];
// Only true variables (not parameters or implicit parameters) can be merged.
if (VD->getKind() == Decl::Var)
@@ -1083,11 +1078,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
const RecordData &Record, unsigned &Idx) {
// Note: the caller has deserialized the IsLambda bit already.
Data.UserDeclaredConstructor = Record[Idx++];
- Data.UserDeclaredCopyConstructor = Record[Idx++];
- Data.UserDeclaredMoveConstructor = Record[Idx++];
- Data.UserDeclaredCopyAssignment = Record[Idx++];
- Data.UserDeclaredMoveAssignment = Record[Idx++];
- Data.UserDeclaredDestructor = Record[Idx++];
+ Data.UserDeclaredSpecialMembers = Record[Idx++];
Data.Aggregate = Record[Idx++];
Data.PlainOldData = Record[Idx++];
Data.Empty = Record[Idx++];
@@ -1101,25 +1092,26 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasMutableFields = Record[Idx++];
Data.HasOnlyCMembers = Record[Idx++];
Data.HasInClassInitializer = Record[Idx++];
- Data.HasTrivialDefaultConstructor = Record[Idx++];
+ Data.HasUninitializedReferenceMember = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++];
+ Data.NeedOverloadResolutionForDestructor = Record[Idx++];
+ Data.DefaultedMoveConstructorIsDeleted = Record[Idx++];
+ Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
+ Data.DefaultedDestructorIsDeleted = Record[Idx++];
+ Data.HasTrivialSpecialMembers = Record[Idx++];
+ Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
Data.HasConstexprDefaultConstructor = Record[Idx++];
- Data.HasTrivialCopyConstructor = Record[Idx++];
- Data.HasTrivialMoveConstructor = Record[Idx++];
- Data.HasTrivialCopyAssignment = Record[Idx++];
- Data.HasTrivialMoveAssignment = Record[Idx++];
- Data.HasTrivialDestructor = Record[Idx++];
- Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
Data.UserProvidedDefaultConstructor = Record[Idx++];
- Data.DeclaredDefaultConstructor = Record[Idx++];
- Data.DeclaredCopyConstructor = Record[Idx++];
- Data.DeclaredMoveConstructor = Record[Idx++];
- Data.DeclaredCopyAssignment = Record[Idx++];
- Data.DeclaredMoveAssignment = Record[Idx++];
- Data.DeclaredDestructor = Record[Idx++];
+ Data.DeclaredSpecialMembers = Record[Idx++];
+ Data.ImplicitCopyConstructorHasConstParam = Record[Idx++];
+ Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
+ Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
+ Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
Data.FailedImplicitMoveConstructor = Record[Idx++];
Data.FailedImplicitMoveAssignment = Record[Idx++];
@@ -1266,10 +1258,12 @@ void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
VisitDecl(D);
- if (Record[Idx++])
- D->Friend = GetTypeSourceInfo(Record, Idx);
- else
+ if (Record[Idx++]) // hasFriendDecl
D->Friend = ReadDeclAs<NamedDecl>(Record, Idx);
+ else
+ D->Friend = GetTypeSourceInfo(Record, Idx);
+ for (unsigned i = 0; i != D->NumTPLists; ++i)
+ D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
D->NextFriend = Record[Idx++];
D->UnsupportedFriend = (Record[Idx++] != 0);
D->FriendLoc = ReadSourceLocation(Record, Idx);
@@ -1532,6 +1526,10 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
D->RParenLoc = ReadSourceLocation(Record, Idx);
}
+void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) {
+ VisitDecl(D);
+}
+
std::pair<uint64_t, uint64_t>
ASTDeclReader::VisitDeclContext(DeclContext *DC) {
uint64_t LexicalOffset = Record[Idx++];
@@ -1563,7 +1561,8 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
// The result structure takes care to note that we need to load the
// other declaration chains for this ID.
- return RedeclarableResult(Reader, FirstDeclID);
+ return RedeclarableResult(Reader, FirstDeclID,
+ static_cast<T *>(D)->getKind());
}
/// \brief Attempts to merge the given declaration (D) with another declaration
@@ -1626,6 +1625,17 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
}
}
+void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ VisitDecl(D);
+ unsigned NumVars = D->varlist_size();
+ SmallVector<DeclRefExpr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i) {
+ Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F)));
+ }
+ D->setVars(Vars);
+}
+
//===----------------------------------------------------------------------===//
// Attribute Reading
//===----------------------------------------------------------------------===//
@@ -1811,6 +1821,30 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
if (DC->isTranslationUnit() && Reader.SemaObj) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
+
+ // Temporarily consider the identifier to be up-to-date. We don't want to
+ // cause additional lookups here.
+ class UpToDateIdentifierRAII {
+ IdentifierInfo *II;
+ bool WasOutToDate;
+
+ public:
+ explicit UpToDateIdentifierRAII(IdentifierInfo *II)
+ : II(II), WasOutToDate(false)
+ {
+ if (II) {
+ WasOutToDate = II->isOutOfDate();
+ if (WasOutToDate)
+ II->setOutOfDate(false);
+ }
+ }
+
+ ~UpToDateIdentifierRAII() {
+ if (WasOutToDate)
+ II->setOutOfDate(true);
+ }
+ } UpToDate(Name.getAsIdentifierInfo());
+
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
IEnd = IdResolver.end();
I != IEnd; ++I) {
@@ -1820,10 +1854,11 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
}
if (DC->isNamespace()) {
- for (DeclContext::lookup_result R = DC->lookup(Name);
- R.first != R.second; ++R.first) {
- if (isSameEntity(*R.first, D))
- return FindExistingResult(Reader, D, *R.first);
+ DeclContext::lookup_result R = DC->lookup(Name);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ if (isSameEntity(*I, D))
+ return FindExistingResult(Reader, D, *I);
}
}
@@ -1937,7 +1972,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx);
Decl *D = 0;
- switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
+ switch ((DeclCode)DeclsCursor.readRecord(Code, Record)) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
@@ -2005,7 +2040,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
D = AccessSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND:
- D = FriendDecl::CreateDeserialized(Context, ID);
+ D = FriendDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
case DECL_FRIEND_TEMPLATE:
D = FriendTemplateDecl::CreateDeserialized(Context, ID);
@@ -2109,6 +2144,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// locations.
D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
break;
+ case DECL_OMP_THREADPRIVATE:
+ D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]);
+ break;
+ case DECL_EMPTY:
+ D = EmptyDecl::CreateDeserialized(Context, ID);
+ break;
}
assert(D && "Unknown declaration reading AST file");
@@ -2122,12 +2163,18 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// If this declaration is also a declaration context, get the
// offsets for its tables of lexical and visible declarations.
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ // FIXME: This should really be
+ // DeclContext *LookupDC = DC->getPrimaryContext();
+ // but that can walk the redeclaration chain, which might not work yet.
+ DeclContext *LookupDC = DC;
+ if (isa<NamespaceDecl>(DC))
+ LookupDC = DC->getPrimaryContext();
std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
if (Offsets.first || Offsets.second) {
if (Offsets.first != 0)
DC->setHasExternalLexicalStorage(true);
if (Offsets.second != 0)
- DC->setHasExternalVisibleStorage(true);
+ LookupDC->setHasExternalVisibleStorage(true);
if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets,
Loc.F->DeclContextInfos[DC]))
return 0;
@@ -2139,7 +2186,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
if (I != PendingVisibleUpdates.end()) {
// There are updates. This means the context has external visible
// storage, even if the original stored version didn't.
- DC->setHasExternalVisibleStorage(true);
+ LookupDC->setHasExternalVisibleStorage(true);
DeclContextVisibleUpdates &U = I->second;
for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
UI != UE; ++UI) {
@@ -2149,9 +2196,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
}
PendingVisibleUpdates.erase(I);
}
-
- if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
- DC->setMustBuildLookupTable();
}
assert(Idx == Record.size());
@@ -2189,7 +2233,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
Cursor.JumpToBit(Offset);
RecordData Record;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record);
+ unsigned RecCode = Cursor.readRecord(Code, Record);
(void)RecCode;
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
@@ -2226,7 +2270,7 @@ namespace {
SmallVectorImpl<DeclID> &SearchDecls;
llvm::SmallPtrSet<Decl *, 16> &Deserialized;
GlobalDeclID CanonID;
- llvm::SmallVector<Decl *, 4> Chain;
+ SmallVector<Decl *, 4> Chain;
public:
RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
@@ -2307,7 +2351,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
Decl *CanonDecl = D->getCanonicalDecl();
// Determine the set of declaration IDs we'll be searching for.
- llvm::SmallVector<DeclID, 1> SearchDecls;
+ SmallVector<DeclID, 1> SearchDecls;
GlobalDeclID CanonID = 0;
if (D == CanonDecl) {
SearchDecls.push_back(ID); // Always first.
@@ -2404,7 +2448,7 @@ namespace {
if (Tail)
ASTDeclReader::setNextObjCCategory(Tail, Cat);
else
- Interface->setCategoryList(Cat);
+ Interface->setCategoryListRaw(Cat);
Tail = Cat;
}
@@ -2419,13 +2463,15 @@ namespace {
Tail(0)
{
// Populate the name -> category map with the set of known categories.
- for (ObjCCategoryDecl *Cat = Interface->getCategoryList(); Cat;
- Cat = Cat->getNextClassCategory()) {
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Interface->known_categories_begin(),
+ CatEnd = Interface->known_categories_end();
+ Cat != CatEnd; ++Cat) {
if (Cat->getDeclName())
- NameCategoryMap[Cat->getDeclName()] = Cat;
+ NameCategoryMap[Cat->getDeclName()] = *Cat;
// Keep track of the tail of the category list.
- Tail = Cat;
+ Tail = *Cat;
}
}
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index e5159e952635..327da4403a3a 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -13,17 +13,19 @@
#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/AST/DeclarationName.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Serialization/ASTBitCodes.h"
#include "llvm/Support/Endian.h"
-#include <utility>
#include <sys/stat.h>
+#include <utility>
namespace clang {
class ASTReader;
class HeaderSearch;
struct HeaderFileInfo;
+class FileEntry;
namespace serialization {
@@ -77,8 +79,43 @@ public:
unsigned DataLen);
};
+/// \brief Base class for the trait describing the on-disk hash table for the
+/// identifiers in an AST file.
+///
+/// This class is not useful by itself; rather, it provides common
+/// functionality for accessing the on-disk hash table of identifiers
+/// in an AST file. Different subclasses customize that functionality
+/// based on what information they are interested in. Those subclasses
+/// must provide the \c data_type typedef and the ReadData operation,
+/// only.
+class ASTIdentifierLookupTraitBase {
+public:
+ typedef StringRef external_key_type;
+ typedef StringRef internal_key_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 std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const external_key_type&
+ GetExternalKey(const internal_key_type& x) { return x; }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned n);
+};
+
/// \brief Class that performs lookup for an identifier stored in an AST file.
-class ASTIdentifierLookupTrait {
+class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase {
ASTReader &Reader;
ModuleFile &F;
@@ -90,42 +127,15 @@ class ASTIdentifierLookupTrait {
public:
typedef IdentifierInfo * data_type;
- typedef const std::pair<const char*, unsigned> external_key_type;
-
- typedef external_key_type internal_key_type;
-
ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F,
IdentifierInfo *II = 0)
: Reader(Reader), F(F), KnownII(II) { }
-
- static bool EqualKey(const internal_key_type& a,
- const internal_key_type& b) {
- return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0
- : false;
- }
-
- static unsigned ComputeHash(const internal_key_type& a);
-
- // This hopefully will just get inlined and removed by the optimizer.
- static const internal_key_type&
- GetInternalKey(const external_key_type& x) { return x; }
-
- // This hopefully will just get inlined and removed by the optimizer.
- static const external_key_type&
- GetExternalKey(const internal_key_type& x) { return x; }
-
- static std::pair<unsigned, unsigned>
- ReadKeyDataLength(const unsigned char*& d);
-
- static std::pair<const char*, unsigned>
- ReadKey(const unsigned char* d, unsigned n);
-
- IdentifierInfo *ReadData(const internal_key_type& k,
- const unsigned char* d,
- unsigned DataLen);
+
+ data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen);
ASTReader &getReader() const { return Reader; }
-
};
/// \brief The on-disk hash table used to contain information about
@@ -142,8 +152,8 @@ class ASTSelectorLookupTrait {
public:
struct data_type {
SelectorID ID;
- llvm::SmallVector<ObjCMethodDecl *, 2> Instance;
- llvm::SmallVector<ObjCMethodDecl *, 2> Factory;
+ SmallVector<ObjCMethodDecl *, 2> Instance;
+ SmallVector<ObjCMethodDecl *, 2> Factory;
};
typedef Selector external_key_type;
@@ -187,47 +197,33 @@ class HeaderFileInfoTrait {
ModuleFile &M;
HeaderSearch *HS;
const char *FrameworkStrings;
- const char *SearchPath;
- struct stat SearchPathStatBuf;
- llvm::Optional<int> SearchPathStatResult;
-
- int StatSimpleCache(const char *Path, struct stat *StatBuf) {
- if (Path == SearchPath) {
- if (!SearchPathStatResult)
- SearchPathStatResult = stat(Path, &SearchPathStatBuf);
-
- *StatBuf = SearchPathStatBuf;
- return *SearchPathStatResult;
- }
-
- return stat(Path, StatBuf);
- }
-
+
public:
- typedef const char *external_key_type;
- typedef const char *internal_key_type;
+ typedef const FileEntry *external_key_type;
+
+ struct internal_key_type {
+ off_t Size;
+ time_t ModTime;
+ const char *Filename;
+ };
+ typedef const internal_key_type &internal_key_ref;
typedef HeaderFileInfo data_type;
HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
- const char *FrameworkStrings,
- const char *SearchPath = 0)
- : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings),
- SearchPath(SearchPath) { }
+ const char *FrameworkStrings)
+ : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
- static unsigned ComputeHash(const char *path);
- static internal_key_type GetInternalKey(const char *path);
- bool EqualKey(internal_key_type a, internal_key_type b);
+ static unsigned ComputeHash(internal_key_ref ikey);
+ static internal_key_type GetInternalKey(const FileEntry *FE);
+ bool EqualKey(internal_key_ref a, internal_key_ref b);
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d);
- static internal_key_type ReadKey(const unsigned char *d, unsigned) {
- return (const char *)d;
- }
+ static internal_key_type ReadKey(const unsigned char *d, unsigned);
- data_type ReadData(const internal_key_type, const unsigned char *d,
- unsigned DataLen);
+ data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen);
};
/// \brief The on-disk hash table used for known header files.
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 367f75f55eb0..078ecb7a06d6 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -132,6 +132,8 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
void ASTStmtReader::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Reader.RecordSwitchCaseID(S, Record[Idx++]);
+ S->setKeywordLoc(ReadSourceLocation(Record, Idx));
+ S->setColonLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
@@ -139,16 +141,12 @@ void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
S->setLHS(Reader.ReadSubExpr());
S->setRHS(Reader.ReadSubExpr());
S->setSubStmt(Reader.ReadSubStmt());
- S->setCaseLoc(ReadSourceLocation(Record, Idx));
S->setEllipsisLoc(ReadSourceLocation(Record, Idx));
- S->setColonLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) {
VisitSwitchCase(S);
S->setSubStmt(Reader.ReadSubStmt());
- S->setDefaultLoc(ReadSourceLocation(Record, Idx));
- S->setColonLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
@@ -380,8 +378,10 @@ void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
VisitExpr(E);
- E->setValue(Reader.getContext(), Reader.ReadAPFloat(Record, Idx));
+ E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record[Idx++]));
E->setExact(Record[Idx++]);
+ E->setValue(Reader.getContext(),
+ Reader.ReadAPFloat(Record, E->getSemantics(), Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
}
@@ -528,6 +528,7 @@ void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
VisitExpr(E);
E->setBase(Reader.ReadSubExpr());
E->setIsaMemberLoc(ReadSourceLocation(Record, Idx));
+ E->setOpLoc(ReadSourceLocation(Record, Idx));
E->setArrow(Record[Idx++]);
}
@@ -892,6 +893,7 @@ void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
VisitExpr(E);
E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setOpLoc(ReadSourceLocation(Record, Idx));
E->setBase(Reader.ReadSubExpr());
E->setIsArrow(Record[Idx++]);
E->setIsFreeIvar(Record[Idx++]);
@@ -1102,6 +1104,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->setLocation(ReadSourceLocation(Record, Idx));
E->setElidable(Record[Idx++]);
E->setHadMultipleCandidates(Record[Idx++]);
+ E->setListInitialization(Record[Idx++]);
E->setRequiresZeroInitialization(Record[Idx++]);
E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
E->ParenRange = ReadSourceRange(Record, Idx);
@@ -1146,6 +1149,8 @@ void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
SourceRange R = ReadSourceRange(Record, Idx);
E->Loc = R.getBegin();
E->RParenLoc = R.getEnd();
+ R = ReadSourceRange(Record, Idx);
+ E->AngleBrackets = R;
}
void ASTStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
@@ -1596,36 +1601,27 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Stmt::EmptyShell Empty;
while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Cursor.ReadBlockEnd()) {
- Error("error at end of block in AST file");
- return 0;
- }
+ llvm::BitstreamEntry Entry = Cursor.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return 0;
+ case llvm::BitstreamEntry::EndBlock:
+ goto Done;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
break;
}
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return 0;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
- }
Stmt *S = 0;
Idx = 0;
Record.clear();
bool Finished = false;
bool IsStmtReference = false;
- switch ((StmtCode)Cursor.ReadRecord(Code, Record)) {
+ switch ((StmtCode)Cursor.readRecord(Entry.ID, Record)) {
case STMT_STOP:
Finished = true;
break;
@@ -1868,7 +1864,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_INIT_LIST:
- S = new (Context) InitListExpr(getContext(), Empty);
+ S = new (Context) InitListExpr(Empty);
break;
case EXPR_DESIGNATED_INIT:
@@ -2250,11 +2246,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
assert(Idx == Record.size() && "Invalid deserialization of statement");
StmtStack.push_back(S);
}
-
-#ifndef NDEBUG
+Done:
assert(StmtStack.size() > PrevNumStmts && "Read too many sub stmts!");
assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!");
-#endif
-
return StmtStack.pop_back_val();
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index a2e8b71123b1..cf93d1cf01a7 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -13,24 +13,15 @@
#include "clang/Serialization/ASTWriter.h"
#include "ASTCommon.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/IdentifierResolver.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclFriend.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/Serialization/ASTReader.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/OnDiskHashTable.h"
@@ -40,8 +31,18 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/FileSystem.h"
@@ -353,7 +354,7 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType(
void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
Writer.AddTypeRef(T->getPattern(), Record);
- if (llvm::Optional<unsigned> NumExpansions = T->getNumExpansions())
+ if (Optional<unsigned> NumExpansions = T->getNumExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
@@ -777,6 +778,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TARGET_OPTIONS);
RECORD(ORIGINAL_FILE);
RECORD(ORIGINAL_PCH_DIR);
+ RECORD(ORIGINAL_FILE_ID);
RECORD(INPUT_FILE_OFFSETS);
RECORD(DIAGNOSTIC_OPTIONS);
RECORD(FILE_SYSTEM_OPTIONS);
@@ -797,7 +799,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
RECORD(UNUSED_FILESCOPED_DECLS);
- RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
+ RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
RECORD(PP_COUNTER_VALUE);
@@ -823,6 +825,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
RECORD(KNOWN_NAMESPACES);
+ RECORD(UNDEFINED_BUT_USED);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
RECORD(OBJC_CATEGORIES_MAP);
@@ -832,7 +835,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
- RECORD(MACRO_UPDATES);
+ RECORD(MACRO_TABLE);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1020,7 +1023,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
// Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
- llvm::SmallVector<char, 128> ModulePaths;
+ SmallVector<char, 128> ModulePaths;
Record.clear();
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
@@ -1030,7 +1033,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
continue;
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
- // FIXME: Write import location, once it matters.
+ 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());
@@ -1047,12 +1052,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) Record.push_back(LangOpts.Sanitize.ID);
+#include "clang/Basic/Sanitizers.def"
Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
Record.push_back(LangOpts.CurrentModule.size());
Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
+
+ // Comment options.
+ Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size());
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = LangOpts.CommentOpts.BlockCommandNames.begin(),
+ IEnd = LangOpts.CommentOpts.BlockCommandNames.end();
+ I != IEnd; ++I) {
+ AddString(*I, Record);
+ }
+
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
// Target options.
@@ -1108,11 +1125,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
AddString(Entry.Path, Record);
Record.push_back(static_cast<unsigned>(Entry.Group));
- Record.push_back(Entry.IsUserSupplied);
Record.push_back(Entry.IsFramework);
Record.push_back(Entry.IgnoreSysRoot);
- Record.push_back(Entry.IsInternal);
- Record.push_back(Entry.ImplicitExternC);
}
// System header prefixes.
@@ -1180,6 +1194,10 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
+ Record.clear();
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
+
// Original PCH directory
if (!OutputFile.empty() && OutputFile != "-") {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
@@ -1197,11 +1215,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
- WriteInputFiles(Context.SourceMgr, isysroot);
+ WriteInputFiles(Context.SourceMgr,
+ PP.getHeaderSearchInfo().getHeaderSearchOpts(),
+ isysroot);
Stream.ExitBlock();
}
-void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
+namespace {
+ /// \brief An input file.
+ struct InputFileEntry {
+ const FileEntry *File;
+ bool IsSystemFile;
+ bool BufferOverridden;
+ };
+}
+
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
+ HeaderSearchOptions &HSOpts,
+ StringRef isysroot) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
@@ -1216,8 +1247,9 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
- // Write out all of the input files.
- std::vector<uint32_t> InputFileOffsets;
+ // Get all ContentCache objects for files, sorted by whether the file is a
+ // system one or not. System files go at the back, users files at the front.
+ std::deque<InputFileEntry> SortedFiles;
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
@@ -1230,28 +1262,67 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
if (!Cache->OrigEntry)
continue;
+ InputFileEntry Entry;
+ Entry.File = Cache->OrigEntry;
+ Entry.IsSystemFile = Cache->IsSystemFile;
+ Entry.BufferOverridden = Cache->BufferOverridden;
+ if (Cache->IsSystemFile)
+ SortedFiles.push_back(Entry);
+ else
+ 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);
+ }
+ }
+
+ unsigned UserFilesNum = 0;
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ for (std::deque<InputFileEntry>::iterator
+ I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
+ const InputFileEntry &Entry = *I;
+
+ uint32_t &InputFileID = InputFileIDs[Entry.File];
+ if (InputFileID != 0)
+ continue; // already recorded this file.
+
// Record this entry's offset.
InputFileOffsets.push_back(Stream.GetCurrentBitNo());
- InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size();
+
+ InputFileID = InputFileOffsets.size();
+
+ if (!Entry.IsSystemFile)
+ ++UserFilesNum;
Record.clear();
Record.push_back(INPUT_FILE);
Record.push_back(InputFileOffsets.size());
// Emit size/modification time for this file.
- Record.push_back(Cache->OrigEntry->getSize());
- Record.push_back(Cache->OrigEntry->getModificationTime());
+ Record.push_back(Entry.File->getSize());
+ Record.push_back(Entry.File->getModificationTime());
// Whether this file was overridden.
- Record.push_back(Cache->BufferOverridden);
+ Record.push_back(Entry.BufferOverridden);
// Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Cache->OrigEntry->getName();
+ const char *Filename = Entry.File->getName();
SmallString<128> FilePath(Filename);
// Ask the file manager to fixup the relative path for us. This will
// honor the working directory.
- SourceMgr.getFileManager().FixupRelativePath(FilePath);
+ FileMgr.FixupRelativePath(FilePath);
// FIXME: This call to make_absolute shouldn't be necessary, the
// call to FixupRelativePath should always return an absolute path.
@@ -1262,13 +1333,15 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
}
-
+
Stream.ExitBlock();
// Create input file offsets abbreviation.
BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system
+ // input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
@@ -1276,58 +1349,11 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Record.clear();
Record.push_back(INPUT_FILE_OFFSETS);
Record.push_back(InputFileOffsets.size());
+ Record.push_back(UserFilesNum);
Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
//===----------------------------------------------------------------------===//
-// stat cache Serialization
-//===----------------------------------------------------------------------===//
-
-namespace {
-// Trait used for the on-disk hash table of stat cache results.
-class ASTStatCacheTrait {
-public:
- typedef const char * key_type;
- typedef key_type key_type_ref;
-
- typedef struct stat data_type;
- typedef const data_type &data_type_ref;
-
- static unsigned ComputeHash(const char *path) {
- return llvm::HashString(path);
- }
-
- std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
- unsigned DataLen = 4 + 4 + 2 + 8 + 8;
- clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
- }
-
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
- }
-
- void EmitData(raw_ostream &Out, key_type_ref,
- data_type_ref Data, unsigned DataLen) {
- using namespace clang::io;
- uint64_t Start = Out.tell(); (void)Start;
-
- Emit32(Out, (uint32_t) Data.st_ino);
- Emit32(Out, (uint32_t) Data.st_dev);
- Emit16(Out, (uint16_t) Data.st_mode);
- Emit64(Out, (uint64_t) Data.st_mtime);
- Emit64(Out, (uint64_t) Data.st_size);
-
- assert(Out.tell() - Start == DataLen && "Wrong data length");
- }
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
// Source Manager Serialization
//===----------------------------------------------------------------------===//
@@ -1391,44 +1417,53 @@ namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
+ const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
- HeaderFileInfoTrait(ASTWriter &Writer)
- : Writer(Writer) { }
+ HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
+ : Writer(Writer), HS(HS) { }
- typedef const char *key_type;
- typedef key_type key_type_ref;
+ struct key_type {
+ const FileEntry *FE;
+ const char *Filename;
+ };
+ typedef const key_type &key_type_ref;
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
- static unsigned ComputeHash(const char *path) {
- // The hash is based only on the filename portion of the key, so that the
- // reader can match based on filenames when symlinking or excess path
- // elements ("foo/../", "../") change the form of the name. However,
- // complete path is still the key.
- return llvm::HashString(llvm::sys::path::filename(path));
+ static unsigned 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.
+ return llvm::hash_combine(key.FE->getSize(),
+ key.FE->getModificationTime());
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
+ unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
+ clang::io::Emit16(Out, KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
+ if (Data.isModuleHeader)
+ DataLen += 4;
clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
+ void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
+ clang::io::Emit64(Out, key.FE->getSize());
+ KeyLen -= 8;
+ clang::io::Emit64(Out, key.FE->getModificationTime());
+ KeyLen -= 8;
+ Out.write(key.Filename, KeyLen);
}
- void EmitData(raw_ostream &Out, key_type_ref,
+ void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start;
@@ -1462,7 +1497,12 @@ namespace {
Offset = Pos->second;
}
Emit32(Out, Offset);
-
+
+ if (Data.isModuleHeader) {
+ Module *Mod = HS.findModuleForHeader(key.FE);
+ Emit32(Out, Writer.getExistingSubmoduleID(Mod));
+ }
+
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
@@ -1481,7 +1521,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
- HeaderFileInfoTrait GeneratorTrait(*this);
+ HeaderFileInfoTrait GeneratorTrait(*this, HS);
OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
@@ -1507,7 +1547,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SavedStrings.push_back(Filename);
}
- Generator.insert(Filename, HFI, GeneratorTrait);
+ HeaderFileInfoTrait::key_type key = { File, Filename };
+ Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
}
@@ -1542,7 +1583,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
// Free all of the strings we had to duplicate.
for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
- free((void*)SavedStrings[I]);
+ free(const_cast<char *>(SavedStrings[I]));
}
/// \brief Writes the block containing the serialized form of the
@@ -1746,14 +1787,67 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Preprocessor Serialization
//===----------------------------------------------------------------------===//
-static int compareMacroDefinitions(const void *XPtr, const void *YPtr) {
- const std::pair<const IdentifierInfo *, MacroInfo *> &X =
- *(const std::pair<const IdentifierInfo *, MacroInfo *>*)XPtr;
- const std::pair<const IdentifierInfo *, MacroInfo *> &Y =
- *(const std::pair<const IdentifierInfo *, MacroInfo *>*)YPtr;
+namespace {
+class ASTMacroTableTrait {
+public:
+ typedef IdentID key_type;
+ typedef key_type key_type_ref;
+
+ struct Data {
+ uint32_t MacroDirectivesOffset;
+ };
+
+ typedef Data data_type;
+ typedef const data_type &data_type_ref;
+
+ static unsigned ComputeHash(IdentID IdID) {
+ return llvm::hash_value(IdID);
+ }
+
+ std::pair<unsigned,unsigned>
+ static EmitKeyDataLength(raw_ostream& Out,
+ key_type_ref Key, data_type_ref Data) {
+ unsigned KeyLen = 4; // IdentID.
+ unsigned DataLen = 4; // MacroDirectivesOffset.
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
+ clang::io::Emit32(Out, Key);
+ }
+
+ static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
+ unsigned) {
+ clang::io::Emit32(Out, Data.MacroDirectivesOffset);
+ }
+};
+} // end anonymous namespace
+
+static int compareMacroDirectives(const void *XPtr, const void *YPtr) {
+ const std::pair<const IdentifierInfo *, MacroDirective *> &X =
+ *(const std::pair<const IdentifierInfo *, MacroDirective *>*)XPtr;
+ const std::pair<const IdentifierInfo *, MacroDirective *> &Y =
+ *(const std::pair<const IdentifierInfo *, MacroDirective *>*)YPtr;
return X.first->getName().compare(Y.first->getName());
}
+static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
+ const Preprocessor &PP) {
+ if (MacroInfo *MI = MD->getMacroInfo())
+ if (MI->isBuiltinMacro())
+ return true;
+
+ if (IsModule) {
+ SourceLocation Loc = MD->getLocation();
+ if (Loc.isInvalid())
+ return true;
+ if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID())
+ return true;
+ }
+
+ return false;
+}
+
/// \brief Writes the block containing the serialized form of the
/// preprocessor.
///
@@ -1780,26 +1874,73 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
- // Loop over all the macro definitions that are live at the end of the file,
+ // Loop over all the macro directives that are live at the end of the file,
// emitting each to the PP section.
- // Construct the list of macro definitions that need to be serialized.
- SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
- MacrosToEmit;
- llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
- for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
- E = PP.macro_end(Chain == 0);
+ // Construct the list of macro directives that need to be serialized.
+ SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2>
+ MacroDirectives;
+ for (Preprocessor::macro_iterator
+ I = PP.macro_begin(/*IncludeExternalMacros=*/false),
+ E = PP.macro_end(/*IncludeExternalMacros=*/false);
I != E; ++I) {
- if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(I->first);
- MacrosToEmit.push_back(std::make_pair(I->first, I->second));
- }
+ MacroDirectives.push_back(std::make_pair(I->first, I->second));
}
// Sort the set of macro definitions that need to be serialized by the
// name of the macro, to provide a stable ordering.
- llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(),
- &compareMacroDefinitions);
+ llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
+ &compareMacroDirectives);
+
+ OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
+
+ // Emit the macro directives as a list and associate the offset with the
+ // identifier they belong to.
+ for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroDirectives[I].first;
+ uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo();
+ MacroDirective *MD = MacroDirectives[I].second;
+
+ // If the macro or identifier need no updates, don't write the macro history
+ // for this one.
+ // FIXME: Chain the macro history instead of re-writing it.
+ if (MD->isFromPCH() &&
+ Name->isFromAST() && !Name->hasChangedSinceDeserialization())
+ continue;
+
+ // Emit the macro directives in reverse source order.
+ for (; MD; MD = MD->getPrevious()) {
+ if (MD->isHidden())
+ continue;
+ if (shouldIgnoreMacro(MD, IsModule, PP))
+ continue;
+
+ AddSourceLocation(MD->getLocation(), Record);
+ Record.push_back(MD->getKind());
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ MacroID InfoID = getMacroRef(DefMD->getInfo(), Name);
+ Record.push_back(InfoID);
+ Record.push_back(DefMD->isImported());
+ Record.push_back(DefMD->isAmbiguous());
+
+ } else if (VisibilityMacroDirective *
+ VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
+ Record.push_back(VisMD->isPublic());
+ }
+ }
+ if (Record.empty())
+ continue;
+
+ Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record);
+ Record.clear();
+
+ IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset;
+
+ IdentID NameID = getIdentifierRef(Name);
+ ASTMacroTableTrait::Data data;
+ data.MacroDirectivesOffset = MacroDirectiveOffset;
+ Generator.insert(NameID, data);
+ }
/// \brief Offsets of each of the macros into the bitstream, indexed by
/// the local macro ID
@@ -1809,95 +1950,107 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
/// defined.
std::vector<uint32_t> MacroOffsets;
- for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) {
- const IdentifierInfo *Name = MacrosToEmit[I].first;
+ for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroInfosToEmit[I].Name;
+ MacroInfo *MI = MacroInfosToEmit[I].MI;
+ MacroID ID = MacroInfosToEmit[I].ID;
- for (MacroInfo *MI = MacrosToEmit[I].second; MI;
- MI = MI->getPreviousDefinition()) {
- MacroID ID = getMacroRef(MI);
- if (!ID)
- continue;
+ if (ID < FirstMacroID) {
+ assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?");
+ continue;
+ }
- // Skip macros from a AST file if we're chaining.
- if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad())
- continue;
+ // Record the local offset of this macro.
+ unsigned Index = ID - FirstMacroID;
+ if (Index == MacroOffsets.size())
+ MacroOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > MacroOffsets.size())
+ MacroOffsets.resize(Index + 1);
- if (ID < FirstMacroID) {
- // This will have been dealt with via an update record.
- assert(MacroUpdates.count(MI) > 0 && "Missing macro update");
- continue;
- }
+ MacroOffsets[Index] = Stream.GetCurrentBitNo();
+ }
- // Record the local offset of this macro.
- unsigned Index = ID - FirstMacroID;
- if (Index == MacroOffsets.size())
- MacroOffsets.push_back(Stream.GetCurrentBitNo());
- else {
- if (Index > MacroOffsets.size())
- MacroOffsets.resize(Index + 1);
+ AddIdentifierRef(Name, Record);
+ Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
+ AddSourceLocation(MI->getDefinitionLoc(), Record);
+ AddSourceLocation(MI->getDefinitionEndLoc(), Record);
+ Record.push_back(MI->isUsed());
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = PP_MACRO_FUNCTION_LIKE;
- MacroOffsets[Index] = Stream.GetCurrentBitNo();
- }
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->hasCommaPasting());
+ Record.push_back(MI->getNumArgs());
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ AddIdentifierRef(*I, Record);
+ }
- AddIdentifierRef(Name, Record);
- addMacroRef(MI, Record);
- Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
- AddSourceLocation(MI->getDefinitionLoc(), Record);
- AddSourceLocation(MI->getUndefLoc(), Record);
- Record.push_back(MI->isUsed());
- Record.push_back(MI->isPublic());
- AddSourceLocation(MI->getVisibilityLocation(), Record);
- unsigned Code;
- if (MI->isObjectLike()) {
- Code = PP_MACRO_OBJECT_LIKE;
- } else {
- Code = PP_MACRO_FUNCTION_LIKE;
-
- Record.push_back(MI->isC99Varargs());
- Record.push_back(MI->isGNUVarargs());
- Record.push_back(MI->getNumArgs());
- for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
- I != E; ++I)
- AddIdentifierRef(*I, Record);
- }
+ // If we have a detailed preprocessing record, record the macro definition
+ // ID that corresponds to this macro.
+ if (PPRec)
+ Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
- // If we have a detailed preprocessing record, record the macro definition
- // ID that corresponds to this macro.
- if (PPRec)
- Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
+ Stream.EmitRecord(Code, Record);
+ Record.clear();
- Stream.EmitRecord(Code, Record);
+ // Emit the tokens array.
+ for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
+ // Note that we know that the preprocessor does not have any annotation
+ // tokens in it because they are created by the parser, and thus can't
+ // be in a macro definition.
+ const Token &Tok = MI->getReplacementToken(TokNo);
+
+ Record.push_back(Tok.getLocation().getRawEncoding());
+ Record.push_back(Tok.getLength());
+
+ // FIXME: When reading literal tokens, reconstruct the literal pointer
+ // if it is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+ // FIXME: Should translate token kind to a stable encoding.
+ Record.push_back(Tok.getKind());
+ // FIXME: Should translate token flags to a stable encoding.
+ Record.push_back(Tok.getFlags());
+
+ Stream.EmitRecord(PP_TOKEN, Record);
Record.clear();
-
- // Emit the tokens array.
- for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
- // Note that we know that the preprocessor does not have any annotation
- // tokens in it because they are created by the parser, and thus can't
- // be in a macro definition.
- const Token &Tok = MI->getReplacementToken(TokNo);
-
- Record.push_back(Tok.getLocation().getRawEncoding());
- Record.push_back(Tok.getLength());
-
- // FIXME: When reading literal tokens, reconstruct the literal pointer
- // if it is needed.
- AddIdentifierRef(Tok.getIdentifierInfo(), Record);
- // FIXME: Should translate token kind to a stable encoding.
- Record.push_back(Tok.getKind());
- // FIXME: Should translate token flags to a stable encoding.
- Record.push_back(Tok.getFlags());
-
- Stream.EmitRecord(PP_TOKEN, Record);
- Record.clear();
- }
- ++NumMacros;
}
+ ++NumMacros;
}
+
Stream.ExitBlock();
- // Write the offsets table for macro IDs.
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> MacroTable;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(MacroTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out);
+ }
+
+ // Write the macro table
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.push_back(MACRO_TABLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str());
+ Record.clear();
+
+ // Write the offsets table for macro IDs.
+ using namespace llvm;
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
@@ -2019,6 +2172,18 @@ unsigned ASTWriter::getSubmoduleID(Module *Mod) {
return SubmoduleIDs[Mod] = NextSubmoduleID++;
}
+unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const {
+ if (!Mod)
+ return 0;
+
+ llvm::DenseMap<Module *, unsigned>::const_iterator
+ Known = SubmoduleIDs.find(Mod);
+ if (Known != SubmoduleIDs.end())
+ return Known->second;
+
+ return 0;
+}
+
/// \brief Compute the number of modules within the given tree (including the
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
@@ -2062,6 +2227,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -2095,6 +2261,23 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
+ unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
+ unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2125,6 +2308,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
+ Record.push_back(Mod->ConfigMacrosExhaustive);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the requirements.
@@ -2163,11 +2347,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
Mod->ExcludedHeaders[I]->getName());
}
- for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
+ ArrayRef<const FileEntry *>
+ TopHeaders = Mod->getTopHeaders(PP->getFileManager());
+ for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_TOPHEADER);
Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
- Mod->TopHeaders[I]->getName());
+ TopHeaders[I]->getName());
}
// Emit the imports.
@@ -2197,7 +2383,35 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}
Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
}
-
+
+ // Emit the link libraries.
+ for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_LINK_LIBRARY);
+ Record.push_back(Mod->LinkLibraries[I].IsFramework);
+ Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record,
+ Mod->LinkLibraries[I].Library);
+ }
+
+ // Emit the conflicts.
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFLICT);
+ unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other);
+ assert(OtherID && "Unknown submodule!");
+ Record.push_back(OtherID);
+ Stream.EmitRecordWithBlob(ConflictAbbrev, Record,
+ Mod->Conflicts[I].Message);
+ }
+
+ // Emit the configuration macros.
+ for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFIG_MACRO);
+ Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record,
+ Mod->ConfigMacros[I]);
+ }
+
// Queue up the submodules of this module.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
@@ -2230,8 +2444,14 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
return getSubmoduleID(OwningMod);
}
-void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
- // FIXME: Make it work properly with modules.
+void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
+ bool isModule) {
+ // Make sure set diagnostic pragmas don't affect the translation unit that
+ // imports the module.
+ // FIXME: Make diagnostic pragma sections work properly with modules.
+ if (isModule)
+ return;
+
llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
DiagStateIDMap;
unsigned CurrID = 0;
@@ -2664,7 +2884,7 @@ class ASTIdentifierTableTrait {
/// \brief Determines whether this is an "interesting" identifier
/// that needs a full IdentifierInfo structure written into the hash
/// table.
- bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) {
+ bool isInterestingIdentifier(IdentifierInfo *II, MacroDirective *&Macro) {
if (II->isPoisoned() ||
II->isExtensionToken() ||
II->getObjCOrBuiltinID() ||
@@ -2675,16 +2895,101 @@ class ASTIdentifierTableTrait {
return hadMacroDefinition(II, Macro);
}
- bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
+ bool hadMacroDefinition(IdentifierInfo *II, MacroDirective *&Macro) {
if (!II->hadMacroDefinition())
return false;
- if (Macro || (Macro = PP.getMacroInfoHistory(II)))
- return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
+ if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) {
+ if (!IsModule)
+ return !shouldIgnoreMacro(Macro, IsModule, PP);
+ SubmoduleID ModID;
+ if (getFirstPublicSubmoduleMacro(Macro, ModID))
+ return true;
+ }
return false;
}
+ DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID) {
+ ModID = 0;
+ if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID))
+ if (!shouldIgnoreMacro(DefMD, IsModule, PP))
+ return DefMD;
+ return 0;
+ }
+
+ DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD,
+ SubmoduleID &ModID) {
+ if (DefMacroDirective *
+ DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID))
+ if (!shouldIgnoreMacro(DefMD, IsModule, PP))
+ return DefMD;
+ return 0;
+ }
+
+ /// \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,
+ /// will still be considered as defined/exported from submodule A.
+ DefMacroDirective *getPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID) {
+ if (!MD)
+ return 0;
+
+ SubmoduleID OrigModID = ModID;
+ bool isUndefined = false;
+ Optional<bool> isPublic;
+ for (; MD; MD = MD->getPrevious()) {
+ if (MD->isHidden())
+ continue;
+
+ SubmoduleID ThisModID = getSubmoduleID(MD);
+ if (ThisModID == 0) {
+ isUndefined = false;
+ isPublic = Optional<bool>();
+ continue;
+ }
+ if (ThisModID != ModID){
+ ModID = ThisModID;
+ isUndefined = false;
+ isPublic = Optional<bool>();
+ }
+ // 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;
+ }
+
+ VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
+ if (!isPublic.hasValue())
+ isPublic = VisMD->isPublic();
+ }
+
+ return 0;
+ }
+
+ 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());
+ }
+
public:
typedef IdentifierInfo* key_type;
typedef key_type key_type_ref;
@@ -2704,17 +3009,21 @@ public:
EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
unsigned KeyLen = II->getLength() + 1;
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
- MacroInfo *Macro = 0;
+ MacroDirective *Macro = 0;
if (isInterestingIdentifier(II, Macro)) {
DataLen += 2; // 2 bytes for builtin ID
DataLen += 2; // 2 bytes for flags
if (hadMacroDefinition(II, Macro)) {
- for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
- if (Writer.getMacroRef(M) != 0)
- DataLen += 4;
+ DataLen += 4; // MacroDirectives offset.
+ if (IsModule) {
+ SubmoduleID ModID;
+ for (DefMacroDirective *
+ DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
+ DataLen += 4; // MacroInfo ID.
+ }
+ DataLen += 4;
}
-
- DataLen += 4;
}
for (IdentifierResolver::iterator D = IdResolver.begin(II),
@@ -2740,7 +3049,7 @@ public:
void EmitData(raw_ostream& Out, IdentifierInfo* II,
IdentID ID, unsigned) {
- MacroInfo *Macro = 0;
+ MacroDirective *Macro = 0;
if (!isInterestingIdentifier(II, Macro)) {
clang::io::Emit32(Out, ID << 1);
return;
@@ -2753,6 +3062,7 @@ public:
Bits = 0;
bool HadMacroDefinition = hadMacroDefinition(II, Macro);
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
+ Bits = (Bits << 1) | unsigned(IsModule);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
@@ -2760,13 +3070,19 @@ public:
clang::io::Emit16(Out, Bits);
if (HadMacroDefinition) {
- // Write all of the macro IDs associated with this identifier.
- for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
- if (MacroID ID = Writer.getMacroRef(M))
- clang::io::Emit32(Out, ID);
+ clang::io::Emit32(Out, 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);
+ }
+ clang::io::Emit32(Out, 0);
}
-
- clang::io::Emit32(Out, 0);
}
// Emit the declaration IDs in reverse order, because the
@@ -2820,7 +3136,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
assert(ID->first && "NULL identifier in identifier table");
if (!Chain || !ID->first->isFromAST() ||
ID->first->hasChangedSinceDeserialization())
- Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
+ Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
Trait);
}
@@ -2857,6 +3173,11 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+#ifndef NDEBUG
+ for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I)
+ assert(IdentifierOffsets[I] && "Missing identifier offset?");
+#endif
+
RecordData Record;
Record.push_back(IDENTIFIER_OFFSET);
Record.push_back(IdentifierOffsets.size());
@@ -2936,7 +3257,7 @@ public:
clang::io::Emit16(Out, KeyLen);
// 2 bytes for num of decls and 4 for each DeclID.
- unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first);
+ unsigned DataLen = 2 + 4 * Lookup.size();
clang::io::Emit16(Out, DataLen);
return std::make_pair(KeyLen, DataLen);
@@ -2976,9 +3297,10 @@ public:
void EmitData(raw_ostream& Out, key_type_ref,
data_type Lookup, unsigned DataLen) {
uint64_t Start = Out.tell(); (void)Start;
- clang::io::Emit16(Out, Lookup.second - Lookup.first);
- for (; Lookup.first != Lookup.second; ++Lookup.first)
- clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first));
+ clang::io::Emit16(Out, Lookup.size());
+ for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
+ I != E; ++I)
+ clang::io::Emit32(Out, Writer.GetDeclRef(*I));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -3002,8 +3324,6 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// If not in C++, we perform name lookup for the translation unit via the
// IdentifierInfo chains, don't bother to build a visible-declarations table.
- // FIXME: In C++ we need the visible declarations in order to "see" the
- // friend declarations, is there a way to do this without writing the table ?
if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus)
return 0;
@@ -3022,12 +3342,12 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// Create the on-disk hash table representation.
DeclarationName ConversionName;
- llvm::SmallVector<NamedDecl *, 4> ConversionDecls;
+ 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.first != Result.second) {
+ 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
@@ -3036,7 +3356,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// functions under a single key.
if (!ConversionName)
ConversionName = Name;
- ConversionDecls.append(Result.first, Result.second);
+ ConversionDecls.append(Result.begin(), Result.end());
continue;
}
@@ -3095,7 +3415,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
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.first != Result.second)
+ if (!Result.empty())
Generator.insert(Name, Result, Trait);
}
@@ -3156,20 +3476,32 @@ void ASTWriter::WriteRedeclarations() {
LocalRedeclChains.push_back(0); // Placeholder for the size.
// Collect the set of local redeclarations of this declaration.
- for (Decl *Prev = MostRecent; Prev != First;
+ for (Decl *Prev = MostRecent; Prev != First;
Prev = Prev->getPreviousDecl()) {
if (!Prev->isFromASTFile()) {
AddDeclRef(Prev, LocalRedeclChains);
++Size;
}
}
+
+ if (!First->isFromASTFile() && Chain) {
+ Decl *FirstFromAST = MostRecent;
+ for (Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) {
+ if (Prev->isFromASTFile())
+ FirstFromAST = Prev;
+ }
+
+ Chain->MergedDecls[FirstFromAST].push_back(getDeclID(First));
+ }
+
LocalRedeclChains[Offset] = Size;
// Reverse the set of local redeclarations, so that we store them in
// order (since we found them in reverse order).
std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
- // Add the mapping from the first ID to the set of local declarations.
+ // Add the mapping from the first ID from the AST to the set of local
+ // declarations.
LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
LocalRedeclsMap.push_back(Info);
@@ -3204,7 +3536,7 @@ void ASTWriter::WriteRedeclarations() {
}
void ASTWriter::WriteObjCCategories() {
- llvm::SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
+ SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
RecordData Categories;
for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) {
@@ -3217,10 +3549,12 @@ void ASTWriter::WriteObjCCategories() {
Categories.push_back(0);
// Add the categories.
- for (ObjCCategoryDecl *Cat = Class->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory(), ++Size) {
- assert(getDeclID(Cat) != 0 && "Bogus category");
- AddDeclRef(Cat, Categories);
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat, ++Size) {
+ assert(getDeclID(*Cat) != 0 && "Bogus category");
+ AddDeclRef(*Cat, Categories);
}
// Update the size.
@@ -3300,11 +3634,11 @@ void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
void ASTWriter::AddVersionTuple(const VersionTuple &Version,
RecordDataImpl &Record) {
Record.push_back(Version.getMajor());
- if (llvm::Optional<unsigned> Minor = Version.getMinor())
+ if (Optional<unsigned> Minor = Version.getMinor())
Record.push_back(*Minor + 1);
else
Record.push_back(0);
- if (llvm::Optional<unsigned> Subminor = Version.getSubminor())
+ if (Optional<unsigned> Subminor = Version.getSubminor())
Record.push_back(*Subminor + 1);
else
Record.push_back(0);
@@ -3405,6 +3739,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Module *WritingModule) {
using namespace llvm;
+ bool isModule = WritingModule != 0;
+
// Make sure that the AST reader knows to finalize itself.
if (Chain)
Chain->finalizeForWriting();
@@ -3447,11 +3783,19 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// If there are any out-of-date identifiers, bring them up to date.
if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) {
+ // Find out-of-date identifiers.
+ SmallVector<IdentifierInfo *, 4> OutOfDate;
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
IDEnd = PP.getIdentifierTable().end();
- ID != IDEnd; ++ID)
+ ID != IDEnd; ++ID) {
if (ID->second->isOutOfDate())
- ExtSource->updateOutOfDateIdentifier(*ID->second);
+ OutOfDate.push_back(ID->second);
+ }
+
+ // Update the out-of-date identifiers.
+ for (unsigned I = 0, N = OutOfDate.size(); I != N; ++I) {
+ ExtSource->updateOutOfDateIdentifier(*OutOfDate[I]);
+ }
}
// Build a record containing all of the tentative definitions in this file, in
@@ -3462,13 +3806,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Build a record containing all of the file scoped decls in this file.
RecordData UnusedFileScopedDecls;
- AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
- UnusedFileScopedDecls);
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
+ UnusedFileScopedDecls);
// Build a record containing all of the delegating constructors we still need
// to resolve.
RecordData DelegatingCtorDecls;
- AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
// Write the set of weak, undeclared identifiers. We always write the
// entire table, since later PCH files in a PCH chain are only interested in
@@ -3485,18 +3831,18 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- // Build a record containing all of the locally-scoped external
+ // Build a record containing all of the locally-scoped extern "C"
// declarations in this header file. Generally, this record will be
// empty.
- RecordData LocallyScopedExternalDecls;
+ RecordData LocallyScopedExternCDecls;
// FIXME: This is filling in the AST file in densemap order which is
// nondeterminstic!
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- TD = SemaRef.LocallyScopedExternalDecls.begin(),
- TDEnd = SemaRef.LocallyScopedExternalDecls.end();
+ TD = SemaRef.LocallyScopedExternCDecls.begin(),
+ TDEnd = SemaRef.LocallyScopedExternCDecls.end();
TD != TDEnd; ++TD) {
if (!TD->second->isFromASTFile())
- AddDeclRef(TD->second, LocallyScopedExternalDecls);
+ AddDeclRef(TD->second, LocallyScopedExternCDecls);
}
// Build a record containing all of the ext_vector declarations.
@@ -3542,7 +3888,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Build a record containing all of the known namespaces.
RecordData KnownNamespaces;
- for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
I = SemaRef.KnownNamespaces.begin(),
IEnd = SemaRef.KnownNamespaces.end();
I != IEnd; ++I) {
@@ -3550,6 +3896,17 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
AddDeclRef(I->first, KnownNamespaces);
}
+ // Build a record of all used, undefined objects that require definitions.
+ RecordData UndefinedButUsed;
+
+ SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
+ SemaRef.getUndefinedButUsed(Undefined);
+ for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
+ I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
+ AddDeclRef(I->first, UndefinedButUsed);
+ AddSourceLocation(I->second, UndefinedButUsed);
+ }
+
// Write the control block
WriteControlBlock(PP, Context, isysroot, OutputFile);
@@ -3557,6 +3914,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
+ // This is so that older clang versions, before the introduction
+ // of the control block, can read and reject the newer PCH format.
+ Record.clear();
+ Record.push_back(VERSION_MAJOR);
+ Stream.EmitRecord(METADATA_OLD_FORMAT, Record);
+
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
@@ -3686,16 +4049,16 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
Buffer.data(), Buffer.size());
}
- WritePreprocessor(PP, WritingModule != 0);
+ WritePreprocessor(PP, isModule);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);
WriteReferencedSelectorsPool(SemaRef);
- WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0);
+ WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);
WriteFPPragmaOptions(SemaRef.getFPOptions());
WriteOpenCLExtensions(SemaRef);
WriteTypeDeclOffsets();
- WritePragmaDiagnosticMappings(Context.getDiagnostics());
+ WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
WriteCXXBaseSpecifiersOffsets();
@@ -3722,10 +4085,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
WeakUndeclaredIdentifiers);
- // Write the record containing locally-scoped external definitions.
- if (!LocallyScopedExternalDecls.empty())
- Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS,
- LocallyScopedExternalDecls);
+ // Write the record containing locally-scoped extern "C" definitions.
+ if (!LocallyScopedExternCDecls.empty())
+ Stream.EmitRecord(LOCALLY_SCOPED_EXTERN_C_DECLS,
+ LocallyScopedExternCDecls);
// Write the record containing ext_vector type names.
if (!ExtVectorDecls.empty())
@@ -3758,6 +4121,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Write the known namespaces.
if (!KnownNamespaces.empty())
Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+
+ // Write the undefined internal functions and variables, and inline functions.
+ if (!UndefinedButUsed.empty())
+ Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
// Write the visible updates to DeclContexts.
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
@@ -3788,11 +4155,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- WriteMacroUpdates();
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
- WriteMergedDecls();
WriteRedeclarations();
+ WriteMergedDecls();
WriteObjCCategories();
// Some simple statistics
@@ -3805,21 +4171,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.ExitBlock();
}
-void ASTWriter::WriteMacroUpdates() {
- if (MacroUpdates.empty())
- return;
-
- RecordData Record;
- for (MacroUpdatesMap::iterator I = MacroUpdates.begin(),
- E = MacroUpdates.end();
- I != E; ++I) {
- addMacroRef(I->first, Record);
- AddSourceLocation(I->second.UndefLoc, Record);
- Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc));
- }
- Stream.EmitRecord(MACRO_UPDATES, Record);
-}
-
/// \brief Go through the declaration update blocks and resolve declaration
/// pointers into declaration IDs.
void ASTWriter::ResolveDeclUpdatesBlocks() {
@@ -3915,10 +4266,6 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor
Record.push_back(getIdentifierRef(II));
}
-void ASTWriter::addMacroRef(MacroInfo *MI, RecordDataImpl &Record) {
- Record.push_back(getMacroRef(MI));
-}
-
IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
if (II == 0)
return 0;
@@ -3929,7 +4276,7 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
-MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
+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).
@@ -3937,11 +4284,27 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
return 0;
MacroID &ID = MacroIDs[MI];
- if (ID == 0)
+ if (ID == 0) {
ID = NextMacroID++;
+ MacroInfoToEmitData Info = { Name, MI, ID };
+ MacroInfosToEmit.push_back(Info);
+ }
return ID;
}
+MacroID ASTWriter::getMacroID(MacroInfo *MI) {
+ if (MI == 0 || MI->isBuiltinMacro())
+ return 0;
+
+ assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!");
+ return MacroIDs[MI];
+}
+
+uint64_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) {
+ assert(IdentMacroDirectivesOffsetMap[Name] && "not set!");
+ return IdentMacroDirectivesOffsetMap[Name];
+}
+
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
Record.push_back(getSelectorRef(SelRef));
}
@@ -3951,14 +4314,16 @@ SelectorID ASTWriter::getSelectorRef(Selector Sel) {
return 0;
}
- SelectorID &SID = SelectorIDs[Sel];
+ SelectorID SID = SelectorIDs[Sel];
if (SID == 0 && Chain) {
// This might trigger a ReadSelector callback, which will set the ID for
// this selector.
Chain->LoadSelector(Sel);
+ SID = SelectorIDs[Sel];
}
if (SID == 0) {
SID = NextSelectorID++;
+ SelectorIDs[Sel] = SID;
}
return SID;
}
@@ -4431,7 +4796,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::TemplateExpansion:
AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
- if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
+ if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
@@ -4474,9 +4839,9 @@ ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
void
-ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record) {
+ASTWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record) {
Record.push_back(Set.size());
- for (UnresolvedSetImpl::const_iterator
+ for (ASTUnresolvedSet::const_iterator
I = Set.begin(), E = Set.end(); I != E; ++I) {
AddDeclRef(I.getDecl(), Record);
Record.push_back(I.getAccess());
@@ -4568,11 +4933,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
Record.push_back(Data.IsLambda);
Record.push_back(Data.UserDeclaredConstructor);
- Record.push_back(Data.UserDeclaredCopyConstructor);
- Record.push_back(Data.UserDeclaredMoveConstructor);
- Record.push_back(Data.UserDeclaredCopyAssignment);
- Record.push_back(Data.UserDeclaredMoveAssignment);
- Record.push_back(Data.UserDeclaredDestructor);
+ Record.push_back(Data.UserDeclaredSpecialMembers);
Record.push_back(Data.Aggregate);
Record.push_back(Data.PlainOldData);
Record.push_back(Data.Empty);
@@ -4586,25 +4947,26 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasMutableFields);
Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasInClassInitializer);
- Record.push_back(Data.HasTrivialDefaultConstructor);
+ Record.push_back(Data.HasUninitializedReferenceMember);
+ Record.push_back(Data.NeedOverloadResolutionForMoveConstructor);
+ Record.push_back(Data.NeedOverloadResolutionForMoveAssignment);
+ Record.push_back(Data.NeedOverloadResolutionForDestructor);
+ Record.push_back(Data.DefaultedMoveConstructorIsDeleted);
+ Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
+ Record.push_back(Data.DefaultedDestructorIsDeleted);
+ Record.push_back(Data.HasTrivialSpecialMembers);
+ Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
Record.push_back(Data.HasConstexprDefaultConstructor);
- Record.push_back(Data.HasTrivialCopyConstructor);
- Record.push_back(Data.HasTrivialMoveConstructor);
- Record.push_back(Data.HasTrivialCopyAssignment);
- Record.push_back(Data.HasTrivialMoveAssignment);
- Record.push_back(Data.HasTrivialDestructor);
- Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.UserProvidedDefaultConstructor);
- Record.push_back(Data.DeclaredDefaultConstructor);
- Record.push_back(Data.DeclaredCopyConstructor);
- Record.push_back(Data.DeclaredMoveConstructor);
- Record.push_back(Data.DeclaredCopyAssignment);
- Record.push_back(Data.DeclaredMoveAssignment);
- Record.push_back(Data.DeclaredDestructor);
+ Record.push_back(Data.DeclaredSpecialMembers);
+ Record.push_back(Data.ImplicitCopyConstructorHasConstParam);
+ Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
+ Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
+ Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
Record.push_back(Data.FailedImplicitMoveConstructor);
Record.push_back(Data.FailedImplicitMoveAssignment);
// IsLambda bit is already saved.
@@ -4676,11 +5038,17 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
- IdentifierIDs[II] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ IdentID &StoredID = IdentifierIDs[II];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
- MacroIDs[MI] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ MacroID &StoredID = MacroIDs[MI];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
@@ -4695,7 +5063,10 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
}
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
- SelectorIDs[S] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ SelectorID &StoredID = SelectorIDs[S];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
@@ -4709,10 +5080,6 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
SubmoduleIDs[Mod] = ID;
}
-void ASTWriter::UndefinedMacro(MacroInfo *MI) {
- MacroUpdates[MI].UndefLoc = MI->getUndefLoc();
-}
-
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
assert(D->isCompleteDefinition());
assert(!WritingAST && "Already writing the AST!");
@@ -4737,6 +5104,7 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile()))
return; // Not a source decl added to a DeclContext from PCH.
+ assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");
AddUpdatedDeclContext(DC);
UpdatingVisibleDecls.push_back(D);
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 74865657637c..023599d0db83 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -12,14 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Serialization/ASTReader.h"
#include "ASTCommon.h"
-#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
@@ -102,6 +102,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
+ void VisitEmptyDecl(EmptyDecl *D);
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset);
@@ -122,6 +123,7 @@ namespace clang {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
};
}
@@ -252,6 +254,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() &&
+ !D->getMemberSpecializationInfo() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();
@@ -263,6 +266,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
Record.push_back(D->hasFlexibleArrayMember());
Record.push_back(D->isAnonymousStructOrUnion());
Record.push_back(D->hasObjectMember());
+ Record.push_back(D->hasVolatileMember());
if (!D->hasAttrs() &&
!D->isImplicit() &&
@@ -315,7 +319,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// after everything else is written.
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
- Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->IsInline);
Record.push_back(D->isInlineSpecified());
Record.push_back(D->isVirtualAsWritten());
@@ -328,6 +331,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isExplicitlyDefaulted());
Record.push_back(D->hasImplicitReturnZero());
Record.push_back(D->isConstexpr());
+ Record.push_back(D->HasSkippedBody);
+ Record.push_back(D->getLinkage());
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->getTemplatedKind());
@@ -419,6 +424,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->isPropertyAccessor());
Record.push_back(D->isDefined());
Record.push_back(D->IsOverriding);
+ Record.push_back(D->HasSkippedBody);
Record.push_back(D->IsRedeclaration);
Record.push_back(D->HasRedeclaration);
@@ -489,13 +495,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
PEnd = Data.AllReferencedProtocols.end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
+
- if (ObjCCategoryDecl *Cat = D->getCategoryList()) {
+ if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) {
// Ensure that we write out the set of categories for this class.
Writer.ObjCClassesWithCategories.insert(D);
// Make sure that the categories get serialized.
- for (; Cat; Cat = Cat->getNextClassCategory())
+ for (; Cat; Cat = Cat->getNextClassCategoryRaw())
(void)Writer.GetDeclRef(Cat);
}
}
@@ -669,8 +676,7 @@ void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
VisitRedeclarable(D);
VisitDeclaratorDecl(D);
- Record.push_back(D->getStorageClass()); // FIXME: stable encoding
- Record.push_back(D->getStorageClassAsWritten());
+ Record.push_back(D->getStorageClass());
Record.push_back(D->isThreadSpecified());
Record.push_back(D->getInitStyle());
Record.push_back(D->isExceptionVariable());
@@ -678,6 +684,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
Record.push_back(D->isConstexpr());
+ Record.push_back(D->getLinkage());
if (D->getInit()) {
Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
@@ -774,6 +781,11 @@ void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Code = serialization::DECL_FILE_SCOPE_ASM;
}
+void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
+ VisitDecl(D);
+ Code = serialization::DECL_EMPTY;
+}
+
void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getBody());
@@ -839,11 +851,10 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
if (StoredDeclsMap *Map = NS->buildLookup()) {
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
D != DEnd; ++D) {
- DeclContext::lookup_result Result = D->second.getLookupResult();
- while (Result.first != Result.second) {
- Writer.GetDeclRef(*Result.first);
- ++Result.first;
- }
+ DeclContext::lookup_result R = D->second.getLookupResult();
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I)
+ Writer.GetDeclRef(*I);
}
}
}
@@ -940,10 +951,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Record.push_back(CXXRecNotTemplate);
}
- // Store the key function to avoid deserializing every method so we can
- // compute it.
+ // Store (what we currently believe to be) the key function to avoid
+ // deserializing every method so we can compute it.
if (D->IsCompleteDefinition)
- Writer.AddDeclRef(Context.getKeyFunction(D), Record);
+ Writer.AddDeclRef(Context.getCurrentKeyFunction(D), Record);
Code = serialization::DECL_CXX_RECORD;
}
@@ -1014,12 +1025,19 @@ void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
}
void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
+ // Record the number of friend type template parameter lists here
+ // so as to simplify memory allocation during deserialization.
+ Record.push_back(D->NumTPLists);
VisitDecl(D);
- Record.push_back(D->Friend.is<TypeSourceInfo*>());
- if (D->Friend.is<TypeSourceInfo*>())
- Writer.AddTypeSourceInfo(D->Friend.get<TypeSourceInfo*>(), Record);
+ bool hasFriendDecl = D->Friend.is<NamedDecl*>();
+ Record.push_back(hasFriendDecl);
+ if (hasFriendDecl)
+ Writer.AddDeclRef(D->getFriendDecl(), Record);
else
- Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
+ Writer.AddTypeSourceInfo(D->getFriendType(), Record);
+ for (unsigned i = 0; i < D->NumTPLists; ++i)
+ Writer.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i),
+ Record);
Writer.AddDeclRef(D->getNextFriend(), Record);
Record.push_back(D->UnsupportedFriend);
Writer.AddSourceLocation(D->FriendLoc, Record);
@@ -1275,7 +1293,10 @@ template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
T *First = D->getFirstDeclaration();
if (First->getMostRecentDecl() != First) {
- // There is more than one declaration of this entity, so we will need to
+ assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) &&
+ "Not considered redeclarable?");
+
+ // There is more than one declaration of this entity, so we will need to
// write a redeclaration chain.
Writer.AddDeclRef(First, Record);
Writer.Redeclarations.insert(First);
@@ -1292,6 +1313,16 @@ 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);
+ Code = serialization::DECL_OMP_THREADPRIVATE;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
@@ -1451,6 +1482,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember
// DC
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
@@ -1483,7 +1515,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
- Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
@@ -1491,6 +1522,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
+ Abv->Add(BitCodeAbbrevOp(0)); // Linkage
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl
@@ -1562,7 +1594,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
@@ -1570,6 +1601,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
// Type Source Info
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7e8ce42d7caf..b6f1d54d4079 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -78,6 +78,8 @@ void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
void ASTStmtWriter::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Record.push_back(Writer.getSwitchCaseID(S));
+ Writer.AddSourceLocation(S->getKeywordLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
}
void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) {
@@ -85,17 +87,13 @@ void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) {
Writer.AddStmt(S->getLHS());
Writer.AddStmt(S->getRHS());
Writer.AddStmt(S->getSubStmt());
- Writer.AddSourceLocation(S->getCaseLoc(), Record);
Writer.AddSourceLocation(S->getEllipsisLoc(), Record);
- Writer.AddSourceLocation(S->getColonLoc(), Record);
Code = serialization::STMT_CASE;
}
void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
VisitSwitchCase(S);
Writer.AddStmt(S->getSubStmt());
- Writer.AddSourceLocation(S->getDefaultLoc(), Record);
- Writer.AddSourceLocation(S->getColonLoc(), Record);
Code = serialization::STMT_DEFAULT;
}
@@ -326,8 +324,9 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
VisitExpr(E);
- Writer.AddAPFloat(E->getValue(), Record);
+ Record.push_back(E->getRawSemantics());
Record.push_back(E->isExact());
+ Writer.AddAPFloat(E->getValue(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
Code = serialization::EXPR_FLOATING_LITERAL;
}
@@ -499,6 +498,7 @@ void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->getBase());
Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
+ Writer.AddSourceLocation(E->getOpLoc(), Record);
Record.push_back(E->isArrow());
Code = serialization::EXPR_OBJC_ISA;
}
@@ -857,6 +857,7 @@ void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getDecl(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceLocation(E->getOpLoc(), Record);
Writer.AddStmt(E->getBase());
Record.push_back(E->isArrow());
Record.push_back(E->isFreeIvar());
@@ -1076,6 +1077,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isElidable());
Record.push_back(E->hadMultipleCandidates());
+ Record.push_back(E->isListInitialization());
Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Writer.AddSourceRange(E->getParenRange(), Record);
@@ -1124,6 +1126,7 @@ void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()),
Record);
+ Writer.AddSourceRange(E->getAngleBrackets(), Record);
}
void ASTStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt
index 20999e1b5c6f..3c68b64625e9 100644
--- a/lib/Serialization/CMakeLists.txt
+++ b/lib/Serialization/CMakeLists.txt
@@ -1,3 +1,5 @@
+set(LLVM_LINK_COMPONENTS bitreader)
+
add_clang_library(clangSerialization
ASTCommon.h
ASTReaderInternals.h
@@ -9,6 +11,7 @@ add_clang_library(clangSerialization
ASTWriterDecl.cpp
ASTWriterStmt.cpp
GeneratePCH.cpp
+ GlobalModuleIndex.cpp
Module.cpp
ModuleManager.cpp
)
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 870d65489584..32c2df3b88d2 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -13,11 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Sema/SemaConsumer.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaConsumer.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
@@ -55,10 +55,6 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
Buffer.clear();
}
-PPMutationListener *PCHGenerator::GetPPMutationListener() {
- return &Writer;
-}
-
ASTMutationListener *PCHGenerator::GetASTMutationListener() {
return &Writer;
}
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
new file mode 100644
index 000000000000..f9acb847284d
--- /dev/null
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -0,0 +1,820 @@
+//===--- GlobalModuleIndex.cpp - Global Module Index ------------*- 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 GlobalModuleIndex class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTReaderInternals.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/Module.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LockFileManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
+#include <cstdio>
+using namespace clang;
+using namespace serialization;
+
+//----------------------------------------------------------------------------//
+// Shared constants
+//----------------------------------------------------------------------------//
+namespace {
+ enum {
+ /// \brief The block containing the index.
+ GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
+ };
+
+ /// \brief Describes the record types in the index.
+ enum IndexRecordTypes {
+ /// \brief Contains version information and potentially other metadata,
+ /// used to determine if we can read this global index file.
+ INDEX_METADATA,
+ /// \brief Describes a module, including its file name and dependencies.
+ MODULE,
+ /// \brief The index for identifiers.
+ IDENTIFIER_INDEX
+ };
+}
+
+/// \brief The name of the global index file.
+static const char * const IndexFileName = "modules.idx";
+
+/// \brief The global index file version.
+static const unsigned CurrentVersion = 1;
+
+//----------------------------------------------------------------------------//
+// Global module index reader.
+//----------------------------------------------------------------------------//
+
+namespace {
+
+/// \brief Trait used to read the identifier index from the on-disk hash
+/// table.
+class IdentifierIndexReaderTrait {
+public:
+ typedef StringRef external_key_type;
+ typedef StringRef internal_key_type;
+ typedef SmallVector<unsigned, 2> data_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) {
+ 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);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static const external_key_type&
+ GetExternalKey(const internal_key_type& x) { return x; }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned n) {
+ return StringRef((const char *)d, n);
+ }
+
+ static data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+
+ data_type Result;
+ while (DataLen > 0) {
+ unsigned ID = ReadUnalignedLE32(d);
+ Result.push_back(ID);
+ DataLen -= 4;
+ }
+
+ return Result;
+ }
+};
+
+typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable;
+
+}
+
+GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
+ llvm::BitstreamCursor Cursor)
+ : Buffer(Buffer), IdentifierIndex(),
+ NumIdentifierLookups(), NumIdentifierLookupHits()
+{
+ // Read the global index.
+ bool InGlobalIndexBlock = false;
+ bool Done = false;
+ while (!Done) {
+ llvm::BitstreamEntry Entry = Cursor.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ return;
+
+ case llvm::BitstreamEntry::EndBlock:
+ if (InGlobalIndexBlock) {
+ InGlobalIndexBlock = false;
+ Done = true;
+ continue;
+ }
+ return;
+
+
+ case llvm::BitstreamEntry::Record:
+ // Entries in the global index block are handled below.
+ if (InGlobalIndexBlock)
+ break;
+
+ return;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
+ if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
+ return;
+
+ InGlobalIndexBlock = true;
+ } else if (Cursor.SkipBlock()) {
+ return;
+ }
+ continue;
+ }
+
+ SmallVector<uint64_t, 64> Record;
+ StringRef Blob;
+ switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) {
+ case INDEX_METADATA:
+ // Make sure that the version matches.
+ if (Record.size() < 1 || Record[0] != CurrentVersion)
+ return;
+ break;
+
+ case MODULE: {
+ unsigned Idx = 0;
+ unsigned ID = Record[Idx++];
+
+ // Make room for this module's information.
+ if (ID == Modules.size())
+ Modules.push_back(ModuleInfo());
+ else
+ Modules.resize(ID + 1);
+
+ // Size/modification time for this module file at the time the
+ // global index was built.
+ Modules[ID].Size = Record[Idx++];
+ Modules[ID].ModTime = Record[Idx++];
+
+ // File name.
+ unsigned NameLen = Record[Idx++];
+ Modules[ID].FileName.assign(Record.begin() + Idx,
+ Record.begin() + Idx + NameLen);
+ Idx += NameLen;
+
+ // Dependencies
+ unsigned NumDeps = Record[Idx++];
+ Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
+ Record.begin() + Idx,
+ Record.begin() + Idx + NumDeps);
+ Idx += NumDeps;
+
+ // Make sure we're at the end of the record.
+ assert(Idx == Record.size() && "More module info?");
+
+ // Record this module as an unresolved module.
+ UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID;
+ break;
+ }
+
+ case IDENTIFIER_INDEX:
+ // Wire up the identifier index.
+ if (Record[0]) {
+ IdentifierIndex = IdentifierIndexTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data(),
+ IdentifierIndexReaderTrait());
+ }
+ break;
+ }
+ }
+}
+
+GlobalModuleIndex::~GlobalModuleIndex() { }
+
+std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode>
+GlobalModuleIndex::readIndex(StringRef Path) {
+ // Load the index file, if it's there.
+ llvm::SmallString<128> IndexPath;
+ IndexPath += Path;
+ llvm::sys::path::append(IndexPath, IndexFileName);
+
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ if (llvm::MemoryBuffer::getFile(IndexPath, Buffer) != llvm::errc::success)
+ return std::make_pair((GlobalModuleIndex *)0, EC_NotFound);
+
+ /// \brief The bitstream reader from which we'll read the AST file.
+ llvm::BitstreamReader Reader((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+
+ /// \brief The main bitstream cursor for the main block.
+ llvm::BitstreamCursor Cursor(Reader);
+
+ // Sniff for the signature.
+ if (Cursor.Read(8) != 'B' ||
+ Cursor.Read(8) != 'C' ||
+ Cursor.Read(8) != 'G' ||
+ Cursor.Read(8) != 'I') {
+ return std::make_pair((GlobalModuleIndex *)0, EC_IOError);
+ }
+
+ return std::make_pair(new GlobalModuleIndex(Buffer.take(), Cursor), EC_None);
+}
+
+void
+GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) {
+ ModuleFiles.clear();
+ for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[I].File)
+ ModuleFiles.push_back(MF);
+ }
+}
+
+void GlobalModuleIndex::getModuleDependencies(
+ ModuleFile *File,
+ SmallVectorImpl<ModuleFile *> &Dependencies) {
+ // Look for information about this module file.
+ llvm::DenseMap<ModuleFile *, unsigned>::iterator Known
+ = ModulesByFile.find(File);
+ if (Known == ModulesByFile.end())
+ return;
+
+ // Record dependencies.
+ Dependencies.clear();
+ ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies;
+ for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[I].File)
+ Dependencies.push_back(MF);
+ }
+}
+
+bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
+ Hits.clear();
+
+ // If there's no identifier index, there is nothing we can do.
+ if (!IdentifierIndex)
+ return false;
+
+ // Look into the identifier index.
+ ++NumIdentifierLookups;
+ IdentifierIndexTable &Table
+ = *static_cast<IdentifierIndexTable *>(IdentifierIndex);
+ IdentifierIndexTable::iterator Known = Table.find(Name);
+ if (Known == Table.end()) {
+ return true;
+ }
+
+ SmallVector<unsigned, 2> ModuleIDs = *Known;
+ for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[ModuleIDs[I]].File)
+ Hits.insert(MF);
+ }
+
+ ++NumIdentifierLookupHits;
+ return true;
+}
+
+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);
+ llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
+ if (Known == UnresolvedModules.end()) {
+ return true;
+ }
+
+ // Rectify this module with the global module index.
+ ModuleInfo &Info = Modules[Known->second];
+
+ // If the size and modification time match what we expected, record this
+ // module file.
+ bool Failed = true;
+ if (File->File->getSize() == Info.Size &&
+ File->File->getModificationTime() == Info.ModTime) {
+ Info.File = File;
+ ModulesByFile[File] = Known->second;
+
+ Failed = false;
+ }
+
+ // One way or another, we have resolved this module file.
+ UnresolvedModules.erase(Known);
+ return Failed;
+}
+
+void GlobalModuleIndex::printStats() {
+ std::fprintf(stderr, "*** Global Module Index Statistics:\n");
+ if (NumIdentifierLookups) {
+ fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n",
+ NumIdentifierLookupHits, NumIdentifierLookups,
+ (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
+ }
+ std::fprintf(stderr, "\n");
+}
+
+//----------------------------------------------------------------------------//
+// Global module index writer.
+//----------------------------------------------------------------------------//
+
+namespace {
+ /// \brief Provides information about a specific module file.
+ struct ModuleFileInfo {
+ /// \brief The numberic ID for this module file.
+ unsigned ID;
+
+ /// \brief The set of modules on which this module depends. Each entry is
+ /// a module ID.
+ SmallVector<unsigned, 4> Dependencies;
+ };
+
+ /// \brief Builder that generates the global module index file.
+ class GlobalModuleIndexBuilder {
+ FileManager &FileMgr;
+
+ /// \brief Mapping from files to module file information.
+ typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
+
+ /// \brief Information about each of the known module files.
+ ModuleFilesMap ModuleFiles;
+
+ /// \brief Mapping from identifiers to the list of module file IDs that
+ /// consider this identifier to be interesting.
+ typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
+
+ /// \brief A mapping from all interesting identifiers to the set of module
+ /// files in which those identifiers are considered interesting.
+ InterestingIdentifierMap InterestingIdentifiers;
+
+ /// \brief Write the block-info block for the global module index file.
+ void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
+
+ /// \brief Retrieve the module file information for the given file.
+ ModuleFileInfo &getModuleFileInfo(const FileEntry *File) {
+ llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known
+ = ModuleFiles.find(File);
+ if (Known != ModuleFiles.end())
+ return Known->second;
+
+ unsigned NewID = ModuleFiles.size();
+ ModuleFileInfo &Info = ModuleFiles[File];
+ Info.ID = NewID;
+ return Info;
+ }
+
+ public:
+ explicit GlobalModuleIndexBuilder(FileManager &FileMgr) : FileMgr(FileMgr){}
+
+ /// \brief Load the contents of the given module file into the builder.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool loadModuleFile(const FileEntry *File);
+
+ /// \brief Write the index to the given bitstream.
+ void writeIndex(llvm::BitstreamWriter &Stream);
+ };
+}
+
+static void emitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<uint64_t> &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (Name == 0 || Name[0] == 0) return;
+ Record.clear();
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+static void emitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<uint64_t> &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+void
+GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
+ SmallVector<uint64_t, 64> Record;
+ Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
+
+#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
+#define RECORD(X) emitRecordID(X, #X, Stream, Record)
+ BLOCK(GLOBAL_INDEX_BLOCK);
+ RECORD(INDEX_METADATA);
+ RECORD(MODULE);
+ RECORD(IDENTIFIER_INDEX);
+#undef RECORD
+#undef BLOCK
+
+ Stream.ExitBlock();
+}
+
+namespace {
+ class InterestingASTIdentifierLookupTrait
+ : public serialization::reader::ASTIdentifierLookupTraitBase {
+
+ public:
+ /// \brief The identifier and whether it is "interesting".
+ typedef std::pair<StringRef, bool> data_type;
+
+ data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ 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);
+ bool IsInteresting = RawID & 0x01;
+ return std::make_pair(k, IsInteresting);
+ }
+ };
+}
+
+bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
+ // Open the module file.
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ std::string ErrorStr;
+ Buffer.reset(FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true));
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the input stream
+ llvm::BitstreamReader InStreamFile;
+ llvm::BitstreamCursor InStream;
+ InStreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ InStream.init(InStreamFile);
+
+ // Sniff for the signature.
+ if (InStream.Read(8) != 'C' ||
+ InStream.Read(8) != 'P' ||
+ InStream.Read(8) != 'C' ||
+ InStream.Read(8) != 'H') {
+ return true;
+ }
+
+ // Record this module file and assign it a unique ID (if it doesn't have
+ // one already).
+ unsigned ID = getModuleFileInfo(File).ID;
+
+ // Search for the blocks and records we care about.
+ enum { Other, ControlBlock, ASTBlock } State = Other;
+ bool Done = false;
+ while (!Done) {
+ llvm::BitstreamEntry Entry = InStream.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Done = true;
+ continue;
+
+ case llvm::BitstreamEntry::Record:
+ // In the 'other' state, just skip the record. We don't care.
+ if (State == Other) {
+ InStream.skipRecord(Entry.ID);
+ continue;
+ }
+
+ // Handle potentially-interesting records below.
+ break;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (Entry.ID == CONTROL_BLOCK_ID) {
+ if (InStream.EnterSubBlock(CONTROL_BLOCK_ID))
+ return true;
+
+ // Found the control block.
+ State = ControlBlock;
+ continue;
+ }
+
+ if (Entry.ID == AST_BLOCK_ID) {
+ if (InStream.EnterSubBlock(AST_BLOCK_ID))
+ return true;
+
+ // Found the AST block.
+ State = ASTBlock;
+ continue;
+ }
+
+ if (InStream.SkipBlock())
+ return true;
+
+ continue;
+
+ case llvm::BitstreamEntry::EndBlock:
+ State = Other;
+ continue;
+ }
+
+ // Read the given record.
+ SmallVector<uint64_t, 64> Record;
+ StringRef Blob;
+ unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob);
+
+ // Handle module dependencies.
+ if (State == ControlBlock && Code == IMPORTS) {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+
+ // Skip the imported kind
+ ++Idx;
+
+ // Skip the import location
+ ++Idx;
+
+ // Load stored size/modification time.
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)Record[Idx++];
+
+ // Retrieve the imported file name.
+ unsigned Length = Record[Idx++];
+ SmallString<128> ImportedFile(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ Idx += Length;
+
+ // Find the imported module file.
+ const FileEntry *DependsOnFile
+ = FileMgr.getFile(ImportedFile, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ if (!DependsOnFile ||
+ (StoredSize != DependsOnFile->getSize()) ||
+ (StoredModTime != DependsOnFile->getModificationTime()))
+ return true;
+
+ // Record the dependency.
+ unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
+ getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
+ }
+
+ continue;
+ }
+
+ // 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()));
+ for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
+ DEnd = Table->data_end();
+ D != DEnd; ++D) {
+ std::pair<StringRef, bool> Ident = *D;
+ if (Ident.second)
+ InterestingIdentifiers[Ident.first].push_back(ID);
+ else
+ (void)InterestingIdentifiers[Ident.first];
+ }
+ }
+
+ // We don't care about this record.
+ }
+
+ return false;
+}
+
+namespace {
+
+/// \brief Trait used to generate the identifier index as an on-disk hash
+/// table.
+class IdentifierIndexWriterTrait {
+public:
+ typedef StringRef key_type;
+ typedef StringRef key_type_ref;
+ typedef SmallVector<unsigned, 2> data_type;
+ typedef const SmallVector<unsigned, 2> &data_type_ref;
+
+ static unsigned 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) {
+ unsigned KeyLen = Key.size();
+ unsigned DataLen = Data.size() * 4;
+ clang::io::Emit16(Out, KeyLen);
+ clang::io::Emit16(Out, DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
+ Out.write(Key.data(), KeyLen);
+ }
+
+ void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
+ unsigned DataLen) {
+ for (unsigned I = 0, N = Data.size(); I != N; ++I)
+ clang::io::Emit32(Out, Data[I]);
+ }
+};
+
+}
+
+void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+
+ // Emit the file header.
+ Stream.Emit((unsigned)'B', 8);
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'G', 8);
+ Stream.Emit((unsigned)'I', 8);
+
+ // Write the block-info block, which describes the records in this bitcode
+ // file.
+ emitBlockInfoBlock(Stream);
+
+ Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
+
+ // Write the metadata.
+ SmallVector<uint64_t, 2> Record;
+ Record.push_back(CurrentVersion);
+ Stream.EmitRecord(INDEX_METADATA, Record);
+
+ // Write the set of known module files.
+ for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
+ MEnd = ModuleFiles.end();
+ M != MEnd; ++M) {
+ Record.clear();
+ Record.push_back(M->second.ID);
+ Record.push_back(M->first->getSize());
+ Record.push_back(M->first->getModificationTime());
+
+ // File name
+ StringRef Name(M->first->getName());
+ Record.push_back(Name.size());
+ Record.append(Name.begin(), Name.end());
+
+ // Dependencies
+ Record.push_back(M->second.Dependencies.size());
+ Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
+ Stream.EmitRecord(MODULE, Record);
+ }
+
+ // Write the identifier -> module file mapping.
+ {
+ OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
+ IdentifierIndexWriterTrait Trait;
+
+ // Populate the hash table.
+ for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
+ IEnd = InterestingIdentifiers.end();
+ I != IEnd; ++I) {
+ Generator.insert(I->first(), I->second, Trait);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> IdentifierTable;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(IdentifierTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the identifier table
+ Record.clear();
+ Record.push_back(IDENTIFIER_INDEX);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
+ }
+
+ Stream.ExitBlock();
+}
+
+GlobalModuleIndex::ErrorCode
+GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
+ llvm::SmallString<128> IndexPath;
+ IndexPath += Path;
+ llvm::sys::path::append(IndexPath, IndexFileName);
+
+ // Coordinate building the global index file with other processes that might
+ // try to do the same.
+ llvm::LockFileManager Locked(IndexPath);
+ switch (Locked) {
+ case llvm::LockFileManager::LFS_Error:
+ return EC_IOError;
+
+ case llvm::LockFileManager::LFS_Owned:
+ // We're responsible for building the index ourselves. Do so below.
+ break;
+
+ case llvm::LockFileManager::LFS_Shared:
+ // Someone else is responsible for building the index. We don't care
+ // when they finish, so we're done.
+ return EC_Building;
+ }
+
+ // The module index builder.
+ GlobalModuleIndexBuilder Builder(FileMgr);
+
+ // Load each of the module files.
+ llvm::error_code EC;
+ for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
+ D != DEnd && !EC;
+ D.increment(EC)) {
+ // If this isn't a module file, we don't care.
+ if (llvm::sys::path::extension(D->path()) != ".pcm") {
+ // ... unless it's a .pcm.lock file, which indicates that someone is
+ // in the process of rebuilding a module. They'll rebuild the index
+ // at the end of that translation unit, so we don't have to.
+ if (llvm::sys::path::extension(D->path()) == ".pcm.lock")
+ return EC_Building;
+
+ continue;
+ }
+
+ // If we can't find the module file, skip it.
+ const FileEntry *ModuleFile = FileMgr.getFile(D->path());
+ if (!ModuleFile)
+ continue;
+
+ // Load this module file.
+ if (Builder.loadModuleFile(ModuleFile))
+ return EC_IOError;
+ }
+
+ // The output buffer, into which the global index will be written.
+ SmallVector<char, 16> OutputBuffer;
+ {
+ llvm::BitstreamWriter OutputStream(OutputBuffer);
+ Builder.writeIndex(OutputStream);
+ }
+
+ // Write the global index file to a temporary file.
+ llvm::SmallString<128> IndexTmpPath;
+ int TmpFD;
+ if (llvm::sys::fs::unique_file(IndexPath + "-%%%%%%%%", TmpFD, IndexTmpPath))
+ return EC_IOError;
+
+ // Open the temporary global index file for output.
+ llvm::raw_fd_ostream Out(TmpFD, true);
+ if (Out.has_error())
+ return EC_IOError;
+
+ // Write the index.
+ Out.write(OutputBuffer.data(), OutputBuffer.size());
+ Out.close();
+ if (Out.has_error())
+ return EC_IOError;
+
+ // Remove the old index file. It isn't relevant any more.
+ bool OldIndexExisted;
+ llvm::sys::fs::remove(IndexPath.str(), OldIndexExisted);
+
+ // 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);
+ return EC_IOError;
+ }
+
+ // We're done.
+ return EC_None;
+}
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 5e42ab4211fa..2eb397176a12 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Serialization/Module.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "ASTReaderInternals.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace serialization;
@@ -33,7 +33,7 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
- HeaderFileFrameworkStrings(0), LocalNumSubmodules(0), BaseSubmoduleID(0),
+ LocalNumSubmodules(0), BaseSubmoduleID(0),
LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index efe442101bb6..f3d53adafa52 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -11,8 +11,11 @@
// modules for the ASTReader.
//
//===----------------------------------------------------------------------===//
+#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
@@ -24,37 +27,63 @@ using namespace clang;
using namespace serialization;
ModuleFile *ModuleManager::lookup(StringRef Name) {
- const FileEntry *Entry = FileMgr.getFile(Name);
- return Modules[Entry];
+ const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ if (Entry)
+ return lookup(Entry);
+
+ return 0;
+}
+
+ModuleFile *ModuleManager::lookup(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
+ = Modules.find(File);
+ if (Known == Modules.end())
+ return 0;
+
+ return Known->second;
}
llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
- const FileEntry *Entry = FileMgr.getFile(Name);
+ const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
+ /*cacheFailure=*/false);
return InMemoryBuffers[Entry];
}
-std::pair<ModuleFile *, bool>
-ModuleManager::addModule(StringRef FileName, ModuleKind Type,
- ModuleFile *ImportedBy, unsigned Generation,
+ModuleManager::AddModuleResult
+ModuleManager::addModule(StringRef FileName, ModuleKind Type,
+ SourceLocation ImportLoc, ModuleFile *ImportedBy,
+ unsigned Generation,
+ off_t ExpectedSize, time_t ExpectedModTime,
+ ModuleFile *&Module,
std::string &ErrorStr) {
- const FileEntry *Entry = FileMgr.getFile(FileName);
+ Module = 0;
+
+ // Look for the file entry. This only fails if the expected size or
+ // modification time differ.
+ const FileEntry *Entry;
+ if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry))
+ return OutOfDate;
+
if (!Entry && FileName != "-") {
ErrorStr = "file not found";
- return std::make_pair(static_cast<ModuleFile*>(0), false);
+ return Missing;
}
-
- // Check whether we already loaded this module, before
+
+ // Check whether we already loaded this module, before
ModuleFile *&ModuleEntry = Modules[Entry];
bool NewModule = false;
if (!ModuleEntry) {
// Allocate a new module.
ModuleFile *New = new ModuleFile(Type, Generation);
+ New->Index = Chain.size();
New->FileName = FileName.str();
New->File = Entry;
+ New->ImportLoc = ImportLoc;
Chain.push_back(New);
NewModule = true;
ModuleEntry = New;
-
+
// Load the contents of the module
if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
@@ -71,21 +100,26 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
if (!New->Buffer)
- return std::make_pair(static_cast<ModuleFile*>(0), false);
+ return Missing;
}
// Initialize the stream
New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
- (const unsigned char *)New->Buffer->getBufferEnd()); }
+ (const unsigned char *)New->Buffer->getBufferEnd());
+ }
if (ImportedBy) {
ModuleEntry->ImportedBy.insert(ImportedBy);
ImportedBy->Imports.insert(ModuleEntry);
} else {
+ if (!ModuleEntry->DirectlyImported)
+ ModuleEntry->ImportLoc = ImportLoc;
+
ModuleEntry->DirectlyImported = true;
}
-
- return std::make_pair(ModuleEntry, NewModule);
+
+ Module = ModuleEntry;
+ return NewModule? NewlyLoaded : AlreadyLoaded;
}
namespace {
@@ -104,7 +138,8 @@ namespace {
};
}
-void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
+void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
+ ModuleMap *modMap) {
if (first == last)
return;
@@ -120,6 +155,14 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
// 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);
+ if (Module *mod = modMap->findModule(ModuleName)) {
+ mod->setASTFile(0);
+ }
+ }
delete *victim;
}
@@ -135,79 +178,166 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName,
InMemoryBuffers[Entry] = Buffer;
}
-ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { }
+ModuleManager::VisitState *ModuleManager::allocateVisitState() {
+ // Fast path: if we have a cached state, use it.
+ if (FirstVisitState) {
+ VisitState *Result = FirstVisitState;
+ FirstVisitState = FirstVisitState->NextState;
+ Result->NextState = 0;
+ return Result;
+ }
+
+ // Allocate and return a new state.
+ return new VisitState(size());
+}
+
+void ModuleManager::returnVisitState(VisitState *State) {
+ assert(State->NextState == 0 && "Visited state is in list?");
+ State->NextState = FirstVisitState;
+ FirstVisitState = State;
+}
+
+void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
+ GlobalIndex = Index;
+ if (!GlobalIndex) {
+ ModulesInCommonWithGlobalIndex.clear();
+ return;
+ }
+
+ // Notify the global module index about all of the modules we've already
+ // loaded.
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (!GlobalIndex->loadedModuleFile(Chain[I])) {
+ ModulesInCommonWithGlobalIndex.push_back(Chain[I]);
+ }
+ }
+}
+
+void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
+ if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
+ return;
+
+ ModulesInCommonWithGlobalIndex.push_back(MF);
+}
+
+ModuleManager::ModuleManager(FileManager &FileMgr)
+ : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { }
ModuleManager::~ModuleManager() {
for (unsigned i = 0, e = Chain.size(); i != e; ++i)
delete Chain[e - i - 1];
+ delete FirstVisitState;
}
-void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
- void *UserData) {
- unsigned N = size();
-
- // Record the number of incoming edges for each module. When we
- // encounter a module with no incoming edges, push it into the queue
- // to seed the queue.
- SmallVector<ModuleFile *, 4> Queue;
- Queue.reserve(N);
- llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges;
- for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
- if (unsigned Size = (*M)->ImportedBy.size())
- UnusedIncomingEdges[*M] = Size;
- else
- Queue.push_back(*M);
- }
-
- llvm::SmallPtrSet<ModuleFile *, 4> Skipped;
- unsigned QueueStart = 0;
- while (QueueStart < Queue.size()) {
- ModuleFile *CurrentModule = Queue[QueueStart++];
+void
+ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
+ void *UserData,
+ llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) {
+ // If the visitation order vector is the wrong size, recompute the order.
+ if (VisitOrder.size() != Chain.size()) {
+ unsigned N = size();
+ VisitOrder.clear();
+ VisitOrder.reserve(N);
- // Check whether this module should be skipped.
- if (Skipped.count(CurrentModule))
+ // Record the number of incoming edges for each module. When we
+ // encounter a module with no incoming edges, push it into the queue
+ // to seed the queue.
+ SmallVector<ModuleFile *, 4> Queue;
+ Queue.reserve(N);
+ llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
+ UnusedIncomingEdges.reserve(size());
+ for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
+ if (unsigned Size = (*M)->ImportedBy.size())
+ UnusedIncomingEdges.push_back(Size);
+ else {
+ UnusedIncomingEdges.push_back(0);
+ Queue.push_back(*M);
+ }
+ }
+
+ // Traverse the graph, making sure to visit a module before visiting any
+ // of its dependencies.
+ unsigned QueueStart = 0;
+ while (QueueStart < Queue.size()) {
+ ModuleFile *CurrentModule = Queue[QueueStart++];
+ VisitOrder.push_back(CurrentModule);
+
+ // For any module that this module depends on, push it on the
+ // stack (if it hasn't already been marked as visited).
+ for (llvm::SetVector<ModuleFile *>::iterator
+ M = CurrentModule->Imports.begin(),
+ MEnd = CurrentModule->Imports.end();
+ M != MEnd; ++M) {
+ // Remove our current module as an impediment to visiting the
+ // module we depend on. If we were the last unvisited module
+ // that depends on this particular module, push it into the
+ // queue to be visited.
+ unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
+ if (NumUnusedEdges && (--NumUnusedEdges == 0))
+ Queue.push_back(*M);
+ }
+ }
+
+ assert(VisitOrder.size() == N && "Visitation order is wrong?");
+
+ delete FirstVisitState;
+ FirstVisitState = 0;
+ }
+
+ VisitState *State = allocateVisitState();
+ unsigned VisitNumber = State->NextVisitNumber++;
+
+ // If the caller has provided us with a hit-set that came from the global
+ // module index, mark every module file in common with the global module
+ // index that is *not* in that set as 'visited'.
+ if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
+ for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
+ {
+ ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
+ if (!ModuleFilesHit->count(M))
+ State->VisitNumber[M->Index] = VisitNumber;
+ }
+ }
+
+ for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
+ ModuleFile *CurrentModule = VisitOrder[I];
+ // Should we skip this module file?
+ if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
continue;
-
- if (Visitor(*CurrentModule, UserData)) {
- // The visitor has requested that cut off visitation of any
- // module that the current module depends on. To indicate this
- // behavior, we mark all of the reachable modules as having N
- // incoming edges (which is impossible otherwise).
- SmallVector<ModuleFile *, 4> Stack;
- Stack.push_back(CurrentModule);
- Skipped.insert(CurrentModule);
- while (!Stack.empty()) {
- ModuleFile *NextModule = Stack.back();
- Stack.pop_back();
-
- // For any module that this module depends on, push it on the
- // stack (if it hasn't already been marked as visited).
- for (llvm::SetVector<ModuleFile *>::iterator
+
+ // Visit the module.
+ assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
+ State->VisitNumber[CurrentModule->Index] = VisitNumber;
+ if (!Visitor(*CurrentModule, UserData))
+ continue;
+
+ // The visitor has requested that cut off visitation of any
+ // module that the current module depends on. To indicate this
+ // behavior, we mark all of the reachable modules as having been visited.
+ ModuleFile *NextModule = CurrentModule;
+ do {
+ // For any module that this module depends on, push it on the
+ // stack (if it hasn't already been marked as visited).
+ for (llvm::SetVector<ModuleFile *>::iterator
M = NextModule->Imports.begin(),
MEnd = NextModule->Imports.end();
- M != MEnd; ++M) {
- if (Skipped.insert(*M))
- Stack.push_back(*M);
+ M != MEnd; ++M) {
+ if (State->VisitNumber[(*M)->Index] != VisitNumber) {
+ State->Stack.push_back(*M);
+ State->VisitNumber[(*M)->Index] = VisitNumber;
}
}
- continue;
- }
-
- // For any module that this module depends on, push it on the
- // stack (if it hasn't already been marked as visited).
- for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(),
- MEnd = CurrentModule->Imports.end();
- M != MEnd; ++M) {
-
- // Remove our current module as an impediment to visiting the
- // module we depend on. If we were the last unvisited module
- // that depends on this particular module, push it into the
- // queue to be visited.
- unsigned &NumUnusedEdges = UnusedIncomingEdges[*M];
- if (NumUnusedEdges && (--NumUnusedEdges == 0))
- Queue.push_back(*M);
- }
+
+ if (State->Stack.empty())
+ break;
+
+ // Pop the next module off the stack.
+ NextModule = State->Stack.back();
+ State->Stack.pop_back();
+ } while (true);
}
+
+ returnVisitState(State);
}
/// \brief Perform a depth-first visit of the current module.
@@ -215,18 +345,19 @@ static bool visitDepthFirst(ModuleFile &M,
bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData,
- llvm::SmallPtrSet<ModuleFile *, 4> &Visited) {
+ SmallVectorImpl<bool> &Visited) {
// Preorder visitation
if (Visitor(M, /*Preorder=*/true, UserData))
return true;
// Visit children
for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
- IMEnd = M.Imports.end();
+ IMEnd = M.Imports.end();
IM != IMEnd; ++IM) {
- if (!Visited.insert(*IM))
+ if (Visited[(*IM)->Index])
continue;
-
+ Visited[(*IM)->Index] = true;
+
if (visitDepthFirst(**IM, Visitor, UserData, Visited))
return true;
}
@@ -238,16 +369,35 @@ static bool visitDepthFirst(ModuleFile &M,
void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData) {
- llvm::SmallPtrSet<ModuleFile *, 4> Visited;
+ SmallVector<bool, 16> Visited(size(), false);
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (!Visited.insert(Chain[I]))
+ if (Visited[Chain[I]->Index])
continue;
-
+ Visited[Chain[I]->Index] = true;
+
if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
return;
}
}
+bool ModuleManager::lookupModuleFile(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ const FileEntry *&File) {
+ File = FileMgr.getFile(FileName, /*openFile=*/false, /*cacheFailure=*/false);
+
+ if (!File && FileName != "-") {
+ return false;
+ }
+
+ if ((ExpectedSize && ExpectedSize != File->getSize()) ||
+ (ExpectedModTime && ExpectedModTime != File->getModificationTime())) {
+ return true;
+ }
+
+ return false;
+}
+
#ifndef NDEBUG
namespace llvm {
template<>
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index aa6f97b2fa8f..9af0a5ac4fd5 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -11,17 +11,17 @@
#define DEBUG_TYPE "StatsChecker"
#include "ClangSACheckers.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-
-#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -60,7 +60,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (D != P.getLocationContext()->getDecl())
continue;
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB);
}
@@ -123,14 +123,14 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
const BlockEdge &BE = I->first;
const CFGBlock *Exit = BE.getDst();
const CFGElement &CE = Exit->front();
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
SmallString<128> bufI;
llvm::raw_svector_ostream outputI(bufI);
outputI << "(" << NameOfRootFunction << ")" <<
": The analyzer generated a sink at this point";
- B.EmitBasicReport(D, "Sink Point", "Internal Statistics", outputI.str(),
- PathDiagnosticLocation::createBegin(CS->getStmt(),
- SM, LC));
+ B.EmitBasicReport(
+ D, "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 535d8eede46a..312bc749b181 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -44,7 +44,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
return;
// Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
// Zero index is always in bound, this also passes ElementRegions created for
// pointer casts.
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 457c870943dd..5e4b824df4b9 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -13,14 +13,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/AST/CharUnits.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -53,7 +53,7 @@ public:
RegionRawOffsetV2(const SubRegion* base, SVal offset)
: baseRegion(base), byteOffset(offset) {}
- NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); }
+ NonLoc getByteOffset() const { return byteOffset.castAs<NonLoc>(); }
const SubRegion *getRegion() const { return baseRegion; }
static RegionRawOffsetV2 computeOffset(ProgramStateRef state,
@@ -110,13 +110,12 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
- if (isa<NonLoc>(extentBegin)) {
- SVal lowerBound
- = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
- cast<NonLoc>(extentBegin),
+ if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
+ SVal lowerBound =
+ svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(), *NV,
svalBuilder.getConditionType());
- NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
+ Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
if (!lowerBoundToCheck)
return;
@@ -140,15 +139,15 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
// we are doing a load/store after the last valid offset.
DefinedOrUnknownSVal extentVal =
rawOffset.getRegion()->getExtent(svalBuilder);
- if (!isa<NonLoc>(extentVal))
+ if (!extentVal.getAs<NonLoc>())
break;
SVal upperbound
= svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
- cast<NonLoc>(extentVal),
+ extentVal.castAs<NonLoc>(),
svalBuilder.getConditionType());
- NonLoc *upperboundToCheck = dyn_cast<NonLoc>(&upperbound);
+ Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
if (!upperboundToCheck)
break;
@@ -235,7 +234,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
// is unknown or undefined, we lazily substitute '0'. Otherwise,
// return 'val'.
static inline SVal getValue(SVal val, SValBuilder &svalBuilder) {
- return isa<UndefinedVal>(val) ? svalBuilder.makeArrayIndex(0) : val;
+ return val.getAs<UndefinedVal>() ? svalBuilder.makeArrayIndex(0) : val;
}
// Scale a base value by a scaling factor, and return the scaled
@@ -256,9 +255,9 @@ static SVal addValue(ProgramStateRef state, SVal x, SVal y,
// only care about computing offsets.
if (x.isUnknownOrUndef() || y.isUnknownOrUndef())
return UnknownVal();
-
- return svalBuilder.evalBinOpNN(state, BO_Add,
- cast<NonLoc>(x), cast<NonLoc>(y),
+
+ return svalBuilder.evalBinOpNN(state, BO_Add, x.castAs<NonLoc>(),
+ y.castAs<NonLoc>(),
svalBuilder.getArrayIndexType());
}
@@ -284,7 +283,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
case MemRegion::ElementRegionKind: {
const ElementRegion *elemReg = cast<ElementRegion>(region);
SVal index = elemReg->getIndex();
- if (!isa<NonLoc>(index))
+ if (!index.getAs<NonLoc>())
return RegionRawOffsetV2();
QualType elemType = elemReg->getElementType();
// If the element is an incomplete type, go no further.
@@ -296,7 +295,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
offset = addValue(state,
getValue(offset, svalBuilder),
scaleValue(state,
- cast<NonLoc>(index),
+ index.castAs<NonLoc>(),
astContext.getTypeSizeInChars(elemType),
svalBuilder),
svalBuilder);
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
deleted file mode 100644
index 81e8dd885a34..000000000000
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines AttrNonNullChecker, a builtin check in ExprEngine that
-// performs checks for arguments declared to have nonnull attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AttrNonNullChecker
- : public Checker< check::PreCall > {
- mutable OwningPtr<BugType> BT;
-public:
-
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
-};
-} // end anonymous namespace
-
-void AttrNonNullChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- const Decl *FD = Call.getDecl();
- if (!FD)
- return;
-
- const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
- if (!Att)
- return;
-
- ProgramStateRef state = C.getState();
-
- // Iterate through the arguments of CE and check them for null.
- for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx) {
- if (!Att->isNonNull(idx))
- continue;
-
- SVal V = Call.getArgSVal(idx);
- DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
-
- // If the value is unknown or undefined, we can't perform this check.
- if (!DV)
- continue;
-
- if (!isa<Loc>(*DV)) {
- // If the argument is a union type, we want to handle a potential
- // transparent_union GCC extension.
- const Expr *ArgE = Call.getArgExpr(idx);
- if (!ArgE)
- continue;
-
- QualType T = ArgE->getType();
- const RecordType *UT = T->getAsUnionType();
- if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
- continue;
-
- if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
- nonloc::CompoundVal::iterator CSV_I = CSV->begin();
- assert(CSV_I != CSV->end());
- V = *CSV_I;
- DV = dyn_cast<DefinedSVal>(&V);
- assert(++CSV_I == CSV->end());
- if (!DV)
- continue;
- } else {
- // FIXME: Handle LazyCompoundVals?
- continue;
- }
- }
-
- ConstraintManager &CM = C.getConstraintManager();
- ProgramStateRef stateNotNull, stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
-
- if (stateNull && !stateNotNull) {
- // Generate an error node. Check for a null node in case
- // we cache out.
- if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
-
- // Lazily allocate the BugType object if it hasn't already been
- // created. Ownership is transferred to the BugReporter object once
- // the BugReport is passed to 'EmitWarning'.
- if (!BT)
- BT.reset(new BugType("Argument with 'nonnull' attribute passed null",
- "API"));
-
- BugReport *R =
- new BugReport(*BT, "Null pointer passed as an argument to a "
- "'nonnull' parameter", errorNode);
-
- // Highlight the range of the argument that was null.
- R->addRange(Call.getArgSourceRange(idx));
- if (const Expr *ArgE = Call.getArgExpr(idx))
- bugreporter::trackNullOrUndefValue(errorNode, ArgE, *R);
- // Emit the bug report.
- C.emitReport(R);
- }
-
- // Always return. Either we cached out or we just emitted an error.
- return;
- }
-
- // If a pointer value passed the check we should assume that it is
- // indeed not null from this point forward.
- assert(stateNotNull);
- state = stateNotNull;
- }
-
- // If we reach here all of the arguments passed the nonnull check.
- // If 'state' has been updated generated a new node.
- C.addTransition(state);
-}
-
-void ento::registerAttrNonNullChecker(CheckerManager &mgr) {
- mgr.registerChecker<AttrNonNullChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index eba534e08f6b..533a324e7507 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -14,23 +14,24 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.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/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/ASTContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -82,10 +83,6 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
return result;
}
-static inline bool isNil(SVal X) {
- return isa<loc::ConcreteInt>(X);
-}
-
//===----------------------------------------------------------------------===//
// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
//===----------------------------------------------------------------------===//
@@ -94,29 +91,55 @@ namespace {
class NilArgChecker : public Checker<check::PreObjCMessage> {
mutable OwningPtr<APIMisuse> BT;
- void WarnNilArg(CheckerContext &C,
- const ObjCMethodCall &msg, unsigned Arg) const;
+ void WarnIfNilArg(CheckerContext &C,
+ const ObjCMethodCall &msg, unsigned Arg,
+ FoundationClass Class,
+ bool CanBeSubscript = false) const;
public:
void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
};
}
-void NilArgChecker::WarnNilArg(CheckerContext &C,
- const ObjCMethodCall &msg,
- unsigned int Arg) const
-{
+void NilArgChecker::WarnIfNilArg(CheckerContext &C,
+ const ObjCMethodCall &msg,
+ unsigned int Arg,
+ FoundationClass Class,
+ bool CanBeSubscript) const {
+ // Check if the argument is nil.
+ ProgramStateRef State = C.getState();
+ if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
+ return;
+
if (!BT)
BT.reset(new APIMisuse("nil argument"));
-
+
if (ExplodedNode *N = C.generateSink()) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
- os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
- << msg.getSelector().getAsString() << "' cannot be nil";
+
+ if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
+
+ if (Class == FC_NSArray) {
+ os << "Array element cannot be nil";
+ } else if (Class == FC_NSDictionary) {
+ if (Arg == 0)
+ os << "Dictionary object cannot be nil";
+ else {
+ assert(Arg == 1);
+ os << "Dictionary key cannot be nil";
+ }
+ } else
+ llvm_unreachable("Missing foundation class for the subscript expr");
+
+ } else {
+ os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
+ << msg.getSelector().getAsString() << "' cannot be nil";
+ }
BugReport *R = new BugReport(*BT, os.str(), N);
R->addRange(msg.getArgSourceRange(Arg));
+ bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
C.emitReport(R);
}
}
@@ -126,8 +149,14 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
if (!ID)
return;
+
+ FoundationClass Class = findKnownClass(ID);
+
+ static const unsigned InvalidArgIndex = UINT_MAX;
+ unsigned Arg = InvalidArgIndex;
+ bool CanBeSubscript = false;
- if (findKnownClass(ID) == FC_NSString) {
+ if (Class == FC_NSString) {
Selector S = msg.getSelector();
if (S.isUnarySelector())
@@ -151,10 +180,58 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(msg.getArgSVal(0)))
- WarnNilArg(C, msg, 0);
+ Arg = 0;
+ }
+ } 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")) {
+ 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")) {
+ Arg = 0;
+ CanBeSubscript = true;
+ } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
+ Arg = 0;
+ }
+ } else if (Class == FC_NSDictionary) {
+ Selector S = msg.getSelector();
+
+ 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")) {
+ Arg = 0;
+ WarnIfNilArg(C, msg, /* Arg */1, Class);
+ } else if (S.getNameForSlot(0).equals("setObject") &&
+ S.getNameForSlot(1).equals("forKeyedSubscript")) {
+ CanBeSubscript = true;
+ Arg = 0;
+ WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
+ } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
+ Arg = 0;
}
}
+
+
+ // If argument is '0', report a warning.
+ if ((Arg != InvalidArgIndex))
+ WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
+
}
//===----------------------------------------------------------------------===//
@@ -195,28 +272,6 @@ enum CFNumberType {
kCFNumberCGFloatType = 16
};
-namespace {
- template<typename T>
- class Optional {
- bool IsKnown;
- T Val;
- public:
- Optional() : IsKnown(false), Val(0) {}
- Optional(const T& val) : IsKnown(true), Val(val) {}
-
- bool isKnown() const { return IsKnown; }
-
- const T& getValue() const {
- assert (isKnown());
- return Val;
- }
-
- operator const T&() const {
- return getValue();
- }
- };
-}
-
static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
@@ -238,7 +293,7 @@ static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
case kCFNumberCGFloatType:
// FIXME: We need a way to map from names to Type*.
default:
- return Optional<uint64_t>();
+ return None;
}
return Ctx.getTypeSize(T);
@@ -289,17 +344,19 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// FIXME: We really should allow ranges of valid theType values, and
// bifurcate the state appropriately.
- nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
+ Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
if (!V)
return;
uint64_t NumberKind = V->getValue().getLimitedValue();
- Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
+ Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
// FIXME: In some cases we can emit an error.
- if (!TargetSize.isKnown())
+ if (!OptTargetSize)
return;
+ uint64_t TargetSize = *OptTargetSize;
+
// Look at the value of the integer being passed by reference. Essentially
// we want to catch cases where the value passed in is not equal to the
// size of the type being created.
@@ -307,7 +364,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// FIXME: Eventually we should handle arbitrary locations. We can do this
// by having an enhanced memory model that does low-level typing.
- loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
+ Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
if (!LV)
return;
@@ -403,18 +460,19 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
return;
// FIXME: The rest of this just checks that the argument is non-null.
- // It should probably be refactored and combined with AttrNonNullChecker.
+ // It should probably be refactored and combined with NonNullParamChecker.
// Get the argument's value.
const Expr *Arg = CE->getArg(0);
SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
- DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
+ Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
if (!DefArgVal)
return;
// Get a NULL value.
SValBuilder &svalBuilder = C.getSValBuilder();
- DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
+ DefinedSVal zero =
+ svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
// Make an expression asserting that they're equal.
DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
@@ -605,7 +663,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
// Verify that all arguments have Objective-C types.
- llvm::Optional<ExplodedNode*> errorNode;
+ Optional<ExplodedNode*> errorNode;
ProgramStateRef state = C.getState();
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
@@ -618,7 +676,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
continue;
// Ignore pointer constants.
- if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
+ if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
continue;
// Ignore pointer types annotated with 'NSObject' attribute.
@@ -715,12 +773,12 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
ElementVar = State->getSVal(Element, C.getLocationContext());
}
- if (!isa<Loc>(ElementVar))
+ if (!ElementVar.getAs<Loc>())
return;
// Go ahead and assume the value is non-nil.
- SVal Val = State->getSVal(cast<Loc>(ElementVar));
- State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
+ SVal Val = State->getSVal(ElementVar.castAs<Loc>());
+ State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
C.addTransition(State);
}
@@ -744,7 +802,7 @@ static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) {
SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
- if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
+ if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
return State->assume(*DV, true);
return State;
}
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index 92edefe7b170..5169244a6f90 100644
--- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -13,17 +13,17 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
namespace {
class BoolAssignmentChecker : public Checker< check::Bind > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
void emitReport(ProgramStateRef state, CheckerContext &C) const;
public:
void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
@@ -69,7 +69,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// Get the value of the right-hand side. We only care about values
// that are defined (UnknownVals and UndefinedVals are handled by other
// checkers).
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&val);
+ Optional<DefinedSVal> DV = val.getAs<DefinedSVal>();
if (!DV)
return;
@@ -85,10 +85,10 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
SVal greaterThanOrEqualToZeroVal =
svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
svalBuilder.getConditionType());
-
- DefinedSVal *greaterThanEqualToZero =
- dyn_cast<DefinedSVal>(&greaterThanOrEqualToZeroVal);
-
+
+ Optional<DefinedSVal> greaterThanEqualToZero =
+ greaterThanOrEqualToZeroVal.getAs<DefinedSVal>();
+
if (!greaterThanEqualToZero) {
// The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it.
@@ -121,10 +121,10 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
SVal lessThanEqToOneVal =
svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal,
svalBuilder.getConditionType());
-
- DefinedSVal *lessThanEqToOne =
- dyn_cast<DefinedSVal>(&lessThanEqToOneVal);
-
+
+ Optional<DefinedSVal> lessThanEqToOne =
+ lessThanEqToOneVal.getAs<DefinedSVal>();
+
if (!lessThanEqToOne) {
// The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it.
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 6ef022b60925..a3327d8b3194 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Basic/Builtins.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/Basic/Builtins.h"
using namespace clang;
using namespace ento;
@@ -61,13 +61,14 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
// SVal of the argument directly. If we save the extent in bits, we
// cannot represent values like symbol*8.
DefinedOrUnknownSVal Size =
- cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin()), LCtx));
+ state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>();
SValBuilder& svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
DefinedOrUnknownSVal extentMatchesSizeArg =
svalBuilder.evalEQ(state, Extent, Size);
state = state->assume(extentMatchesSizeArg, true);
+ assert(state && "The region should not have any previous constraints");
C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
return true;
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 8e455de3bf46..b7df10e7ffbe 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -7,7 +7,6 @@ add_clang_library(clangStaticAnalyzerCheckers
AnalyzerStatsChecker.cpp
ArrayBoundChecker.cpp
ArrayBoundCheckerV2.cpp
- AttrNonNullChecker.cpp
BasicObjCFoundationChecks.cpp
BoolAssignmentChecker.cpp
BuiltinFunctionChecker.cpp
@@ -31,7 +30,6 @@ add_clang_library(clangStaticAnalyzerCheckers
DivZeroChecker.cpp
DynamicTypePropagation.cpp
ExprInspectionChecker.cpp
- SimpleStreamChecker.cpp
FixedAddressChecker.cpp
GenericTaintChecker.cpp
IdempotentOperationChecker.cpp
@@ -44,6 +42,7 @@ add_clang_library(clangStaticAnalyzerCheckers
MallocSizeofChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
+ NonNullParamChecker.cpp
NoReturnFunctionChecker.cpp
ObjCAtSyncChecker.cpp
ObjCContainersASTChecker.cpp
@@ -57,6 +56,7 @@ add_clang_library(clangStaticAnalyzerCheckers
RetainCountChecker.cpp
ReturnPointerRangeChecker.cpp
ReturnUndefChecker.cpp
+ SimpleStreamChecker.cpp
StackAddrEscapeChecker.cpp
StreamChecker.cpp
TaintTesterChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index eae9ddfc05b9..cc55e9f6ecf0 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -14,14 +14,16 @@
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
+#include "clang/Basic/CharInfo.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -63,7 +65,7 @@ public:
ProgramStateRef
checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *,
+ const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const;
@@ -199,7 +201,7 @@ REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
QualType Ty) {
- DefinedSVal *val = dyn_cast<DefinedSVal>(&V);
+ Optional<DefinedSVal> val = V.getAs<DefinedSVal>();
if (!val)
return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
@@ -276,10 +278,10 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
SValBuilder &svalBuilder = C.getSValBuilder();
SVal Extent =
svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
- DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Extent);
+ DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>();
// Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true);
ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false);
@@ -304,7 +306,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
SmallString<80> buf;
llvm::raw_svector_ostream os(buf);
- os << (char)toupper(CurrentFunctionDescription[0])
+ os << toUppercase(CurrentFunctionDescription[0])
<< &CurrentFunctionDescription[1]
<< " accesses out-of-bound array element";
report = new BugReport(*BT, os.str(), N);
@@ -357,18 +359,18 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
SVal LengthVal = state->getSVal(Size, LCtx);
- NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
+ Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return state;
// Compute the offset of the last element to be accessed: size-1.
- NonLoc One = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
- NonLoc LastOffset = cast<NonLoc>(svalBuilder.evalBinOpNN(state, BO_Sub,
- *Length, One, sizeTy));
+ NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
+ NonLoc LastOffset = svalBuilder
+ .evalBinOpNN(state, BO_Sub, *Length, One, sizeTy).castAs<NonLoc>();
// Check that the first buffer is sufficiently long.
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
- if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+ if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf);
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
@@ -388,7 +390,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
return NULL;
BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType());
- if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+ if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf);
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
@@ -424,11 +426,11 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
SVal firstVal = state->getSVal(First, LCtx);
SVal secondVal = state->getSVal(Second, LCtx);
- Loc *firstLoc = dyn_cast<Loc>(&firstVal);
+ Optional<Loc> firstLoc = firstVal.getAs<Loc>();
if (!firstLoc)
return state;
- Loc *secondLoc = dyn_cast<Loc>(&secondVal);
+ Optional<Loc> secondLoc = secondVal.getAs<Loc>();
if (!secondLoc)
return state;
@@ -451,7 +453,8 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
QualType cmpTy = svalBuilder.getConditionType();
SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT,
*firstLoc, *secondLoc, cmpTy);
- DefinedOrUnknownSVal *reverseTest = dyn_cast<DefinedOrUnknownSVal>(&reverse);
+ Optional<DefinedOrUnknownSVal> reverseTest =
+ reverse.getAs<DefinedOrUnknownSVal>();
if (!reverseTest)
return state;
@@ -462,20 +465,16 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
return state;
} else {
// Switch the values so that firstVal is before secondVal.
- Loc *tmpLoc = firstLoc;
- firstLoc = secondLoc;
- secondLoc = tmpLoc;
+ std::swap(firstLoc, secondLoc);
// Switch the Exprs as well, so that they still correspond.
- const Expr *tmpExpr = First;
- First = Second;
- Second = tmpExpr;
+ std::swap(First, Second);
}
}
// Get the length, and make sure it too is known.
SVal LengthVal = state->getSVal(Size, LCtx);
- NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
+ Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return state;
@@ -485,21 +484,22 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
First->getType());
- Loc *FirstStartLoc = dyn_cast<Loc>(&FirstStart);
+ Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
if (!FirstStartLoc)
return state;
// Compute the end of the first buffer. Bail out if THAT fails.
SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add,
*FirstStartLoc, *Length, CharPtrTy);
- Loc *FirstEndLoc = dyn_cast<Loc>(&FirstEnd);
+ Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
if (!FirstEndLoc)
return state;
// Is the end of the first buffer past the start of the second buffer?
SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT,
*FirstEndLoc, *secondLoc, cmpTy);
- DefinedOrUnknownSVal *OverlapTest = dyn_cast<DefinedOrUnknownSVal>(&Overlap);
+ Optional<DefinedOrUnknownSVal> OverlapTest =
+ Overlap.getAs<DefinedOrUnknownSVal>();
if (!OverlapTest)
return state;
@@ -555,7 +555,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
SVal maxMinusRight;
- if (isa<nonloc::ConcreteInt>(right)) {
+ if (right.getAs<nonloc::ConcreteInt>()) {
maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
sizeTy);
} else {
@@ -566,7 +566,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
left = right;
}
- if (NonLoc *maxMinusRightNL = dyn_cast<NonLoc>(&maxMinusRight)) {
+ if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
QualType cmpTy = svalBuilder.getConditionType();
// If left > max - right, we have an overflow.
SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
@@ -574,7 +574,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
ProgramStateRef stateOverflow, stateOkay;
llvm::tie(stateOverflow, stateOkay) =
- state->assume(cast<DefinedOrUnknownSVal>(willOverflow));
+ state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
if (stateOverflow && !stateOkay) {
// We have an overflow. Emit a bug report.
@@ -681,7 +681,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
// If we can't get a region, see if it's something we /know/ isn't a
// C string. In the context of locations, the only time we can issue such
// a warning is for labels.
- if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
+ if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
if (!Filter.CheckCStringNotNullTerm)
return UndefinedVal();
@@ -796,14 +796,14 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
ProgramStateRef state,
const Expr *E, SVal V) {
- Loc *L = dyn_cast<Loc>(&V);
+ Optional<Loc> L = V.getAs<Loc>();
if (!L)
return state;
// FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
// some assumptions about the value that CFRefCount can't. Even so, it should
// probably be refactored.
- if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(L)) {
+ if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
const MemRegion *R = MR->getRegion()->StripCasts();
// Are we dealing with an ElementRegion? If so, we should be invalidating
@@ -815,7 +815,8 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
// Invalidate this region.
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- return state->invalidateRegions(R, E, C.blockCount(), LCtx);
+ return state->invalidateRegions(R, E, C.blockCount(), LCtx,
+ /*CausesPointerEscape*/ false);
}
// If we have a non-region value by chance, just remove the binding.
@@ -926,16 +927,13 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// If this is mempcpy, get the byte after the last byte copied and
// bind the expr.
if (IsMempcpy) {
- loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
- assert(destRegVal && "Destination should be a known MemRegionVal here");
+ loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>();
// Get the length to copy.
- NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&sizeVal);
-
- if (lenValNonLoc) {
+ if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
// Get the byte after the last byte copied.
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
- *destRegVal,
+ destRegVal,
*lenValNonLoc,
Dest->getType());
@@ -1051,9 +1049,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// First, get the two buffers' addresses. Another checker will have already
// made sure they're not undefined.
DefinedOrUnknownSVal LV =
- cast<DefinedOrUnknownSVal>(state->getSVal(Left, LCtx));
+ state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>();
DefinedOrUnknownSVal RV =
- cast<DefinedOrUnknownSVal>(state->getSVal(Right, LCtx));
+ state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>();
// See if they are the same.
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
@@ -1163,19 +1161,17 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
const Expr *maxlenExpr = CE->getArg(1);
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
- NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
- NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
+ Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
if (strLengthNL && maxlenValNL) {
ProgramStateRef stateStringTooLong, stateStringNotTooLong;
// Check if the strLength is greater than the maxlen.
llvm::tie(stateStringTooLong, stateStringNotTooLong) =
- state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_GT,
- *strLengthNL,
- *maxlenValNL,
- cmpTy)));
+ 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.
@@ -1192,28 +1188,24 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// 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());
- NonLoc *resultNL = cast<NonLoc>(&result);
+ NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
- state = state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_LE,
- *resultNL,
- *strLengthNL,
- cmpTy)), true);
+ state = state->assume(C.getSValBuilder().evalBinOpNN(
+ state, BO_LE, resultNL, *strLengthNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>(), true);
}
if (maxlenValNL) {
- state = state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_LE,
- *resultNL,
- *maxlenValNL,
- cmpTy)), true);
+ state = state->assume(C.getSValBuilder().evalBinOpNN(
+ state, BO_LE, resultNL, *maxlenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>(), true);
}
}
} else {
// This is a plain strlen(), not strnlen().
- result = cast<DefinedOrUnknownSVal>(strLength);
+ result = strLength.castAs<DefinedOrUnknownSVal>();
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
@@ -1332,8 +1324,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Protect against misdeclared strncpy().
lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType());
- NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
- NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
+ Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
// If we know both values, we might be able to figure out how much
// we're copying.
@@ -1343,10 +1335,9 @@ 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(cast<DefinedOrUnknownSVal>
- (svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL,
- *lenValNL, cmpTy)));
+ llvm::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
+ svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>());
if (stateSourceTooLong && !stateSourceNotTooLong) {
// Max number to copy is less than the length of the src, so the actual
@@ -1373,7 +1364,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (dstStrLength.isUndef())
return;
- if (NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength)) {
+ if (Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>()) {
maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Add,
*lenValNL,
*dstStrLengthNL,
@@ -1404,7 +1395,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Otherwise, go ahead and figure out the last element we'll touch.
// We don't record the non-zero assumption here because we can't
// be sure. We won't warn on a possible zero.
- NonLoc one = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
+ NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
one, sizeTy);
boundWarning = "Size argument is greater than the length of the "
@@ -1422,15 +1413,15 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
amountCopied = getCStringLength(C, state, lenExpr, srcVal, true);
assert(!amountCopied.isUndef());
- if (NonLoc *amountCopiedNL = dyn_cast<NonLoc>(&amountCopied)) {
+ if (Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>()) {
if (lenValNL) {
// amountCopied <= lenVal
SVal copiedLessThanBound = svalBuilder.evalBinOpNN(state, BO_LE,
*amountCopiedNL,
*lenValNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(copiedLessThanBound),
- true);
+ state = state->assume(
+ copiedLessThanBound.castAs<DefinedOrUnknownSVal>(), true);
if (!state)
return;
}
@@ -1441,8 +1432,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
*amountCopiedNL,
*strLengthNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(copiedLessThanSrc),
- true);
+ state = state->assume(
+ copiedLessThanSrc.castAs<DefinedOrUnknownSVal>(), true);
if (!state)
return;
}
@@ -1472,8 +1463,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (dstStrLength.isUndef())
return;
- NonLoc *srcStrLengthNL = dyn_cast<NonLoc>(&amountCopied);
- NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength);
+ Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>();
+ Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
// If we know both string lengths, we might know the final string length.
if (srcStrLengthNL && dstStrLengthNL) {
@@ -1494,14 +1485,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
finalStrLength = getCStringLength(C, state, CE, DstVal, true);
assert(!finalStrLength.isUndef());
- if (NonLoc *finalStrLengthNL = dyn_cast<NonLoc>(&finalStrLength)) {
+ if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) {
if (srcStrLengthNL) {
// finalStrLength >= srcStrLength
SVal sourceInResult = svalBuilder.evalBinOpNN(state, BO_GE,
*finalStrLengthNL,
*srcStrLengthNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(sourceInResult),
+ state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
true);
if (!state)
return;
@@ -1513,8 +1504,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
*finalStrLengthNL,
*dstStrLengthNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(destInResult),
- true);
+ state =
+ state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true);
if (!state)
return;
}
@@ -1535,13 +1526,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If the destination is a MemRegion, try to check for a buffer overflow and
// record the new string length.
- if (loc::MemRegionVal *dstRegVal = dyn_cast<loc::MemRegionVal>(&DstVal)) {
+ if (Optional<loc::MemRegionVal> dstRegVal =
+ DstVal.getAs<loc::MemRegionVal>()) {
QualType ptrTy = Dst->getType();
// If we have an exact value on a bounded copy, use that to check for
// overflows, rather than our estimate about how much is actually copied.
if (boundWarning) {
- if (NonLoc *maxLastNL = dyn_cast<NonLoc>(&maxLastElementIndex)) {
+ if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*maxLastNL, ptrTy);
state = CheckLocation(C, state, CE->getArg(2), maxLastElement,
@@ -1552,7 +1544,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
// Then, if the final length is known...
- if (NonLoc *knownStrLength = dyn_cast<NonLoc>(&finalStrLength)) {
+ if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*knownStrLength, ptrTy);
@@ -1670,8 +1662,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// If we know the two buffers are the same, we know the result is 0.
// First, get the two buffers' addresses. Another checker will have already
// made sure they're not undefined.
- DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(s1Val);
- DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(s2Val);
+ DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>();
+ DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>();
// See if they are the same.
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -1856,8 +1848,8 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
SVal StrVal = state->getSVal(Init, C.getLocationContext());
assert(StrVal.isValid() && "Initializer string is unknown or undefined");
- DefinedOrUnknownSVal strLength
- = cast<DefinedOrUnknownSVal>(getCStringLength(C, state, Init, StrVal));
+ DefinedOrUnknownSVal strLength =
+ getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
state = state->set<CStringLength>(MR, strLength);
}
@@ -1872,7 +1864,7 @@ bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
ProgramStateRef
CStringChecker::checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *,
+ const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index f1a3aacc7c4c..3a57a56aea6e 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -13,14 +13,14 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TypeTraits.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 82bc1361acfe..4965d2299616 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -13,14 +13,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.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"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -75,6 +76,8 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
if (BadE) {
R->addRange(BadE->getSourceRange());
+ if (BadE->isGLValue())
+ BadE = bugreporter::getDerefExpr(BadE);
bugreporter::trackNullOrUndefValue(N, BadE, *R);
}
C.emitReport(R);
@@ -130,9 +133,9 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
if (!checkUninitFields)
return false;
-
- if (const nonloc::LazyCompoundVal *LV =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ if (Optional<nonloc::LazyCompoundVal> LV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
class FindUninitializedField {
public:
@@ -233,7 +236,8 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(L));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(L.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_call_null)
@@ -262,7 +266,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(V.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_cxx_call_null)
@@ -341,7 +346,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
} else {
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+ DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();
ProgramStateRef state = C.getState();
ProgramStateRef notNilState, nilState;
@@ -361,17 +366,23 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
if (!BT_msg_ret)
BT_msg_ret.reset(
- new BuiltinBug("Receiver in message expression is "
- "'nil' and returns a garbage value"));
+ new BuiltinBug("Receiver in message expression is 'nil'"));
const ObjCMessageExpr *ME = msg.getOriginExpr();
+ QualType ResTy = msg.getResultType();
+
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString()
- << "' is nil and returns a value of type '";
- msg.getResultType().print(os, C.getLangOpts());
- os << "' that will be garbage";
+ << "' is nil";
+ if (ResTy->isReferenceType()) {
+ os << ", which results in forming a null reference";
+ } else {
+ os << " and returns a value of type '";
+ msg.getResultType().print(os, C.getLangOpts());
+ os << "' that will be garbage";
+ }
BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
report->addRange(ME->getReceiverRange());
@@ -392,6 +403,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
const ObjCMethodCall &Msg) const {
ASTContext &Ctx = C.getASTContext();
+ static SimpleProgramPointTag Tag("CallAndMessageChecker : 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.
@@ -402,7 +414,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
- C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
@@ -413,14 +425,15 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
- if (voidPtrSize < returnTypeSize &&
- !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
- (Ctx.FloatTy == CanRetTy ||
- Ctx.DoubleTy == CanRetTy ||
- Ctx.LongDoubleTy == CanRetTy ||
- Ctx.LongLongTy == CanRetTy ||
- Ctx.UnsignedLongLongTy == CanRetTy))) {
- if (ExplodedNode *N = C.generateSink(state))
+ if (CanRetTy.getTypePtr()->isReferenceType()||
+ (voidPtrSize < returnTypeSize &&
+ !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
+ (Ctx.FloatTy == CanRetTy ||
+ Ctx.DoubleTy == CanRetTy ||
+ Ctx.LongDoubleTy == CanRetTy ||
+ Ctx.LongLongTy == CanRetTy ||
+ Ctx.UnsignedLongLongTy == CanRetTy)))) {
+ if (ExplodedNode *N = C.generateSink(state, 0 , &Tag))
emitNilReceiverBug(C, Msg, N);
return;
}
@@ -439,7 +452,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
- C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 1cb8a8de7348..5e6e10541483 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.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/BugReporter/BugType.h"
-#include "clang/AST/CharUnits.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index d6d0e3c7b3b8..60348c73584b 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 90872058af55..3f9b3cc7f805 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -14,14 +14,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Expr.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index 6df47b1d9998..9cb1d2d6909b 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -14,13 +14,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ASTContext.h"
-
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 5cd61941841d..7ef13ab53865 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -36,13 +36,6 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) {
}
namespace {
-struct DefaultBool {
- bool val;
- DefaultBool() : val(false) {}
- operator bool() const { return val; }
- DefaultBool &operator=(bool b) { val = b; return *this; }
-};
-
struct ChecksFilter {
DefaultBool check_gets;
DefaultBool check_getpw;
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index cc7fd37ff602..f2c50501a65c 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -14,8 +14,8 @@
#include "ClangSACheckers.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
using namespace clang;
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index efaec2b3f1e3..a9dd19a395c5 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
using namespace clang;
@@ -44,13 +44,15 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
check::Location,
check::Bind,
check::DeadSymbols,
- check::EndPath,
+ check::EndFunction,
check::EndAnalysis,
check::EndOfTranslationUnit,
eval::Call,
eval::Assume,
check::LiveSymbols,
check::RegionChanges,
+ check::PointerEscape,
+ check::ConstPointerEscape,
check::Event<ImplicitNullDerefEvent>,
check::ASTDecl<FunctionDecl> > {
public:
@@ -152,11 +154,11 @@ public:
/// check::DeadSymbols
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const {}
- /// \brief Called when the analyzer core reaches the end of the top-level
+ /// \brief Called when the analyzer core reaches the end of a
/// function being analyzed.
///
- /// check::EndPath
- void checkEndPath(CheckerContext &Ctx) const {}
+ /// check::EndFunction
+ void checkEndFunction(CheckerContext &Ctx) const {}
/// \brief Called after all the paths in the ExplodedGraph reach end of path
/// - the symbolic execution graph is fully explored.
@@ -246,13 +248,44 @@ public:
/// check::RegionChanges
ProgramStateRef
checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *Invalidated,
+ const InvalidatedSymbols *Invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
return State;
}
+ /// \brief Called when pointers escape.
+ ///
+ /// This notifies the checkers about pointer escape, which occurs whenever
+ /// the analyzer cannot track the symbol any more. For example, as a
+ /// result of assigning a pointer into a global or when it's passed to a
+ /// function call the analyzer cannot model.
+ ///
+ /// \param State The state at the point of escape.
+ /// \param Escaped The list of escaped symbols.
+ /// \param Call The corresponding CallEvent, if the symbols escape as
+ /// parameters to the given call.
+ /// \param Kind How the symbols have escaped.
+ /// \returns Checkers can modify the state by returning a new state.
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return State;
+ }
+
+ /// \brief Called when const pointers escape.
+ ///
+ /// Note: in most cases checkPointerEscape callback is sufficient.
+ /// \sa checkPointerEscape
+ ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return State;
+ }
+
/// check::Event<ImplicitNullDerefEvent>
void checkEvent(ImplicitNullDerefEvent Event) const {}
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 235e63306f04..3db3fb9962a5 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -60,9 +60,9 @@ def CallAndMessageChecker : Checker<"CallAndMessage">,
HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
DescFile<"CallAndMessageChecker.cpp">;
-def AttrNonNullChecker : Checker<"AttributeNonNull">,
- HelpText<"Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute">,
- DescFile<"AttrNonNullChecker.cpp">;
+def NonNullParamChecker : Checker<"NonNullParamChecker">,
+ HelpText<"Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute">,
+ DescFile<"NonNullParamChecker.cpp">;
def VLASizeChecker : Checker<"VLASize">,
HelpText<"Check for declarations of VLA of undefined or zero size">,
@@ -166,12 +166,19 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
// C++ checkers.
//===----------------------------------------------------------------------===//
+let ParentPackage = Cplusplus in {
+} // end: "cplusplus"
+
let ParentPackage = CplusplusAlpha in {
def VirtualCallChecker : Checker<"VirtualCall">,
HelpText<"Check virtual function calls during construction or destruction">,
DescFile<"VirtualCallChecker.cpp">;
+def NewDeleteChecker : Checker<"NewDelete">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by new/delete.">,
+ DescFile<"MallocChecker.cpp">;
+
} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
@@ -276,12 +283,16 @@ def UnixAPIChecker : Checker<"API">,
DescFile<"UnixAPIChecker.cpp">;
def MallocPessimistic : Checker<"Malloc">,
- HelpText<"Check for memory leaks, double free, and use-after-free problems.">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
DescFile<"MallocChecker.cpp">;
def MallocSizeofChecker : Checker<"MallocSizeof">,
HelpText<"Check for dubious malloc arguments involving sizeof">,
DescFile<"MallocSizeofChecker.cpp">;
+
+def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
+ HelpText<"Check for mismatched deallocators.">,
+ DescFile<"MallocChecker.cpp">;
} // end "unix"
@@ -292,7 +303,7 @@ def ChrootChecker : Checker<"Chroot">,
DescFile<"ChrootChecker.cpp">;
def MallocOptimistic : Checker<"MallocWithAnnotations">,
- HelpText<"Check for memory leaks, double free, and use-after-free problems. Assumes that all user-defined functions which might free a pointer are annotated.">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free(). Assumes that all user-defined functions which might free a pointer are annotated.">,
DescFile<"MallocChecker.cpp">;
def PthreadLockChecker : Checker<"PthreadLock">,
@@ -343,7 +354,7 @@ let ParentPackage = OSX in {
def MacOSXAPIChecker : Checker<"API">,
InPackage<OSX>,
- HelpText<"Check for proper uses of various Mac OS X APIs">,
+ HelpText<"Check for proper uses of various Apple APIs">,
DescFile<"MacOSXAPIChecker.cpp">;
def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
@@ -351,7 +362,7 @@ def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
HelpText<"Check for proper uses of Secure Keychain APIs">,
DescFile<"MacOSKeychainAPIChecker.cpp">;
-} // end "macosx"
+} // end "osx"
let ParentPackage = Cocoa in {
@@ -412,12 +423,20 @@ def ObjCDeallocChecker : Checker<"Dealloc">,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
DescFile<"CheckObjCDealloc.cpp">;
-def IvarInvalidationChecker : Checker<"InstanceVariableInvalidation">,
+def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
DescFile<"IvarInvalidationChecker.cpp">;
+def MissingInvalidationMethod : Checker<"MissingInvalidationMethod">,
+ HelpText<"Check that the invalidation methods are present in classes that contain invalidatable instance variables">,
+ DescFile<"IvarInvalidationChecker.cpp">;
+
def DirectIvarAssignment : Checker<"DirectIvarAssignment">,
- HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
+ HelpText<"Check for direct assignments to instance variables">,
+ DescFile<"DirectIvarAssignment.cpp">;
+
+def DirectIvarAssignmentForAnnotatedFunctions : Checker<"DirectIvarAssignmentForAnnotatedFunctions">,
+ 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">,
@@ -515,4 +534,3 @@ def ExprInspectionChecker : Checker<"ExprInspection">,
DescFile<"ExprInspectionChecker.cpp">;
} // end "debug"
-
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index c8856162fe89..991296538a5b 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index 230baa759c5a..bea908dfa687 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/CommonBugCategories.h"
-
#ifndef LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
#define LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
+#include "clang/StaticAnalyzer/Checkers/CommonBugCategories.h"
+
namespace clang {
namespace ento {
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 59e03ecd5c61..f2e3e6d7815e 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -14,6 +14,7 @@
#include "ClangSACheckers.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
@@ -125,7 +126,7 @@ class DeadStoreObs : public LiveVariables::Observer {
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
OwningPtr<ReachableCode> reachableCode;
const CFGBlock *currentBlock;
- llvm::OwningPtr<llvm::DenseSet<const VarDecl *> > InEH;
+ OwningPtr<llvm::DenseSet<const VarDecl *> > InEH;
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
@@ -418,6 +419,15 @@ class DeadStoresChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
+
+ // Don't do anything for template instantiations.
+ // Proving that code in a template instantiation is "dead"
+ // means proving that it is dead in all instantiations.
+ // This same problem exists with -Wunreachable-code.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isTemplateInstantiation())
+ return;
+
if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
CFG &cfg = *mgr.getCFG(D);
AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 7ad9c59a1bb2..29b4a637cda4 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/Dominators.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CallGraph.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/Support/Process.h"
using namespace clang;
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 3ace4be44804..72d46c50e109 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -14,11 +14,12 @@
#include "ClangSACheckers.h"
#include "clang/AST/ExprObjC.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/BugReporter/BugType.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -75,6 +76,14 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
Ranges.push_back(SourceRange(L, L));
break;
}
+ case Stmt::ObjCIvarRefExprClass: {
+ const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
+ os << " (" << (loadedFrom ? "loaded from" : "via")
+ << " ivar '" << IV->getDecl()->getName() << "')";
+ SourceLocation L = IV->getLocation();
+ Ranges.push_back(SourceRange(L, L));
+ break;
+ }
}
}
@@ -156,7 +165,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
buf.empty() ? BT_null->getDescription() : buf.str(),
N);
- bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S), *report);
for (SmallVectorImpl<SourceRange>::iterator
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
@@ -175,17 +184,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N),
+ bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S),
*report);
C.emitReport(report);
}
return;
}
- DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
+ DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
// Check for null dereferences.
- if (!isa<Loc>(location))
+ if (!location.getAs<Loc>())
return;
ProgramStateRef state = C.getState();
@@ -230,7 +239,8 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
ProgramStateRef State = C.getState();
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V));
+ llvm::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 dc90b67e20fa..6d3dd1e42f02 100644
--- a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -7,18 +7,27 @@
//
//===----------------------------------------------------------------------===//
//
-// Check that Objective C properties follow the following rules:
-// - The property should be set with the setter, not though a direct
-// assignment.
+// Check that Objective C properties are set with the setter, not though a
+// direct assignment.
+//
+// Two versions of a checker exist: one that checks all methods and the other
+// that only checks the methods annotated with
+// __attribute__((annotate("objc_no_direct_instance_variable_assignment")))
+//
+// The checker does not warn about assignments to Ivars, annotated with
+// __attribute__((objc_allow_direct_instance_variable_assignment"))). This
+// annotation serves as a false positive suppression mechanism for the
+// checker. The annotation is allowed on properties and Ivars.
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/DenseMap.h"
using namespace clang;
@@ -26,6 +35,27 @@ using namespace ento;
namespace {
+/// The default method filter, which is used to filter out the methods on which
+/// the check should not be performed.
+///
+/// Checks for the init, dealloc, and any other functions that might be allowed
+/// to perform direct instance variable assignment based on their name.
+struct MethodFilter {
+ virtual ~MethodFilter() {}
+ virtual bool operator()(ObjCMethodDecl *M) {
+ if (M->getMethodFamily() == OMF_init ||
+ M->getMethodFamily() == OMF_dealloc ||
+ M->getMethodFamily() == OMF_copy ||
+ M->getMethodFamily() == OMF_mutableCopy ||
+ M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
+ M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
+ return true;
+ return false;
+ }
+};
+
+static MethodFilter DefaultMethodFilter;
+
class DirectIvarAssignment :
public Checker<check::ASTDecl<ObjCImplementationDecl> > {
@@ -59,6 +89,10 @@ class DirectIvarAssignment :
};
public:
+ MethodFilter *ShouldSkipMethod;
+
+ DirectIvarAssignment() : ShouldSkipMethod(&DefaultMethodFilter) {}
+
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
BugReporter &BR) const;
};
@@ -118,14 +152,7 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
ObjCMethodDecl *M = *I;
AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M);
- // Skip the init, dealloc functions and any functions that might be doing
- // initialization based on their name.
- if (M->getMethodFamily() == OMF_init ||
- M->getMethodFamily() == OMF_dealloc ||
- M->getMethodFamily() == OMF_copy ||
- M->getMethodFamily() == OMF_mutableCopy ||
- M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
- M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
+ if ((*ShouldSkipMethod)(M))
continue;
const Stmt *Body = M->getBody();
@@ -136,6 +163,18 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
}
}
+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;
+ if (Ann->getAnnotation() ==
+ "objc_allow_direct_instance_variable_assignment")
+ return true;
+ }
+ return false;
+}
+
void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
const BinaryOperator *BO) {
if (!BO->isAssignmentOp())
@@ -149,8 +188,16 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
if (const ObjCIvarDecl *D = IvarRef->getDecl()) {
IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D);
+
if (I != IvarToPropMap.end()) {
const ObjCPropertyDecl *PD = I->second;
+ // Skip warnings on Ivars, annotated with
+ // objc_allow_direct_instance_variable_assignment. This annotation serves
+ // as a false positive suppression mechanism for the checker. The
+ // annotation is allowed on properties and ivars.
+ if (isAnnotatedToAllowDirectAssignment(PD) ||
+ isAnnotatedToAllowDirectAssignment(D))
+ return;
ObjCMethodDecl *GetterMethod =
InterfD->getInstanceMethod(PD->getGetterName());
@@ -175,6 +222,33 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
}
}
+// Register the checker that checks for direct accesses in all functions,
+// except for the initialization and copy routines.
void ento::registerDirectIvarAssignment(CheckerManager &mgr) {
mgr.registerChecker<DirectIvarAssignment>();
}
+
+// Register the checker that checks for direct accesses in functions annotated
+// with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))).
+namespace {
+struct InvalidatorMethodFilter : MethodFilter {
+ virtual ~InvalidatorMethodFilter() {}
+ virtual bool operator()(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;
+ if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
+ return false;
+ }
+ return true;
+ }
+};
+
+InvalidatorMethodFilter AttrFilter;
+}
+
+void ento::registerDirectIvarAssignmentForAnnotatedFunctions(
+ CheckerManager &mgr) {
+ mgr.registerChecker<DirectIvarAssignment>()->ShouldSkipMethod = &AttrFilter;
+}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 76fb3f2b288e..93daf94fbe32 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
@@ -58,7 +58,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
return;
SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
+ Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
// Divide-by-undefined handled in the generic checking for uses of
// undefined values.
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index b0a4bc67485e..9f176a4b5bf7 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Basic/Builtins.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/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Basic/Builtins.h"
using namespace clang;
using namespace ento;
@@ -110,38 +110,40 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
return;
ProgramStateRef State = C.getState();
-
- switch (Msg->getMethodFamily()) {
- default:
- break;
-
- // We assume that the type of the object returned by alloc and new are the
- // pointer to the object of the class specified in the receiver of the
- // message.
- case OMF_alloc:
- case OMF_new: {
- // Get the type of object that will get created.
- const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
- const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
- if (!ObjTy)
- return;
- QualType DynResTy =
+ const ObjCMethodDecl *D = Msg->getDecl();
+
+ if (D && D->hasRelatedResultType()) {
+ switch (Msg->getMethodFamily()) {
+ default:
+ break;
+
+ // We assume that the type of the object returned by alloc and new are the
+ // pointer to the object of the class specified in the receiver of the
+ // message.
+ case OMF_alloc:
+ case OMF_new: {
+ // Get the type of object that will get created.
+ const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
+ const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
+ if (!ObjTy)
+ return;
+ QualType DynResTy =
C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
- C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
- break;
- }
- case OMF_init: {
- // Assume, the result of the init method has the same dynamic type as
- // the receiver and propagate the dynamic type info.
- const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
- if (!RecReg)
- return;
- DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
- C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
- break;
- }
+ C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
+ break;
+ }
+ case OMF_init: {
+ // Assume, the result of the init method has the same dynamic type as
+ // the receiver and propagate the dynamic type info.
+ const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
+ if (!RecReg)
+ return;
+ DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
+ C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
+ break;
+ }
+ }
}
-
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index e7e316281faa..810473f1a6e0 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -8,9 +8,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace ento;
@@ -64,7 +65,7 @@ static const char *getArgumentValueString(const CallExpr *CE,
ProgramStateRef StTrue, StFalse;
llvm::tie(StTrue, StFalse) =
- State->assume(cast<DefinedOrUnknownSVal>(AssertionVal));
+ State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
if (StTrue) {
if (StFalse)
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 7fde68923124..085a991f7866 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index a9e02173c3a9..c67c597feced 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -15,12 +15,13 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/Builtins.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/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Basic/Builtins.h"
#include <climits>
using namespace clang;
@@ -102,7 +103,7 @@ private:
CheckerContext &C) const;
- typedef llvm::SmallVector<unsigned, 2> ArgVector;
+ typedef SmallVector<unsigned, 2> ArgVector;
/// \brief A struct used to specify taint propagation rules for a function.
///
@@ -430,7 +431,7 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
if (AddrVal.isUnknownOrUndef())
return 0;
- Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
+ Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
if (!AddrLoc)
return 0;
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index ffbbb8b68d8a..271ba4702c57 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -43,23 +43,24 @@
// - Handling ~0 values
#include "ClangSACheckers.h"
-#include "clang/Analysis/CFGStmtMap.h"
-#include "clang/Analysis/Analyses/PseudoConstantAnalysis.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/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/AST/Stmt.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -172,11 +173,11 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
case BO_ShrAssign:
case BO_Assign:
// Assign statements have one extra level of indirection
- if (!isa<Loc>(LHSVal)) {
+ if (!LHSVal.getAs<Loc>()) {
A = Impossible;
return;
}
- LHSVal = state->getSVal(cast<Loc>(LHSVal), LHS->getType());
+ LHSVal = state->getSVal(LHSVal.castAs<Loc>(), LHS->getType());
}
@@ -331,9 +332,9 @@ void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B,
// Add the ExplodedNode we just visited
BinaryOperatorData &Data = hash[B];
- const Stmt *predStmt
- = cast<StmtPoint>(C.getPredecessor()->getLocation()).getStmt();
-
+ const Stmt *predStmt =
+ C.getPredecessor()->getLocation().castAs<StmtPoint>().getStmt();
+
// Ignore implicit calls to setters.
if (!isa<BinaryOperator>(predStmt))
return;
@@ -422,12 +423,12 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
if (LHSRelevant) {
const Expr *LHS = i->first->getLHS();
report->addRange(LHS->getSourceRange());
- FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS);
+ FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS, false);
}
if (RHSRelevant) {
const Expr *RHS = i->first->getRHS();
report->addRange(i->first->getRHS()->getSourceRange());
- FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS);
+ FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS, false);
}
BR.emitReport(report);
@@ -581,16 +582,13 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisDeclContext *AC,
virtual bool visit(const WorkListUnit &U) {
ProgramPoint P = U.getNode()->getLocation();
const CFGBlock *B = 0;
- if (StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+ if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
B = CBM->getBlock(SP->getStmt());
- }
- else if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
B = BE->getDst();
- }
- else if (BlockEntrance *BEnt = dyn_cast<BlockEntrance>(&P)) {
+ } else if (Optional<BlockEntrance> BEnt = P.getAs<BlockEntrance>()) {
B = BEnt->getBlock();
- }
- else if (BlockExit *BExit = dyn_cast<BlockExit>(&P)) {
+ } else if (Optional<BlockExit> BExit = P.getAs<BlockExit>()) {
B = BExit->getBlock();
}
if (!B)
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index bf256cd9fa45..5ed28e955d4e 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -20,25 +20,40 @@
// been called on them. An invalidation method should either invalidate all
// the ivars or call another invalidation method (on self).
//
+// Partial invalidor annotation allows to addess cases when ivars are
+// invalidated by other methods, which might or might not be called from
+// the invalidation method. The checker checks that each invalidation
+// method and all the partial methods cumulatively invalidate all ivars.
+// __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
namespace {
-class IvarInvalidationChecker :
- public Checker<check::ASTDecl<ObjCMethodDecl> > {
- typedef llvm::DenseSet<const ObjCMethodDecl*> MethodSet;
+struct ChecksFilter {
+ /// Check for missing invalidation method declarations.
+ DefaultBool check_MissingInvalidationMethod;
+ /// Check that all ivars are invalidated.
+ DefaultBool check_InstanceVariableInvalidation;
+};
+
+class IvarInvalidationCheckerImpl {
+
+ typedef llvm::SmallSetVector<const ObjCMethodDecl*, 2> MethodSet;
typedef llvm::DenseMap<const ObjCMethodDecl*,
const ObjCIvarDecl*> MethToIvarMapTy;
typedef llvm::DenseMap<const ObjCPropertyDecl*,
@@ -47,14 +62,14 @@ class IvarInvalidationChecker :
const ObjCPropertyDecl*> IvarToPropMapTy;
- struct IvarInfo {
+ struct InvalidationInfo {
/// Has the ivar been invalidated?
bool IsInvalidated;
/// The methods which can be used to invalidate the ivar.
MethodSet InvalidationMethods;
- IvarInfo() : IsInvalidated(false) {}
+ InvalidationInfo() : IsInvalidated(false) {}
void addInvalidationMethod(const ObjCMethodDecl *MD) {
InvalidationMethods.insert(MD);
}
@@ -63,11 +78,7 @@ class IvarInvalidationChecker :
return !InvalidationMethods.empty();
}
- void markInvalidated() {
- IsInvalidated = true;
- }
-
- bool markInvalidated(const ObjCMethodDecl *MD) {
+ bool hasMethod(const ObjCMethodDecl *MD) {
if (IsInvalidated)
return true;
for (MethodSet::iterator I = InvalidationMethods.begin(),
@@ -79,13 +90,9 @@ class IvarInvalidationChecker :
}
return false;
}
-
- bool isInvalidated() const {
- return IsInvalidated;
- }
};
- typedef llvm::DenseMap<const ObjCIvarDecl*, IvarInfo> IvarSet;
+ typedef llvm::DenseMap<const ObjCIvarDecl*, InvalidationInfo> IvarSet;
/// Statement visitor, which walks the method body and flags the ivars
/// referenced in it (either directly or via property).
@@ -168,12 +175,16 @@ class IvarInvalidationChecker :
/// Check if the any of the methods inside the interface are annotated with
/// the invalidation annotation, update the IvarInfo accordingly.
+ /// \param LookForPartial is set when we are searching for partial
+ /// invalidators.
static void containsInvalidationMethod(const ObjCContainerDecl *D,
- IvarInfo &Out);
+ InvalidationInfo &Out,
+ bool LookForPartial);
/// Check if ivar should be tracked and add to TrackedIvars if positive.
/// Returns true if ivar should be tracked.
- static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars);
+ static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl);
/// Given the property declaration, and the list of tracked ivars, finds
/// the ivar backing the property when possible. Returns '0' when no such
@@ -181,54 +192,90 @@ class IvarInvalidationChecker :
static const ObjCIvarDecl *findPropertyBackingIvar(
const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD,
- IvarSet &TrackedIvars);
+ IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl);
+
+ /// Print ivar name or the property if the given ivar backs a property.
+ static void printIvar(llvm::raw_svector_ostream &os,
+ const ObjCIvarDecl *IvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap);
+
+ void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCInterfaceDecl *InterfaceD,
+ bool MissingDeclaration) const;
+ void reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCMethodDecl *MethodD) const;
+
+ AnalysisManager& Mgr;
+ BugReporter &BR;
+ /// Filter on the checks performed.
+ const ChecksFilter &Filter;
public:
- void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr,
- BugReporter &BR) const;
+ IvarInvalidationCheckerImpl(AnalysisManager& InMgr,
+ BugReporter &InBR,
+ const ChecksFilter &InFilter) :
+ Mgr (InMgr), BR(InBR), Filter(InFilter) {}
- // TODO: We are currently ignoring the ivars coming from class extensions.
+ void visit(const ObjCImplementationDecl *D) const;
};
-static bool isInvalidationMethod(const ObjCMethodDecl *M) {
+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;
- if (Ann->getAnnotation() == "objc_instance_variable_invalidator")
+ if (!LookForPartial &&
+ Ann->getAnnotation() == "objc_instance_variable_invalidator")
+ return true;
+ if (LookForPartial &&
+ Ann->getAnnotation() == "objc_instance_variable_invalidator_partial")
return true;
}
return false;
}
-void IvarInvalidationChecker::containsInvalidationMethod(
- const ObjCContainerDecl *D, IvarInfo &OutInfo) {
-
- // TODO: Cache the results.
+void IvarInvalidationCheckerImpl::containsInvalidationMethod(
+ const ObjCContainerDecl *D, InvalidationInfo &OutInfo, bool Partial) {
if (!D)
return;
+ assert(!isa<ObjCImplementationDecl>(D));
+ // 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))
+ if (isInvalidationMethod(MDI, Partial))
OutInfo.addInvalidationMethod(
cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
}
// If interface, check all parent protocols and super.
- // TODO: Visit all categories in case the invalidation method is declared in
- // a category.
- if (const ObjCInterfaceDecl *InterfaceD = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (const ObjCInterfaceDecl *InterfD = dyn_cast<ObjCInterfaceDecl>(D)) {
+
+ // Visit all protocols.
for (ObjCInterfaceDecl::protocol_iterator
- I = InterfaceD->protocol_begin(),
- E = InterfaceD->protocol_end(); I != E; ++I) {
- containsInvalidationMethod(*I, OutInfo);
+ I = InterfD->protocol_begin(),
+ E = InterfD->protocol_end(); I != E; ++I) {
+ 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);
}
- containsInvalidationMethod(InterfaceD->getSuperClass(), OutInfo);
+
+ containsInvalidationMethod(InterfD->getSuperClass(), OutInfo, Partial);
return;
}
@@ -237,45 +284,52 @@ void IvarInvalidationChecker::containsInvalidationMethod(
for (ObjCInterfaceDecl::protocol_iterator
I = ProtD->protocol_begin(),
E = ProtD->protocol_end(); I != E; ++I) {
- containsInvalidationMethod(*I, OutInfo);
+ containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
}
return;
}
- llvm_unreachable("One of the casts above should have succeeded.");
+ return;
}
-bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
- IvarSet &TrackedIvars) {
+bool IvarInvalidationCheckerImpl::trackIvar(const ObjCIvarDecl *Iv,
+ IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl) {
QualType IvQTy = Iv->getType();
const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
if (!IvTy)
return false;
const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl();
- IvarInfo Info;
- containsInvalidationMethod(IvInterf, Info);
+ InvalidationInfo Info;
+ containsInvalidationMethod(IvInterf, Info, /*LookForPartial*/ false);
if (Info.needsInvalidation()) {
- TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info;
+ const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl());
+ TrackedIvars[I] = Info;
+ if (!*FirstIvarDecl)
+ *FirstIvarDecl = I;
return true;
}
return false;
}
-const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
+const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD,
- IvarSet &TrackedIvars) {
+ IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl) {
const ObjCIvarDecl *IvarD = 0;
// Lookup for the synthesized case.
IvarD = Prop->getPropertyIvarDecl();
- if (IvarD) {
+ // We only track the ivars/properties that are defined in the current
+ // class (not the parent).
+ if (IvarD && IvarD->getContainingInterface() == InterfaceD) {
if (TrackedIvars.count(IvarD)) {
return IvarD;
}
// If the ivar is synthesized we still want to track it.
- if (trackIvar(IvarD, TrackedIvars))
+ if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl))
return IvarD;
}
@@ -304,22 +358,35 @@ const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
return 0;
}
-void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D,
- AnalysisManager& Mgr,
- BugReporter &BR) const {
- // We are only interested in checking the cleanup methods.
- if (!D->hasBody() || !isInvalidationMethod(D))
- return;
+void IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os,
+ const ObjCIvarDecl *IvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap) {
+ if (IvarDecl->getSynthesize()) {
+ const ObjCPropertyDecl *PD = IvarToPopertyMap.lookup(IvarDecl);
+ assert(PD &&"Do we synthesize ivars for something other than properties?");
+ os << "Property "<< PD->getName() << " ";
+ } else {
+ os << "Instance variable "<< IvarDecl->getName() << " ";
+ }
+}
+// Check that the invalidatable interfaces with ivars/properties implement the
+// invalidation methods.
+void IvarInvalidationCheckerImpl::
+visit(const ObjCImplementationDecl *ImplD) const {
// Collect all ivars that need cleanup.
IvarSet Ivars;
- const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
+ // 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 ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface();
// Collect ivars declared in this class, its extensions and its implementation
ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD);
for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
Iv= Iv->getNextIvar())
- trackIvar(Iv, Ivars);
+ trackIvar(Iv, Ivars, &FirstIvarDecl);
// Construct Property/Property Accessor to Ivar maps to assist checking if an
// ivar which is backing a property has been reset.
@@ -329,16 +396,17 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D,
IvarToPropMapTy IvarToPopertyMap;
ObjCInterfaceDecl::PropertyMap PropMap;
- InterfaceD->collectPropertiesToImplement(PropMap);
+ ObjCInterfaceDecl::PropertyDeclOrder PropOrder;
+ InterfaceD->collectPropertiesToImplement(PropMap, PropOrder);
for (ObjCInterfaceDecl::PropertyMap::iterator
I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
const ObjCPropertyDecl *PD = I->second;
- const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars);
- if (!ID) {
+ const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars,
+ &FirstIvarDecl);
+ if (!ID)
continue;
- }
// Store the mappings.
PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
@@ -359,66 +427,159 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D,
}
}
+ // If no ivars need invalidation, there is nothing to check here.
+ if (Ivars.empty())
+ return;
+
+ // Find all partial invalidation methods.
+ InvalidationInfo PartialInfo;
+ containsInvalidationMethod(InterfaceD, PartialInfo, /*LookForPartial*/ true);
+
+ // Remove ivars invalidated by the partial invalidation methods. They do not
+ // need to be invalidated in the regular invalidation methods.
+ for (MethodSet::iterator
+ I = PartialInfo.InvalidationMethods.begin(),
+ E = PartialInfo.InvalidationMethods.end(); I != E; ++I) {
+ const ObjCMethodDecl *InterfD = *I;
+
+ // Get the corresponding method in the @implementation.
+ const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
+ InterfD->isInstanceMethod());
+ if (D && D->hasBody()) {
+ bool CalledAnotherInvalidationMethod = false;
+ // The MethodCrowler is going to remove the invalidated ivars.
+ MethodCrawler(Ivars,
+ CalledAnotherInvalidationMethod,
+ PropSetterToIvarMap,
+ PropGetterToIvarMap,
+ PropertyToIvarMap,
+ BR.getContext()).VisitStmt(D->getBody());
+ // If another invalidation method was called, trust that full invalidation
+ // has occurred.
+ if (CalledAnotherInvalidationMethod)
+ Ivars.clear();
+ }
+ }
- // Check which ivars have been invalidated in the method body.
- bool CalledAnotherInvalidationMethod = false;
- MethodCrawler(Ivars,
- CalledAnotherInvalidationMethod,
- PropSetterToIvarMap,
- PropGetterToIvarMap,
- PropertyToIvarMap,
- BR.getContext()).VisitStmt(D->getBody());
+ // If all ivars have been invalidated by partial invalidators, there is
+ // nothing to check here.
+ if (Ivars.empty())
+ return;
- if (CalledAnotherInvalidationMethod)
+ // Find all invalidation methods in this @interface declaration and parents.
+ InvalidationInfo Info;
+ containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
+
+ // Report an error in case none of the invalidation methods are declared.
+ if (!Info.needsInvalidation()) {
+ if (Filter.check_MissingInvalidationMethod)
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ /*MissingDeclaration*/ true);
+ // If there are no invalidation methods, there is no ivar validation work
+ // to be done.
return;
+ }
- // Warn on the ivars that were not accessed by the method.
- for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I){
- if (!I->second.isInvalidated()) {
- const ObjCIvarDecl *IvarDecl = I->first;
-
- PathDiagnosticLocation IvarDecLocation =
- PathDiagnosticLocation::createEnd(D->getBody(), BR.getSourceManager(),
- Mgr.getAnalysisDeclContext(D));
-
- SmallString<128> sbuf;
- llvm::raw_svector_ostream os(sbuf);
-
- // Construct the warning message.
- if (IvarDecl->getSynthesize()) {
- const ObjCPropertyDecl *PD = IvarToPopertyMap[IvarDecl];
- assert(PD &&
- "Do we synthesize ivars for something other than properties?");
- os << "Property "<< PD->getName() <<
- " needs to be invalidated or set to nil";
- } else {
- os << "Instance variable "<< IvarDecl->getName()
- << " needs to be invalidated or set to nil";
- }
+ // Only check if Ivars are invalidated when InstanceVariableInvalidation
+ // has been requested.
+ if (!Filter.check_InstanceVariableInvalidation)
+ return;
- BR.EmitBasicReport(D,
- "Incomplete invalidation",
- categories::CoreFoundationObjectiveC, os.str(),
- IvarDecLocation);
+ // Check that all ivars are invalidated by the invalidation methods.
+ bool AtImplementationContainsAtLeastOneInvalidationMethod = false;
+ for (MethodSet::iterator I = Info.InvalidationMethods.begin(),
+ E = Info.InvalidationMethods.end(); I != E; ++I) {
+ const ObjCMethodDecl *InterfD = *I;
+
+ // Get the corresponding method in the @implementation.
+ const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
+ InterfD->isInstanceMethod());
+ if (D && D->hasBody()) {
+ AtImplementationContainsAtLeastOneInvalidationMethod = true;
+
+ // Get a copy of ivars needing invalidation.
+ IvarSet IvarsI = Ivars;
+
+ bool CalledAnotherInvalidationMethod = false;
+ MethodCrawler(IvarsI,
+ CalledAnotherInvalidationMethod,
+ PropSetterToIvarMap,
+ PropGetterToIvarMap,
+ PropertyToIvarMap,
+ BR.getContext()).VisitStmt(D->getBody());
+ // If another invalidation method was called, trust that full invalidation
+ // has occurred.
+ if (CalledAnotherInvalidationMethod)
+ continue;
+
+ // Warn on the ivars that were not invalidated by the method.
+ for (IvarSet::const_iterator
+ I = IvarsI.begin(), E = IvarsI.end(); I != E; ++I)
+ reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, D);
}
}
+
+ // Report an error in case none of the invalidation methods are implemented.
+ if (!AtImplementationContainsAtLeastOneInvalidationMethod)
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ /*MissingDeclaration*/ false);
}
-void IvarInvalidationChecker::MethodCrawler::markInvalidated(
+void IvarInvalidationCheckerImpl::
+reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCInterfaceDecl *InterfaceD,
+ bool MissingDeclaration) const {
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ assert(FirstIvarDecl);
+ printIvar(os, FirstIvarDecl, IvarToPopertyMap);
+ os << "needs to be invalidated; ";
+ if (MissingDeclaration)
+ os << "no invalidation method is declared for ";
+ else
+ os << "no invalidation method is defined in the @implementation for ";
+ os << InterfaceD->getName();
+
+ PathDiagnosticLocation IvarDecLocation =
+ PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager());
+
+ BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ IvarDecLocation);
+}
+
+void IvarInvalidationCheckerImpl::
+reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCMethodDecl *MethodD) const {
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ printIvar(os, IvarD, IvarToPopertyMap);
+ os << "needs to be invalidated or set to nil";
+ PathDiagnosticLocation MethodDecLocation =
+ PathDiagnosticLocation::createEnd(MethodD->getBody(),
+ BR.getSourceManager(),
+ Mgr.getAnalysisDeclContext(MethodD));
+ BR.EmitBasicReport(MethodD, "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ MethodDecLocation);
+}
+
+void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated(
const ObjCIvarDecl *Iv) {
IvarSet::iterator I = IVars.find(Iv);
if (I != IVars.end()) {
// If InvalidationMethod is present, we are processing the message send and
// should ensure we are invalidating with the appropriate method,
// otherwise, we are processing setting to 'nil'.
- if (InvalidationMethod)
- I->second.markInvalidated(InvalidationMethod);
- else
- I->second.markInvalidated();
+ if (!InvalidationMethod ||
+ (InvalidationMethod && I->second.hasMethod(InvalidationMethod)))
+ IVars.erase(I);
}
}
-const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
+const Expr *IvarInvalidationCheckerImpl::MethodCrawler::peel(const Expr *E) const {
E = E->IgnoreParenCasts();
if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
E = POE->getSyntacticForm()->IgnoreParenCasts();
@@ -427,13 +588,13 @@ const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
return E;
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCIvarRefExpr(
const ObjCIvarRefExpr *IvarRef) {
if (const Decl *D = IvarRef->getDecl())
markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCMessageExpr(
const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
@@ -444,7 +605,7 @@ void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
}
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCPropertyRefExpr(
const ObjCPropertyRefExpr *PA) {
if (PA->isExplicitProperty()) {
@@ -470,14 +631,14 @@ void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
}
}
-bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const {
+bool IvarInvalidationCheckerImpl::MethodCrawler::isZero(const Expr *E) const {
E = peel(E);
return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)
!= Expr::NPCK_NotNull);
}
-void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
+void IvarInvalidationCheckerImpl::MethodCrawler::check(const Expr *E) {
E = peel(E);
if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
@@ -496,28 +657,36 @@ void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
}
}
-void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
+void IvarInvalidationCheckerImpl::MethodCrawler::VisitBinaryOperator(
const BinaryOperator *BO) {
VisitStmt(BO);
- if (BO->getOpcode() != BO_Assign)
+ // Do we assign/compare against zero? If yes, check the variable we are
+ // assigning to.
+ BinaryOperatorKind Opcode = BO->getOpcode();
+ if (Opcode != BO_Assign &&
+ Opcode != BO_EQ &&
+ Opcode != BO_NE)
return;
- // Do we assign zero?
- if (!isZero(BO->getRHS()))
- return;
+ if (isZero(BO->getRHS())) {
+ check(BO->getLHS());
+ return;
+ }
- // Check the variable we are assigning to.
- check(BO->getLHS());
+ if (Opcode != BO_Assign && isZero(BO->getLHS())) {
+ check(BO->getRHS());
+ return;
+ }
}
-void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
- const ObjCMessageExpr *ME) {
+void IvarInvalidationCheckerImpl::MethodCrawler::VisitObjCMessageExpr(
+ const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
const Expr *Receiver = ME->getInstanceReceiver();
// Stop if we are calling '[self invalidate]'.
- if (Receiver && isInvalidationMethod(MD))
+ if (Receiver && isInvalidationMethod(MD, /*LookForPartial*/ false))
if (Receiver->isObjCSelfExpr()) {
CalledAnotherInvalidationMethod = true;
return;
@@ -544,7 +713,27 @@ void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
}
}
-// Register the checker.
-void ento::registerIvarInvalidationChecker(CheckerManager &mgr) {
- mgr.registerChecker<IvarInvalidationChecker>();
+// Register the checkers.
+namespace {
+
+class IvarInvalidationChecker :
+ public Checker<check::ASTDecl<ObjCImplementationDecl> > {
+public:
+ ChecksFilter Filter;
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ IvarInvalidationCheckerImpl Walker(Mgr, BR, Filter);
+ Walker.visit(D);
+ }
+};
+}
+
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ mgr.registerChecker<IvarInvalidationChecker>()->Filter.check_##name = true;\
}
+
+REGISTER_CHECKER(InstanceVariableInvalidation)
+REGISTER_CHECKER(MissingInvalidationMethod)
+
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 757a4ce28817..02a7cc34e4d4 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -13,11 +13,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 76f20b6e2e51..f1f06c798cde 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -13,22 +13,21 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
- check::PreStmt<ReturnStmt>,
check::PostStmt<CallExpr>,
- check::EndPath,
check::DeadSymbols> {
mutable OwningPtr<BugType> BT;
@@ -56,14 +55,12 @@ public:
};
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
- void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
private:
typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
- typedef llvm::SmallVector<AllocationPair, 2> AllocationPairVec;
+ typedef SmallVector<AllocationPair, 2> AllocationPairVec;
enum APIKind {
/// Denotes functions tracked by this checker.
@@ -94,7 +91,8 @@ private:
inline void initBugType() const {
if (!BT)
- BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API"));
+ BT.reset(new BugType("Improper use of SecKeychain API",
+ "API Misuse (Apple)"));
}
void generateDeallocatorMismatchReport(const AllocationPair &AP,
@@ -102,8 +100,8 @@ private:
CheckerContext &C) const;
/// Find the allocation site for Sym on the path leading to the node N.
- const Stmt *getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
- CheckerContext &C) const;
+ const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const;
BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
ExplodedNode *N,
@@ -220,7 +218,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
ProgramStateRef State = C.getState();
SVal ArgV = State->getSVal(Expr, C.getLocationContext());
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
+ if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
StoreManager& SM = C.getStoreManager();
SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
if (sym)
@@ -396,16 +394,18 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return;
}
// If kCFAllocatorNull, which does not deallocate, we still have to
- // find the deallocator. Otherwise, assume that the user had written a
- // custom deallocator which does the right thing.
- if (DE->getFoundDecl()->getName() != "kCFAllocatorNull") {
- State = State->remove<AllocatedData>(ArgSM);
- C.addTransition(State);
+ // find the deallocator.
+ if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
return;
- }
}
+ // In all other cases, assume the user supplied a correct deallocator
+ // that will free memory so stop tracking.
+ State = State->remove<AllocatedData>(ArgSM);
+ C.addTransition(State);
+ return;
}
- return;
+
+ llvm_unreachable("We know of no other possible APIs.");
}
// The call is deallocating a value we previously allocated, so remove it
@@ -422,7 +422,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// If the buffer can be null and the return status can be an error,
// report a bad call to free.
- if (State->assume(cast<DefinedSVal>(ArgSVal), false) &&
+ if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
ExplodedNode *N = C.addTransition(State);
if (!N)
@@ -486,31 +486,9 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
}
}
-void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
- CheckerContext &C) const {
- const Expr *retExpr = S->getRetValue();
- if (!retExpr)
- return;
-
- // If inside inlined call, skip it.
- const LocationContext *LC = C.getLocationContext();
- if (LC->getParent() != 0)
- return;
-
- // Check if the value is escaping through the return.
- ProgramStateRef state = C.getState();
- SymbolRef sym = state->getSVal(retExpr, LC).getAsLocSymbol();
- if (!sym)
- return;
- state = state->remove<AllocatedData>(sym);
-
- // Proceed from the new state.
- C.addTransition(state);
-}
-
// TODO: This logic is the same as in Malloc checker.
-const Stmt *
-MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
+const ExplodedNode *
+MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
SymbolRef Sym,
CheckerContext &C) const {
const LocationContext *LeakContext = N->getLocationContext();
@@ -528,12 +506,7 @@ MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
N = N->pred_empty() ? NULL : *(N->pred_begin());
}
- ProgramPoint P = AllocNode->getLocation();
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
- return Exit->getCalleeContext()->getCallSite();
- if (clang::PostStmt *PS = dyn_cast<clang::PostStmt>(&P))
- return PS->getStmt();
- return 0;
+ return AllocNode;
}
BugReport *MacOSKeychainAPIChecker::
@@ -551,11 +524,22 @@ BugReport *MacOSKeychainAPIChecker::
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- if (const Stmt *AllocStmt = getAllocationSite(N, AP.first, C))
+ const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
+ const Stmt *AllocStmt = 0;
+ ProgramPoint P = AllocNode->getLocation();
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
+ AllocStmt = Exit->getCalleeContext()->getCallSite();
+ else if (Optional<clang::PostStmt> PS = P.getAs<clang::PostStmt>())
+ AllocStmt = PS->getStmt();
+
+ if (AllocStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
- C.getSourceManager(), N->getLocationContext());
+ C.getSourceManager(),
+ AllocNode->getLocationContext());
+
+ BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
- BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing);
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
markInteresting(Report, AP);
return Report;
@@ -604,55 +588,6 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(State, N);
}
-// TODO: Remove this after we ensure that checkDeadSymbols are always called.
-void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
- ProgramStateRef state = C.getState();
-
- // If inside inlined call, skip it.
- if (C.getLocationContext()->getParent() != 0)
- return;
-
- AllocatedDataTy AS = state->get<AllocatedData>();
- if (AS.isEmpty())
- return;
-
- // Anything which has been allocated but not freed (nor escaped) will be
- // found here, so report it.
- bool Changed = false;
- AllocationPairVec Errors;
- for (AllocatedDataTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
- Changed = true;
- state = state->remove<AllocatedData>(I->first);
- // If the allocated symbol is null or if error code was returned at
- // allocation, do not report.
- ConstraintManager &CMgr = state->getConstraintManager();
- ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
- if (AllocFailed.isConstrainedTrue() ||
- definitelyReturnedError(I->second.Region, state,
- C.getSValBuilder())) {
- continue;
- }
- Errors.push_back(std::make_pair(I->first, &I->second));
- }
-
- // If no change, do not generate a new state.
- if (!Changed) {
- C.addTransition(state);
- return;
- }
-
- static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : EndPathLeak");
- ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
-
- // Generate the error reports.
- for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
- I != E; ++I) {
- C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
- }
-
- C.addTransition(state, N);
-}
-
PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
const ExplodedNode *N,
@@ -668,8 +603,8 @@ PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
// (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
// allocation site.
- const CallExpr *CE = cast<CallExpr>(cast<StmtPoint>(N->getLocation())
- .getStmt());
+ const CallExpr *CE =
+ cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt());
const FunctionDecl *funDecl = CE->getDirectCallee();
assert(funDecl && "We do not support indirect function calls as of now.");
StringRef funName = funDecl->getName();
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 467b8b1d815c..32ebb51226bb 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This defines MacOSXAPIChecker, which is an assortment of checks on calls
-// to various, widely used Mac OS X functions.
+// to various, widely used Apple APIs.
//
// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
// to here, using the new Checker interface.
@@ -16,12 +16,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
@@ -68,7 +68,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (!BT_dispatchOnce)
BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
- "Mac OS X API"));
+ "API Misuse (Apple)"));
// Handle _dispatch_once. In some versions of the OS X SDK we have the case
// that dispatch_once is a macro that wraps a call to _dispatch_once.
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index caf70ca3706f..4b0e7661d8da 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -14,18 +14,19 @@
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/SourceManager.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include <climits>
@@ -34,6 +35,14 @@ using namespace ento;
namespace {
+// Used to check correspondence between allocators and deallocators.
+enum AllocationFamily {
+ AF_None,
+ AF_Malloc,
+ AF_CXXNew,
+ AF_CXXNewArray
+};
+
class RefState {
enum Kind { // Reference to allocated memory.
Allocated,
@@ -41,33 +50,55 @@ class RefState {
Released,
// The responsibility for freeing resources has transfered from
// this reference. A relinquished symbol should not be freed.
- Relinquished } K;
+ Relinquished };
+
const Stmt *S;
+ unsigned K : 2; // Kind enum, but stored as a bitfield.
+ unsigned Family : 30; // Rest of 32-bit word, currently just an allocation
+ // family.
+ RefState(Kind k, const Stmt *s, unsigned family)
+ : S(s), K(k), Family(family) {}
public:
- RefState(Kind k, const Stmt *s) : K(k), S(s) {}
-
bool isAllocated() const { return K == Allocated; }
bool isReleased() const { return K == Released; }
bool isRelinquished() const { return K == Relinquished; }
-
+ AllocationFamily getAllocationFamily() const {
+ return (AllocationFamily)Family;
+ }
const Stmt *getStmt() const { return S; }
bool operator==(const RefState &X) const {
- return K == X.K && S == X.S;
+ return K == X.K && S == X.S && Family == X.Family;
}
- static RefState getAllocated(const Stmt *s) {
- return RefState(Allocated, s);
+ static RefState getAllocated(unsigned family, const Stmt *s) {
+ return RefState(Allocated, s, family);
+ }
+ static RefState getReleased(unsigned family, const Stmt *s) {
+ return RefState(Released, s, family);
}
- static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
- static RefState getRelinquished(const Stmt *s) {
- return RefState(Relinquished, s);
+ static RefState getRelinquished(unsigned family, const Stmt *s) {
+ return RefState(Relinquished, s, family);
}
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
ID.AddPointer(S);
+ ID.AddInteger(Family);
+ }
+
+ void dump(raw_ostream &OS) const {
+ static const char *Table[] = {
+ "Allocated",
+ "Released",
+ "Relinquished"
+ };
+ OS << Table[(unsigned) K];
+ }
+
+ LLVM_ATTRIBUTE_USED void dump() const {
+ dump(llvm::errs());
}
};
@@ -99,24 +130,27 @@ struct ReallocPair {
}
};
-typedef std::pair<const Stmt*, const MemRegion*> LeakInfo;
+typedef std::pair<const ExplodedNode*, const MemRegion*> LeakInfo;
class MallocChecker : public Checker<check::DeadSymbols,
- check::EndPath,
+ check::PointerEscape,
+ check::ConstPointerEscape,
check::PreStmt<ReturnStmt>,
check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
+ check::PostStmt<CXXNewExpr>,
+ check::PreStmt<CXXDeleteExpr>,
check::PostStmt<BlockExpr>,
check::PostObjCMessage,
check::Location,
- check::Bind,
- eval::Assume,
- check::RegionChanges>
+ 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;
@@ -129,32 +163,33 @@ public:
struct ChecksFilter {
DefaultBool CMallocPessimistic;
DefaultBool CMallocOptimistic;
+ DefaultBool CNewDeleteChecker;
+ DefaultBool CMismatchedDeallocatorChecker;
};
ChecksFilter Filter;
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
+ void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
bool Assumption) const;
void checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const;
- void checkBind(SVal location, SVal val, const Stmt*S,
- CheckerContext &C) const;
- ProgramStateRef
- checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const;
- bool wantsRegionChangeUpdate(ProgramStateRef state) const {
- return true;
- }
+
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
+ ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const;
@@ -162,31 +197,52 @@ public:
private:
void initIdentifierInfo(ASTContext &C) const;
+ /// \brief Determine family of a deallocation expression.
+ AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const;
+
+ /// \brief Print names of allocators and deallocators.
+ ///
+ /// \returns true on success.
+ bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) const;
+
+ /// \brief Print expected name of an allocator based on the deallocator's
+ /// family derived from the DeallocExpr.
+ void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
+ const Expr *DeallocExpr) const;
+ /// \brief Print expected name of a deallocator based on the allocator's
+ /// family.
+ void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const;
+
+ ///@{
/// Check if this is one of the functions which can allocate/reallocate memory
/// pointed to by one of its arguments.
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const;
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);
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
- ProgramStateRef state) {
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc) {
return MallocMemAux(C, CE,
- state->getSVal(SizeEx, C.getLocationContext()),
- Init, state);
+ State->getSVal(SizeEx, C.getLocationContext()),
+ Init, State, Family);
}
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
- ProgramStateRef state);
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc);
/// Update the RefState to reflect the new memory allocation.
- static ProgramStateRef MallocUpdateRefState(CheckerContext &C,
- const CallExpr *CE,
- ProgramStateRef state);
+ static ProgramStateRef
+ MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc);
ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att) const;
@@ -209,17 +265,43 @@ private:
///\brief Check if the memory associated with this symbol was released.
bool isReleased(SymbolRef Sym, CheckerContext &C) const;
- bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
- const Stmt *S = 0) const;
-
- /// Check if the function is not known to us. So, for example, we could
- /// conservatively assume it can free/reallocate it's pointer arguments.
- bool doesNotFreeMemory(const CallEvent *Call,
- ProgramStateRef State) const;
+ bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
+
+ /// Check if the function is known not to free memory, or if it is
+ /// "interesting" and should be modeled explicitly.
+ ///
+ /// We assume that pointers do not escape through calls to system functions
+ /// not handled by this checker.
+ bool doesNotFreeMemOrInteresting(const CallEvent *Call,
+ ProgramStateRef State) const;
+
+ // Implementation of the checkPointerEscape callabcks.
+ ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool(*CheckRefState)(const RefState*)) const;
+
+ // Used to suppress warnings if they are not related to the tracked family
+ // (derived from AllocDeallocStmt).
+ bool isTrackedFamily(AllocationFamily Family) const;
+ bool isTrackedFamily(CheckerContext &C, const Stmt *AllocDeallocStmt) const;
+ bool isTrackedFamily(CheckerContext &C, SymbolRef Sym) const;
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
- void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
+ void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
+ const Expr *DeallocExpr) const;
+ void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
+ const Expr *DeallocExpr,
+ const RefState *RS) const;
+ void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
+ const Expr *DeallocExpr,
+ const Expr *AllocExpr = 0) const;
+ void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
+ SymbolRef Sym) const;
+ void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
+ SymbolRef Sym, SymbolRef PrevSym) const;
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
@@ -264,14 +346,14 @@ private:
inline bool isAllocated(const RefState *S, const RefState *SPrev,
const Stmt *Stmt) {
// Did not track -> allocated. Other state (released) -> allocated.
- return (Stmt && isa<CallExpr>(Stmt) &&
+ return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
(S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated()));
}
inline bool isReleased(const RefState *S, const RefState *SPrev,
const Stmt *Stmt) {
// Did not track -> released. Other state (allocated) -> released.
- return (Stmt && isa<CallExpr>(Stmt) &&
+ return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt)) &&
(S && S->isReleased()) && (!SPrev || !SPrev->isReleased()));
}
@@ -381,6 +463,9 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
if (isAllocationFunction(FD, C))
return true;
+ if (isStandardNewDelete(FD, C))
+ return true;
+
return false;
}
@@ -432,6 +517,39 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const
return false;
}
+// Tells if the callee is one of the following:
+// 1) A global non-placement new/delete operator function.
+// 2) A global placement operator function with the single placement argument
+// of type std::nothrow_t.
+bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
+ ASTContext &C) const {
+ if (!FD)
+ return false;
+
+ OverloadedOperatorKind Kind = FD->getOverloadedOperator();
+ if (Kind != OO_New && Kind != OO_Array_New &&
+ Kind != OO_Delete && Kind != OO_Array_Delete)
+ return false;
+
+ // Skip all operator new/delete methods.
+ if (isa<CXXMethodDecl>(FD))
+ return false;
+
+ // Return true if tested operator is a standard placement nothrow operator.
+ if (FD->getNumParams() == 2) {
+ QualType T = FD->getParamDecl(1)->getType();
+ if (const IdentifierInfo *II = T.getBaseTypeIdentifier())
+ return II->getName().equals("nothrow_t");
+ }
+
+ // Skip placement operators.
+ if (FD->getNumParams() != 1 || FD->isVariadic())
+ return false;
+
+ // One of the standard new/new[]/delete/delete[] non-placement operators.
+ return true;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
@@ -464,9 +582,26 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
} else if (FunI == II_strndup) {
State = MallocUpdateRefState(C, CE, State);
}
+ else if (isStandardNewDelete(FD, C.getASTContext())) {
+ // Process direct calls to operator new/new[]/delete/delete[] functions
+ // as distinct from new/new[]/delete/delete[] expressions that are
+ // processed by the checkPostStmt callbacks for CXXNewExpr and
+ // CXXDeleteExpr.
+ OverloadedOperatorKind K = FD->getOverloadedOperator();
+ if (K == OO_New)
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_CXXNew);
+ else if (K == OO_Array_New)
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_CXXNewArray);
+ else if (K == OO_Delete || K == OO_Array_Delete)
+ State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+ else
+ llvm_unreachable("not a new/delete operator");
+ }
}
- if (Filter.CMallocOptimistic) {
+ if (Filter.CMallocOptimistic || Filter.CMismatchedDeallocatorChecker) {
// Check all the attributes, if there are any.
// There can be multiple of these attributes.
if (FD->hasAttrs())
@@ -488,37 +623,91 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
C.addTransition(State);
}
-static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
+void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
+ CheckerContext &C) const {
+
+ if (NE->getNumPlacementArgs())
+ for (CXXNewExpr::const_arg_iterator I = NE->placement_arg_begin(),
+ E = NE->placement_arg_end(); I != E; ++I)
+ if (SymbolRef Sym = C.getSVal(*I).getAsSymbol())
+ checkUseAfterFree(Sym, C, *I);
+
+ if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext()))
+ return;
+
+ ProgramStateRef State = C.getState();
+ // The return value from operator new is bound to a specified initialization
+ // value (if any) and we don't want to loose this value. So we call
+ // MallocUpdateRefState() instead of MallocMemAux() which breakes the
+ // existing binding.
+ State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
+ : AF_CXXNew);
+ C.addTransition(State);
+}
+
+void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
+ CheckerContext &C) const {
+
+ if (!Filter.CNewDeleteChecker)
+ if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
+ checkUseAfterFree(Sym, C, DE->getArgument());
+
+ if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext()))
+ return;
+
+ ProgramStateRef State = C.getState();
+ bool ReleasedAllocated;
+ State = FreeMemAux(C, DE->getArgument(), DE, State,
+ /*Hold*/false, ReleasedAllocated);
+
+ C.addTransition(State);
+}
+
+static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
+ // If the first selector piece is one of the names below, assume that the
+ // object takes ownership of the memory, promising to eventually deallocate it
+ // with free().
+ // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
+ // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
+ StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
+ if (FirstSlot == "dataWithBytesNoCopy" ||
+ FirstSlot == "initWithBytesNoCopy" ||
+ FirstSlot == "initWithCharactersNoCopy")
+ return true;
+
+ return false;
+}
+
+static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
Selector S = Call.getSelector();
+
+ // FIXME: We should not rely on fully-constrained symbols being folded.
for (unsigned i = 1; i < S.getNumArgs(); ++i)
if (S.getNameForSlot(i).equals("freeWhenDone"))
- if (Call.getArgSVal(i).isConstant(0))
- return true;
+ return !Call.getArgSVal(i).isZeroConstant();
- return false;
+ return None;
}
void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
CheckerContext &C) const {
- // If the first selector is dataWithBytesNoCopy, assume that the memory will
- // be released with 'free' by the new object.
- // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
- // Unless 'freeWhenDone' param set to 0.
- // TODO: Check that the memory was allocated with malloc.
- bool ReleasedAllocatedMemory = false;
- Selector S = Call.getSelector();
- if ((S.getNameForSlot(0) == "dataWithBytesNoCopy" ||
- S.getNameForSlot(0) == "initWithBytesNoCopy" ||
- S.getNameForSlot(0) == "initWithCharactersNoCopy") &&
- !isFreeWhenDoneSetToZero(Call)){
- unsigned int argIdx = 0;
- ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(argIdx),
- Call.getOriginExpr(), C.getState(), true,
- ReleasedAllocatedMemory,
- /* RetNullOnFailure*/ true);
-
- C.addTransition(State);
- }
+ if (C.wasInlined)
+ return;
+
+ if (!isKnownDeallocObjCMethodName(Call))
+ return;
+
+ if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
+ if (!*FreeWhenDone)
+ return;
+
+ bool ReleasedAllocatedMemory;
+ ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0),
+ Call.getOriginExpr(), C.getState(),
+ /*Hold=*/true, ReleasedAllocatedMemory,
+ /*RetNullOnFailure=*/true);
+
+ C.addTransition(State);
}
ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
@@ -537,7 +726,8 @@ ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
SVal Size, SVal Init,
- ProgramStateRef state) {
+ ProgramStateRef State,
+ AllocationFamily Family) {
// Bind the return value to the symbolic value from the heap region.
// TODO: We could rewrite post visit to eval call; 'malloc' does not have
@@ -545,52 +735,52 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
unsigned Count = C.blockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count));
- state = state->BindExpr(CE, C.getLocationContext(), RetVal);
+ DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
+ .castAs<DefinedSVal>();
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
// We expect the malloc functions to return a pointer.
- if (!isa<Loc>(RetVal))
+ if (!RetVal.getAs<Loc>())
return 0;
// Fill the region with the initialization value.
- state = state->bindDefault(RetVal, Init);
+ State = State->bindDefault(RetVal, Init);
// Set the region's extent equal to the Size parameter.
const SymbolicRegion *R =
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
if (!R)
return 0;
- if (isa<DefinedOrUnknownSVal>(Size)) {
+ if (Optional<DefinedOrUnknownSVal> DefinedSize =
+ Size.getAs<DefinedOrUnknownSVal>()) {
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
- DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
DefinedOrUnknownSVal extentMatchesSize =
- svalBuilder.evalEQ(state, Extent, DefinedSize);
+ svalBuilder.evalEQ(State, Extent, *DefinedSize);
- state = state->assume(extentMatchesSize, true);
- assert(state);
+ State = State->assume(extentMatchesSize, true);
+ assert(State);
}
- return MallocUpdateRefState(C, CE, state);
+ return MallocUpdateRefState(C, CE, State, Family);
}
ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
- const CallExpr *CE,
- ProgramStateRef state) {
+ const Expr *E,
+ ProgramStateRef State,
+ AllocationFamily Family) {
// Get the return value.
- SVal retVal = state->getSVal(CE, C.getLocationContext());
+ SVal retVal = State->getSVal(E, C.getLocationContext());
// We expect the malloc functions to return a pointer.
- if (!isa<Loc>(retVal))
+ if (!retVal.getAs<Loc>())
return 0;
SymbolRef Sym = retVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- return state->set<RegionState>(Sym, RefState::getAllocated(CE));
-
+ return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
}
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
@@ -629,8 +819,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
/// Checks if the previous call to free on the given symbol failed - if free
/// failed, returns true. Also, returns the corresponding return value symbol.
-bool didPreviousFreeFail(ProgramStateRef State,
- SymbolRef Sym, SymbolRef &RetStatusSymbol) {
+static bool didPreviousFreeFail(ProgramStateRef State,
+ SymbolRef Sym, SymbolRef &RetStatusSymbol) {
const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
if (Ret) {
assert(*Ret && "We should not store the null return symbol");
@@ -642,6 +832,107 @@ bool didPreviousFreeFail(ProgramStateRef State,
return false;
}
+AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
+ const Stmt *S) const {
+ if (!S)
+ return AF_None;
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
+
+ if (!FD)
+ FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
+
+ ASTContext &Ctx = C.getASTContext();
+
+ if (isAllocationFunction(FD, Ctx) || isFreeFunction(FD, Ctx))
+ return AF_Malloc;
+
+ if (isStandardNewDelete(FD, Ctx)) {
+ OverloadedOperatorKind Kind = FD->getOverloadedOperator();
+ if (Kind == OO_New || Kind == OO_Delete)
+ return AF_CXXNew;
+ else if (Kind == OO_Array_New || Kind == OO_Array_Delete)
+ return AF_CXXNewArray;
+ }
+
+ return AF_None;
+ }
+
+ if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(S))
+ return NE->isArray() ? AF_CXXNewArray : AF_CXXNew;
+
+ if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(S))
+ return DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew;
+
+ if (isa<ObjCMessageExpr>(S))
+ return AF_Malloc;
+
+ return AF_None;
+}
+
+bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) const {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ // FIXME: This doesn't handle indirect calls.
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return false;
+
+ os << *FD;
+ if (!FD->isOverloadedOperator())
+ os << "()";
+ return true;
+ }
+
+ if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
+ if (Msg->isInstanceMessage())
+ os << "-";
+ else
+ os << "+";
+ os << Msg->getSelector().getAsString();
+ return true;
+ }
+
+ if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
+ os << "'"
+ << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
+ << "'";
+ return true;
+ }
+
+ if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
+ os << "'"
+ << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
+ << "'";
+ return true;
+ }
+
+ return false;
+}
+
+void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) const {
+ AllocationFamily Family = getAllocationFamily(C, E);
+
+ switch(Family) {
+ case AF_Malloc: os << "malloc()"; return;
+ case AF_CXXNew: os << "'new'"; return;
+ case AF_CXXNewArray: os << "'new[]'"; return;
+ case AF_None: llvm_unreachable("not a deallocation expression");
+ }
+}
+
+void MallocChecker::printExpectedDeallocName(raw_ostream &os,
+ AllocationFamily Family) const {
+ switch(Family) {
+ case AF_Malloc: os << "free()"; return;
+ case AF_CXXNew: os << "'delete'"; return;
+ case AF_CXXNewArray: os << "'delete[]'"; return;
+ case AF_None: llvm_unreachable("suspicious AF_None argument");
+ }
+}
+
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const Expr *ArgExpr,
const Expr *ParentExpr,
@@ -651,12 +942,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
bool ReturnsNullOnFailure) const {
SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
- if (!isa<DefinedOrUnknownSVal>(ArgVal))
+ if (!ArgVal.getAs<DefinedOrUnknownSVal>())
return 0;
- DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
+ DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
// Check for null dereferences.
- if (!isa<Loc>(location))
+ if (!location.getAs<Loc>())
return 0;
// The explicit NULL case, no operation is performed.
@@ -675,7 +966,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Nonlocs can't be freed, of course.
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
if (!R) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return 0;
}
@@ -683,13 +974,14 @@ 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());
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return 0;
}
const MemSpaceRegion *MS = R->getMemorySpace();
- // Parameters, locals, statics, and globals shouldn't be freed.
+ // Parameters, locals, statics, globals, and memory returned by alloca()
+ // shouldn't be freed.
if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
// FIXME: at the time this code was written, malloc() regions were
// represented by conjured symbols, which are all in UnknownSpaceRegion.
@@ -699,46 +991,59 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// function, so UnknownSpaceRegion is always a possibility.
// False negatives are better than false positives.
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return 0;
}
-
- const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+
+ const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
// Various cases could lead to non-symbol values here.
// For now, ignore them.
- if (!SR)
+ if (!SrBase)
return 0;
- SymbolRef Sym = SR->getSymbol();
- const RefState *RS = State->get<RegionState>(Sym);
+ SymbolRef SymBase = SrBase->getSymbol();
+ const RefState *RsBase = State->get<RegionState>(SymBase);
SymbolRef PreviousRetStatusSymbol = 0;
- // Check double free.
- if (RS &&
- (RS->isReleased() || RS->isRelinquished()) &&
- !didPreviousFreeFail(State, Sym, PreviousRetStatusSymbol)) {
-
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_DoubleFree)
- BT_DoubleFree.reset(
- new BugType("Double free", "Memory Error"));
- BugReport *R = new BugReport(*BT_DoubleFree,
- (RS->isReleased() ? "Attempt to free released memory" :
- "Attempt to free non-owned memory"), N);
- R->addRange(ArgExpr->getSourceRange());
- R->markInteresting(Sym);
- if (PreviousRetStatusSymbol)
- R->markInteresting(PreviousRetStatusSymbol);
- R->addVisitor(new MallocBugVisitor(Sym));
- C.emitReport(R);
+ if (RsBase) {
+
+ bool DeallocMatchesAlloc =
+ RsBase->getAllocationFamily() == AF_None ||
+ RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
+
+ // Check if an expected deallocation function matches the real one.
+ if (!DeallocMatchesAlloc && RsBase->isAllocated()) {
+ ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase);
+ return 0;
+ }
+
+ // Check double free.
+ if (DeallocMatchesAlloc &&
+ (RsBase->isReleased() || RsBase->isRelinquished()) &&
+ !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
+ ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
+ SymBase, PreviousRetStatusSymbol);
+ return 0;
+ }
+
+ // Check if the memory location being freed is the actual location
+ // allocated, or an offset.
+ RegionOffset Offset = R->getAsOffset();
+ if (RsBase->isAllocated() &&
+ Offset.isValid() &&
+ !Offset.hasSymbolicOffset() &&
+ Offset.getOffset() != 0) {
+ const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
+ ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
+ AllocExpr);
+ return 0;
}
- return 0;
}
- ReleasedAllocated = (RS != 0);
+ ReleasedAllocated = (RsBase != 0);
// Clean out the info on previous call to free return info.
- State = State->remove<FreeReturnValue>(Sym);
+ State = State->remove<FreeReturnValue>(SymBase);
// Keep track of the return value. If it is NULL, we will know that free
// failed.
@@ -746,23 +1051,60 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
SVal RetVal = C.getSVal(ParentExpr);
SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
if (RetStatusSymbol) {
- C.getSymbolManager().addSymbolDependency(Sym, RetStatusSymbol);
- State = State->set<FreeReturnValue>(Sym, RetStatusSymbol);
+ C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
+ State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
}
}
+ AllocationFamily Family = RsBase ? RsBase->getAllocationFamily() : AF_None;
// Normal free.
if (Hold)
- return State->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr));
- return State->set<RegionState>(Sym, RefState::getReleased(ParentExpr));
+ return State->set<RegionState>(SymBase,
+ RefState::getRelinquished(Family,
+ ParentExpr));
+
+ return State->set<RegionState>(SymBase,
+ RefState::getReleased(Family, ParentExpr));
+}
+
+bool MallocChecker::isTrackedFamily(AllocationFamily Family) const {
+ switch (Family) {
+ case AF_Malloc: {
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic)
+ return false;
+ return true;
+ }
+ case AF_CXXNew:
+ case AF_CXXNewArray: {
+ if (!Filter.CNewDeleteChecker)
+ return false;
+ return true;
+ }
+ case AF_None: {
+ return true;
+ }
+ }
+ llvm_unreachable("unhandled family");
+}
+
+bool MallocChecker::isTrackedFamily(CheckerContext &C,
+ const Stmt *AllocDeallocStmt) const {
+ return isTrackedFamily(getAllocationFamily(C, AllocDeallocStmt));
+}
+
+bool MallocChecker::isTrackedFamily(CheckerContext &C, SymbolRef Sym) const {
+ const RefState *RS = C.getState()->get<RegionState>(Sym);
+
+ return RS ? isTrackedFamily(RS->getAllocationFamily())
+ : isTrackedFamily(AF_None);
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
- if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V))
+ if (Optional<nonloc::ConcreteInt> IntVal = V.getAs<nonloc::ConcreteInt>())
os << "an integer (" << IntVal->getValue() << ")";
- else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V))
+ else if (Optional<loc::ConcreteInt> ConstAddr = V.getAs<loc::ConcreteInt>())
os << "a constant address (" << ConstAddr->getValue() << ")";
- else if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&V))
+ else if (Optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
os << "the address of the label '" << Label->getLabel()->getName() << "'";
else
return false;
@@ -844,41 +1186,192 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
}
}
-void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
- SourceRange range) const {
+void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range,
+ const Expr *DeallocExpr) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, DeallocExpr))
+ return;
+
if (ExplodedNode *N = C.generateSink()) {
if (!BT_BadFree)
BT_BadFree.reset(new BugType("Bad free", "Memory Error"));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
-
+
const MemRegion *MR = ArgVal.getAsRegion();
- if (MR) {
- while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR))
- MR = ER->getSuperRegion();
-
- // Special case for alloca()
- if (isa<AllocaRegion>(MR))
- os << "Argument to free() was allocated by alloca(), not malloc()";
- else {
- os << "Argument to free() is ";
- if (SummarizeRegion(os, MR))
- os << ", which is not memory allocated by malloc()";
- else
- os << "not memory allocated by malloc()";
- }
- } else {
- os << "Argument to free() is ";
- if (SummarizeValue(os, ArgVal))
- os << ", which is not memory allocated by malloc()";
+ while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
+ MR = ER->getSuperRegion();
+
+ if (MR && isa<AllocaRegion>(MR))
+ os << "Memory allocated by alloca() should not be deallocated";
+ else {
+ os << "Argument to ";
+ if (!printAllocDeallocName(os, C, DeallocExpr))
+ os << "deallocator";
+
+ os << " is ";
+ bool Summarized = MR ? SummarizeRegion(os, MR)
+ : SummarizeValue(os, ArgVal);
+ if (Summarized)
+ os << ", which is not memory allocated by ";
else
- os << "not memory allocated by malloc()";
+ os << "not memory allocated by ";
+
+ printExpectedAllocName(os, C, DeallocExpr);
}
-
+
BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
R->markInteresting(MR);
- R->addRange(range);
+ R->addRange(Range);
+ C.emitReport(R);
+ }
+}
+
+void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
+ SourceRange Range,
+ const Expr *DeallocExpr,
+ const RefState *RS) const {
+
+ if (!Filter.CMismatchedDeallocatorChecker)
+ return;
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_MismatchedDealloc)
+ BT_MismatchedDealloc.reset(new BugType("Bad deallocator",
+ "Memory Error"));
+
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ const Expr *AllocExpr = cast<Expr>(RS->getStmt());
+ SmallString<20> AllocBuf;
+ llvm::raw_svector_ostream AllocOs(AllocBuf);
+ SmallString<20> DeallocBuf;
+ llvm::raw_svector_ostream DeallocOs(DeallocBuf);
+
+ os << "Memory";
+ if (printAllocDeallocName(AllocOs, C, AllocExpr))
+ os << " allocated by " << AllocOs.str();
+
+ os << " should be deallocated by ";
+ printExpectedDeallocName(os, RS->getAllocationFamily());
+
+ if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
+ os << ", not " << DeallocOs.str();
+
+ BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N);
+ R->addRange(Range);
+ C.emitReport(R);
+ }
+}
+
+void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range, const Expr *DeallocExpr,
+ const Expr *AllocExpr) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, AllocExpr))
+ return;
+
+ ExplodedNode *N = C.generateSink();
+ if (N == NULL)
+ return;
+
+ if (!BT_OffsetFree)
+ BT_OffsetFree.reset(new BugType("Offset free", "Memory Error"));
+
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+ SmallString<20> AllocNameBuf;
+ llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
+
+ const MemRegion *MR = ArgVal.getAsRegion();
+ assert(MR && "Only MemRegion based symbols can have offset free errors");
+
+ RegionOffset Offset = MR->getAsOffset();
+ assert((Offset.isValid() &&
+ !Offset.hasSymbolicOffset() &&
+ Offset.getOffset() != 0) &&
+ "Only symbols with a valid offset can have offset free errors");
+
+ int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
+
+ os << "Argument to ";
+ if (!printAllocDeallocName(os, C, DeallocExpr))
+ os << "deallocator";
+ os << " is offset by "
+ << offsetBytes
+ << " "
+ << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
+ << " from the start of ";
+ if (AllocExpr && printAllocDeallocName(AllocNameOs, C, AllocExpr))
+ os << "memory allocated by " << AllocNameOs.str();
+ else
+ os << "allocated memory";
+
+ BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N);
+ R->markInteresting(MR->getBaseRegion());
+ R->addRange(Range);
+ C.emitReport(R);
+}
+
+void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
+ SymbolRef Sym) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, Sym))
+ return;
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_UseFree)
+ BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
+
+ BugReport *R = new BugReport(*BT_UseFree,
+ "Use of memory after it is freed", N);
+
+ R->markInteresting(Sym);
+ R->addRange(Range);
+ R->addVisitor(new MallocBugVisitor(Sym));
+ C.emitReport(R);
+ }
+}
+
+void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
+ bool Released, SymbolRef Sym,
+ SymbolRef PrevSym) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, Sym))
+ 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);
+ R->addRange(Range);
+ R->markInteresting(Sym);
+ if (PrevSym)
+ R->markInteresting(PrevSym);
+ R->addVisitor(new MallocBugVisitor(Sym));
C.emitReport(R);
}
}
@@ -893,9 +1386,9 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
const Expr *arg0Expr = CE->getArg(0);
const LocationContext *LCtx = C.getLocationContext();
SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
- if (!isa<DefinedOrUnknownSVal>(Arg0Val))
+ if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
return 0;
- DefinedOrUnknownSVal arg0Val = cast<DefinedOrUnknownSVal>(Arg0Val);
+ DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -909,9 +1402,9 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// Get the value of the size argument.
SVal Arg1ValG = state->getSVal(Arg1, LCtx);
- if (!isa<DefinedOrUnknownSVal>(Arg1ValG))
+ if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
return 0;
- DefinedOrUnknownSVal Arg1Val = cast<DefinedOrUnknownSVal>(Arg1ValG);
+ DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
@@ -1032,18 +1525,19 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
N = N->pred_empty() ? NULL : *(N->pred_begin());
}
- ProgramPoint P = AllocNode->getLocation();
- const Stmt *AllocationStmt = 0;
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
- AllocationStmt = Exit->getCalleeContext()->getCallSite();
- else if (StmtPoint *SP = dyn_cast<StmtPoint>(&P))
- AllocationStmt = SP->getStmt();
-
- return LeakInfo(AllocationStmt, ReferenceRegion);
+ return LeakInfo(AllocNode, ReferenceRegion);
}
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
CheckerContext &C) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, Sym))
+ return;
+
assert(N);
if (!BT_Leak) {
BT_Leak.reset(new BugType("Memory leak", "Memory Error"));
@@ -1059,12 +1553,20 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- const Stmt *AllocStmt = 0;
+ const ExplodedNode *AllocNode = 0;
const MemRegion *Region = 0;
- llvm::tie(AllocStmt, Region) = getAllocationSite(N, Sym, C);
- if (AllocStmt)
- LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
- C.getSourceManager(), N->getLocationContext());
+ llvm::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
+
+ ProgramPoint P = AllocNode->getLocation();
+ const Stmt *AllocationStmt = 0;
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
+ AllocationStmt = Exit->getCalleeContext()->getCallSite();
+ else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
+ AllocationStmt = SP->getStmt();
+ if (AllocationStmt)
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
+ C.getSourceManager(),
+ AllocNode->getLocationContext());
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
@@ -1075,7 +1577,9 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
os << '\'';
}
- BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
+ BugReport *R = new BugReport(*BT_Leak, os.str(), N,
+ LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym, true));
C.emitReport(R);
@@ -1091,7 +1595,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
RegionStateTy RS = state->get<RegionState>();
RegionStateTy::Factory &F = state->get_context<RegionState>();
- llvm::SmallVector<SymbolRef, 2> Errors;
+ SmallVector<SymbolRef, 2> Errors;
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
if (SymReaper.isDead(I->first)) {
if (I->second.isAllocated())
@@ -1125,7 +1629,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (!Errors.empty()) {
static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
- for (llvm::SmallVector<SymbolRef, 2>::iterator
+ for (SmallVector<SymbolRef, 2>::iterator
I = Errors.begin(), E = Errors.end(); I != E; ++I) {
reportLeak(*I, N, C);
}
@@ -1134,27 +1638,14 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
C.addTransition(state->set<RegionState>(RS), N);
}
-void MallocChecker::checkEndPath(CheckerContext &C) const {
- ProgramStateRef state = C.getState();
- RegionStateTy M = state->get<RegionState>();
-
- // If inside inlined call, skip it.
- if (C.getLocationContext()->getParent() != 0)
- return;
-
- for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- RefState RS = I->second;
- if (RS.isAllocated()) {
- ExplodedNode *N = C.addTransition(state);
- if (N)
- reportLeak(I->first, N, C);
- }
- }
-}
-
void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// We will check for double free in the post visit.
- if (isFreeFunction(C.getCalleeDecl(CE), C.getASTContext()))
+ if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) &&
+ isFreeFunction(C.getCalleeDecl(CE), C.getASTContext()))
+ return;
+
+ if (Filter.CNewDeleteChecker &&
+ isStandardNewDelete(C.getCalleeDecl(CE), C.getASTContext()))
return;
// Check use after free, when a freed pointer is passed to a call.
@@ -1163,7 +1654,7 @@ void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
E = CE->arg_end(); I != E; ++I) {
const Expr *A = *I;
if (A->getType().getTypePtr()->isAnyPointerType()) {
- SymbolRef Sym = State->getSVal(A, C.getLocationContext()).getAsSymbol();
+ SymbolRef Sym = C.getSVal(A).getAsSymbol();
if (!Sym)
continue;
if (checkUseAfterFree(Sym, C, A))
@@ -1193,15 +1684,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
// Check if we are returning freed memory.
if (Sym)
- if (checkUseAfterFree(Sym, C, E))
- return;
-
- // If this function body is not inlined, stop tracking any returned symbols.
- if (C.getLocationContext()->getParent() == 0) {
- State =
- State->scanReachableSymbols<StopTrackingCallback>(RetVal).getState();
- C.addTransition(State);
- }
+ checkUseAfterFree(Sym, C, E);
}
// TODO: Blocks should be either inlined or should call invalidate regions
@@ -1231,7 +1714,7 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
for ( ; I != E; ++I) {
- const VarRegion *VR = *I;
+ const VarRegion *VR = I.getCapturedRegion();
if (VR->getSuperRegion() == R) {
VR = MemMgr.getVarRegion(VR->getDecl(), LC);
}
@@ -1252,21 +1735,12 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const {
+
if (isReleased(Sym, C)) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_UseFree)
- BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
-
- BugReport *R = new BugReport(*BT_UseFree,
- "Use of memory after it is freed",N);
- if (S)
- R->addRange(S->getSourceRange());
- R->markInteresting(Sym);
- R->addVisitor(new MallocBugVisitor(Sym));
- C.emitReport(R);
- return true;
- }
+ ReportUseAfterFree(C, S->getSourceRange(), Sym);
+ return true;
}
+
return false;
}
@@ -1278,51 +1752,6 @@ void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
checkUseAfterFree(Sym, C, S);
}
-//===----------------------------------------------------------------------===//
-// Check various ways a symbol can be invalidated.
-// TODO: This logic (the next 3 functions) is copied/similar to the
-// RetainRelease checker. We might want to factor this out.
-//===----------------------------------------------------------------------===//
-
-// Stop tracking symbols when a value escapes as a result of checkBind.
-// A value escapes in three possible cases:
-// (1) we are binding to something that is not a memory region.
-// (2) we are binding to a memregion that does not have stack storage
-// (3) we are binding to a memregion with stack storage that the store
-// does not understand.
-void MallocChecker::checkBind(SVal loc, SVal val, const Stmt *S,
- CheckerContext &C) const {
- // Are we storing to something that causes the value to "escape"?
- bool escapes = true;
- ProgramStateRef state = C.getState();
-
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
- escapes = !regionLoc->getRegion()->hasStackStorage();
-
- if (!escapes) {
- // To test (3), generate a new state with the binding added. If it is
- // the same state, then it escapes (since the store cannot represent
- // the binding).
- // Do this only if we know that the store is not supposed to generate the
- // same state.
- SVal StoredVal = state->getSVal(regionLoc->getRegion());
- if (StoredVal != val)
- escapes = (state == (state->bindLoc(*regionLoc, val)));
- }
- }
-
- // If our store can represent the binding and we aren't storing to something
- // that doesn't have local storage then just return and have the simulation
- // state continue as is.
- if (!escapes)
- return;
-
- // Otherwise, find all symbols referenced by 'val' that we are tracking
- // and stop tracking them.
- state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
- C.addTransition(state);
-}
-
// If a symbolic region is assumed to NULL (or another constant), stop tracking
// it - assuming that allocation failed on this path.
ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
@@ -1352,7 +1781,7 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
if (RS->isReleased()) {
if (I.getData().Kind == RPToBeFreedAfterFailure)
state = state->set<RegionState>(ReallocSym,
- RefState::getAllocated(RS->getStmt()));
+ RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
else if (I.getData().Kind == RPDoNotTrackAfterFailure)
state = state->remove<RegionState>(ReallocSym);
else
@@ -1365,12 +1794,8 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
return state;
}
-// Check if the function is known to us. So, for example, we could
-// conservatively assume it can free/reallocate its pointer arguments.
-// (We assume that the pointers cannot escape through calls to system
-// functions not handled by this checker.)
-bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
- ProgramStateRef State) const {
+bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
+ ProgramStateRef State) const {
assert(Call);
// For now, assume that any C++ call can free memory.
@@ -1387,24 +1812,23 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
if (!Call->isInSystemHeader() || Call->hasNonZeroCallbackArg())
return false;
- Selector S = Msg->getSelector();
-
- // Whitelist the ObjC methods which do free memory.
- // - Anything containing 'freeWhenDone' param set to 1.
- // Ex: dataWithBytesNoCopy:length:freeWhenDone.
- for (unsigned i = 1; i < S.getNumArgs(); ++i) {
- if (S.getNameForSlot(i).equals("freeWhenDone")) {
- if (Call->getArgSVal(i).isConstant(1))
- return false;
- else
- return true;
- }
- }
+ // If it's a method we know about, handle it explicitly post-call.
+ // This should happen before the "freeWhenDone" check below.
+ if (isKnownDeallocObjCMethodName(*Msg))
+ return true;
- // If the first selector ends with NoCopy, assume that the ownership is
- // transferred as well.
- // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
- StringRef FirstSlot = S.getNameForSlot(0);
+ // If there's a "freeWhenDone" parameter, but the method isn't one we know
+ // about, we can't be sure that the object will use free() to deallocate the
+ // memory, so we can't model it explicitly. The best we can do is use it to
+ // decide whether the pointer escapes.
+ if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
+ return !*FreeWhenDone;
+
+ // If the first selector piece ends with "NoCopy", and there is no
+ // "freeWhenDone" parameter set to zero, we know ownership is being
+ // transferred. Again, though, we can't be sure that the object will use
+ // free() to deallocate the memory, so we can't model it explicitly.
+ StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
if (FirstSlot.endswith("NoCopy"))
return false;
@@ -1509,41 +1933,50 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
return true;
}
-// If the symbol we are tracking is invalidated, but not explicitly (ex: the &p
-// escapes, when we are tracking p), do not track the symbol as we cannot reason
-// about it anymore.
-ProgramStateRef
-MallocChecker::checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const {
- if (!invalidated || invalidated->empty())
- return State;
- llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
+static bool retTrue(const RefState *RS) {
+ return true;
+}
- // If it's a call which might free or reallocate memory, we assume that all
- // regions (explicit and implicit) escaped.
+static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
+ return (RS->getAllocationFamily() == AF_CXXNewArray ||
+ RS->getAllocationFamily() == AF_CXXNew);
+}
- // Otherwise, whitelist explicit pointers; we still can track them.
- if (!Call || doesNotFreeMemory(Call, State)) {
- for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
- E = ExplicitRegions.end(); I != E; ++I) {
- if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
- WhitelistedSymbols.insert(R->getSymbol());
- }
+ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return checkPointerEscapeAux(State, Escaped, Call, Kind, &retTrue);
+}
+
+ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return checkPointerEscapeAux(State, Escaped, Call, Kind,
+ &checkIfNewOrNewArrayFamily);
+}
+
+ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ 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.
+ if ((Kind == PSK_DirectEscapeOnCall ||
+ Kind == PSK_IndirectEscapeOnCall) &&
+ doesNotFreeMemOrInteresting(Call, State)) {
+ return State;
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
- E = invalidated->end(); I!=E; ++I) {
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end();
+ I != E; ++I) {
SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
- // The symbol escaped. Note, we assume that if the symbol is released,
- // passing it out will result in a use after free. We also keep tracking
- // relinquished symbols.
+
if (const RefState *RS = State->get<RegionState>(sym)) {
- if (RS->isAllocated())
+ if (RS->isAllocated() && CheckRefState(RS))
State = State->remove<RegionState>(sym);
}
}
@@ -1584,16 +2017,16 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
// Retrieve the associated statement.
ProgramPoint ProgLoc = N->getLocation();
- if (StmtPoint *SP = dyn_cast<StmtPoint>(&ProgLoc))
+ if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) {
S = SP->getStmt();
- else if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&ProgLoc))
+ } else if (Optional<CallExitEnd> Exit = ProgLoc.getAs<CallExitEnd>()) {
S = Exit->getCalleeContext()->getCallSite();
- // If an assumption was made on a branch, it should be caught
- // here by looking at the state transition.
- else if (BlockEdge *Edge = dyn_cast<BlockEdge>(&ProgLoc)) {
- const CFGBlock *srcBlk = Edge->getSrc();
- S = srcBlk->getTerminator();
+ } else if (Optional<BlockEdge> Edge = ProgLoc.getAs<BlockEdge>()) {
+ // If an assumption was made on a branch, it should be caught
+ // here by looking at the state transition.
+ S = Edge->getSrc()->getTerminator();
}
+
if (!S)
return 0;
@@ -1658,8 +2091,15 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
RegionStateTy RS = State->get<RegionState>();
- if (!RS.isEmpty())
- Out << "Has Malloc data" << NL;
+ if (!RS.isEmpty()) {
+ Out << Sep << "MallocChecker:" << NL;
+ for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+ I.getKey()->dumpToStream(Out);
+ Out << " : ";
+ I.getData().dump(Out);
+ Out << NL;
+ }
+ }
}
#define REGISTER_CHECKER(name) \
@@ -1670,3 +2110,5 @@ void ento::register##name(CheckerManager &mgr) {\
REGISTER_CHECKER(MallocPessimistic)
REGISTER_CHECKER(MallocOptimistic)
+REGISTER_CHECKER(NewDeleteChecker)
+REGISTER_CHECKER(MismatchedDeallocatorChecker)
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index daec4180a0c2..34425e314062 100644
--- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -20,9 +20,9 @@
#include "ClangSACheckers.h"
#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -44,18 +44,18 @@ public:
BugReporter &BR) const;
void CheckMallocArgument(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Expr *TheArgument, ASTContext &Context) const;
void OutputPossibleOverflows(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Decl *D, BugReporter &BR, AnalysisManager &mgr) const;
};
} // end anonymous namespace
void MallocOverflowSecurityChecker::CheckMallocArgument(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Expr *TheArgument,
ASTContext &Context) const {
@@ -111,7 +111,7 @@ namespace {
class CheckOverflowOps :
public EvaluatedExprVisitor<CheckOverflowOps> {
public:
- typedef llvm::SmallVectorImpl<MallocOverflowCheck> theVecType;
+ typedef SmallVectorImpl<MallocOverflowCheck> theVecType;
private:
theVecType &toScanFor;
@@ -197,7 +197,7 @@ private:
// detect the most blatent cases of overflow and educate the
// programmer.
void MallocOverflowSecurityChecker::OutputPossibleOverflows(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Decl *D, BugReporter &BR, AnalysisManager &mgr) const {
// By far the most common case: nothing to check.
if (PossibleMallocOverflows.empty())
@@ -230,13 +230,13 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
return;
// A list of variables referenced in possibly overflowing malloc operands.
- llvm::SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows;
+ SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows;
for (CFG::iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) {
CFGBlock *block = *it;
for (CFGBlock::iterator bi = block->begin(), be = block->end();
bi != be; ++bi) {
- if (const CFGStmt *CS = bi->getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> CS = bi->getAs<CFGStmt>()) {
if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
// Get the callee.
const FunctionDecl *FD = TheCall->getDirectCallee();
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index fb40f222b846..ce7d4ccf7a0a 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -14,13 +14,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -225,7 +226,7 @@ public:
OS << " is converted to a pointer of type '"
<< PointeeType.getAsString() << "', which is incompatible with "
<< "sizeof operand type '" << SizeofType.getAsString() << "'";
- llvm::SmallVector<SourceRange, 4> Ranges;
+ SmallVector<SourceRange, 4> Ranges;
Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
if (TSI)
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 3331bc8a9a8d..fc28e1fb7f49 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -16,15 +16,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.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/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 7a66ec3a934f..9f01522eadbd 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -16,14 +16,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.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/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -185,7 +186,7 @@ static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
const StackFrameContext *
SFC = C.getLocationContext()->getCurrentStackFrame();
- if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(&val)) {
+ if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
if (const StackArgumentsSpaceRegion *
@@ -202,7 +203,7 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
CheckerContext &C) const {
if (!isLoad)
return;
- if (loc.isUndef() || !isa<Loc>(loc))
+ if (loc.isUndef() || !loc.getAs<Loc>())
return;
ASTContext &Ctx = C.getASTContext();
@@ -224,12 +225,12 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
CFErrorII = &Ctx.Idents.get("CFErrorRef");
if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) {
- setFlag<NSErrorOut>(state, state->getSVal(cast<Loc>(loc)), C);
+ setFlag<NSErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
return;
}
if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) {
- setFlag<CFErrorOut>(state, state->getSVal(cast<Loc>(loc)), C);
+ setFlag<CFErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
return;
}
}
@@ -251,18 +252,15 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
return;
// Storing to possible null NSError/CFErrorRef out parameter.
+ SmallString<128> Buf;
+ llvm::raw_svector_ostream os(Buf);
- // Emit an error.
- std::string err;
- llvm::raw_string_ostream os(err);
- os << "Potential null dereference. According to coding standards ";
-
- if (isNSError)
- os << "in 'Creating and Returning NSError Objects' the parameter '";
- else
- os << "documented in CoreFoundation/CFError.h the parameter '";
+ os << "Potential null dereference. According to coding standards ";
+ os << (isNSError
+ ? "in 'Creating and Returning NSError Objects' the parameter"
+ : "documented in CoreFoundation/CFError.h the parameter");
- os << "' may be null.";
+ os << " may be null";
BugType *bug = 0;
if (isNSError)
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index efb707294d56..0009e1b7cf49 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -47,7 +48,7 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
if (!FD)
return;
- if (FD->getAttr<AnalyzerNoReturnAttr>())
+ if (FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn())
BuildSinks = true;
else if (const IdentifierInfo *II = FD->getIdentifier()) {
// HACK: Some functions are not marked noreturn, and don't return.
@@ -100,6 +101,15 @@ static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) {
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
CheckerContext &C) const {
+ // Check if the method is annotated with analyzer_noreturn.
+ if (const ObjCMethodDecl *MD = Msg.getDecl()) {
+ MD = MD->getCanonicalDecl();
+ if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
+ C.generateSink();
+ return;
+ }
+ }
+
// HACK: This entire check is to handle two messages in the Cocoa frameworks:
// -[NSAssertionHandler
// handleFailureInMethod:object:file:lineNumber:description:]
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
new file mode 100644
index 000000000000..273a7a38824a
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -0,0 +1,193 @@
+//===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NonNullParamChecker, which checks for arguments expected not to
+// be null due to:
+// - the corresponding parameters being declared to have nonnull attribute
+// - the corresponding parameters being references; since the call would form
+// a reference to a null pointer
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/Attr.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/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class NonNullParamChecker
+ : public Checker< check::PreCall > {
+ mutable OwningPtr<BugType> BTAttrNonNull;
+ mutable OwningPtr<BugType> BTNullRefArg;
+public:
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+ BugReport *genReportNullAttrNonNull(const ExplodedNode *ErrorN,
+ const Expr *ArgE) const;
+ BugReport *genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
+ const Expr *ArgE) const;
+};
+} // end anonymous namespace
+
+void NonNullParamChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const Decl *FD = Call.getDecl();
+ if (!FD)
+ return;
+
+ const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
+
+ ProgramStateRef state = C.getState();
+
+ CallEvent::param_type_iterator TyI = Call.param_type_begin(),
+ TyE = Call.param_type_end();
+
+ for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){
+
+ // Check if the parameter is a reference. We want to report when reference
+ // to a null pointer is passed as a paramter.
+ bool haveRefTypeParam = false;
+ if (TyI != TyE) {
+ haveRefTypeParam = (*TyI)->isReferenceType();
+ TyI++;
+ }
+
+ bool haveAttrNonNull = Att && Att->isNonNull(idx);
+
+ if (!haveRefTypeParam && !haveAttrNonNull)
+ continue;
+
+ // If the value is unknown or undefined, we can't perform this check.
+ const Expr *ArgE = Call.getArgExpr(idx);
+ SVal V = Call.getArgSVal(idx);
+ Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
+ if (!DV)
+ continue;
+
+ // Process the case when the argument is not a location.
+ assert(!haveRefTypeParam || DV->getAs<Loc>());
+
+ if (haveAttrNonNull && !DV->getAs<Loc>()) {
+ // If the argument is a union type, we want to handle a potential
+ // transparent_union GCC extension.
+ if (!ArgE)
+ continue;
+
+ QualType T = ArgE->getType();
+ const RecordType *UT = T->getAsUnionType();
+ if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ continue;
+
+ if (Optional<nonloc::CompoundVal> CSV =
+ DV->getAs<nonloc::CompoundVal>()) {
+ nonloc::CompoundVal::iterator CSV_I = CSV->begin();
+ assert(CSV_I != CSV->end());
+ V = *CSV_I;
+ DV = V.getAs<DefinedSVal>();
+ assert(++CSV_I == CSV->end());
+ if (!DV)
+ continue;
+ // Retrieve the corresponding expression.
+ if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
+ if (const InitListExpr *IE =
+ dyn_cast<InitListExpr>(CE->getInitializer()))
+ ArgE = dyn_cast<Expr>(*(IE->begin()));
+
+ } else {
+ // FIXME: Handle LazyCompoundVals?
+ continue;
+ }
+ }
+
+ ConstraintManager &CM = C.getConstraintManager();
+ ProgramStateRef stateNotNull, stateNull;
+ llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+
+ if (stateNull && !stateNotNull) {
+ // Generate an error node. Check for a null node in case
+ // we cache out.
+ if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
+
+ BugReport *R = 0;
+ if (haveAttrNonNull)
+ R = genReportNullAttrNonNull(errorNode, ArgE);
+ else if (haveRefTypeParam)
+ R = genReportReferenceToNullPointer(errorNode, ArgE);
+
+ // Highlight the range of the argument that was null.
+ R->addRange(Call.getArgSourceRange(idx));
+
+ // Emit the bug report.
+ C.emitReport(R);
+ }
+
+ // Always return. Either we cached out or we just emitted an error.
+ return;
+ }
+
+ // If a pointer value passed the check we should assume that it is
+ // indeed not null from this point forward.
+ assert(stateNotNull);
+ state = stateNotNull;
+ }
+
+ // If we reach here all of the arguments passed the nonnull check.
+ // If 'state' has been updated generated a new node.
+ C.addTransition(state);
+}
+
+BugReport *NonNullParamChecker::genReportNullAttrNonNull(
+ const ExplodedNode *ErrorNode, const Expr *ArgE) const {
+ // Lazily allocate the BugType object if it hasn't already been
+ // created. Ownership is transferred to the BugReporter object once
+ // the BugReport is passed to 'EmitWarning'.
+ if (!BTAttrNonNull)
+ BTAttrNonNull.reset(new BugType(
+ "Argument with 'nonnull' attribute passed null",
+ "API"));
+
+ BugReport *R = new BugReport(*BTAttrNonNull,
+ "Null pointer passed as an argument to a 'nonnull' parameter",
+ ErrorNode);
+ if (ArgE)
+ bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
+
+ return R;
+}
+
+BugReport *NonNullParamChecker::genReportReferenceToNullPointer(
+ const ExplodedNode *ErrorNode, const Expr *ArgE) const {
+ if (!BTNullRefArg)
+ BTNullRefArg.reset(new BuiltinBug("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)
+ ArgEDeref = ArgE;
+ bugreporter::trackNullOrUndefValue(ErrorNode,
+ ArgEDeref,
+ *R);
+ }
+ return R;
+
+}
+
+void ento::registerNonNullParamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<NonNullParamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 9d84f52f934e..4018a66ecf57 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -14,10 +14,10 @@
#include "ClangSACheckers.h"
#include "clang/AST/StmtObjC.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -42,7 +42,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
SVal V = state->getSVal(Ex, C.getLocationContext());
// Uninitialized value used for the mutex?
- if (isa<UndefinedVal>(V)) {
+ if (V.getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
@@ -60,7 +60,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// Check for null mutexes.
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
+ llvm::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
if (nullState) {
if (!notNullState) {
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 63a84805e73e..4a0309de044e 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index 999c994cb1c6..b9e96ee99fc6 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -17,12 +17,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.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/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
using namespace clang;
using namespace ento;
@@ -72,7 +72,8 @@ void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size,
if (!ArraySym)
return;
- C.addTransition(State->set<ArraySizeMap>(ArraySym, cast<DefinedSVal>(SizeV)));
+ C.addTransition(
+ State->set<ArraySizeMap>(ArraySym, SizeV.castAs<DefinedSVal>()));
return;
}
@@ -125,7 +126,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
SVal IdxVal = State->getSVal(IdxExpr, C.getLocationContext());
if (IdxVal.isUnknownOrUndef())
return;
- DefinedSVal Idx = cast<DefinedSVal>(IdxVal);
+ DefinedSVal Idx = IdxVal.castAs<DefinedSVal>();
// Now, check if 'Idx in [0, Size-1]'.
const QualType T = IdxExpr->getType();
diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
index e906e8aa3016..789b9f4cc19c 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -14,30 +14,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
-static bool isUIViewControllerSubclass(ASTContext &Ctx,
- const ObjCImplementationDecl *D) {
- IdentifierInfo *ViewControllerII = &Ctx.Idents.get("UIViewController");
- const ObjCInterfaceDecl *ID = D->getClassInterface();
-
- for ( ; ID; ID = ID->getSuperClass())
- if (ID->getIdentifier() == ViewControllerII)
- return true;
- return false;
+namespace {
+struct SelectorDescriptor {
+ const char *SelectorName;
+ unsigned ArgumentCount;
+};
}
//===----------------------------------------------------------------------===//
@@ -71,9 +67,102 @@ namespace {
class ObjCSuperCallChecker : public Checker<
check::ASTDecl<ObjCImplementationDecl> > {
public:
+ ObjCSuperCallChecker() : IsInitialized(false) {}
+
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr,
BugReporter &BR) const;
+private:
+ bool isCheckableClass(const ObjCImplementationDecl *D,
+ StringRef &SuperclassName) const;
+ void initializeSelectors(ASTContext &Ctx) const;
+ void fillSelectors(ASTContext &Ctx, ArrayRef<SelectorDescriptor> Sel,
+ StringRef ClassName) const;
+ mutable llvm::StringMap<llvm::SmallSet<Selector, 16> > SelectorsForClass;
+ mutable bool IsInitialized;
};
+
+}
+
+/// \brief Determine whether the given class has a superclass that we want
+/// to check. The name of the found superclass is stored in SuperclassName.
+///
+/// \param D The declaration to check for superclasses.
+/// \param[out] SuperclassName On return, the found superclass name.
+bool ObjCSuperCallChecker::isCheckableClass(const ObjCImplementationDecl *D,
+ StringRef &SuperclassName) const {
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
+ for ( ; ID ; ID = ID->getSuperClass())
+ {
+ SuperclassName = ID->getIdentifier()->getName();
+ if (SelectorsForClass.count(SuperclassName))
+ return true;
+ }
+ return false;
+}
+
+void ObjCSuperCallChecker::fillSelectors(ASTContext &Ctx,
+ ArrayRef<SelectorDescriptor> Sel,
+ StringRef ClassName) const {
+ llvm::SmallSet<Selector, 16> &ClassSelectors = SelectorsForClass[ClassName];
+ // Fill the Selectors SmallSet with all selectors we want to check.
+ for (ArrayRef<SelectorDescriptor>::iterator I = Sel.begin(), E = Sel.end();
+ I != E; ++I) {
+ SelectorDescriptor Descriptor = *I;
+ assert(Descriptor.ArgumentCount <= 1); // No multi-argument selectors yet.
+
+ // Get the selector.
+ IdentifierInfo *II = &Ctx.Idents.get(Descriptor.SelectorName);
+
+ Selector Sel = Ctx.Selectors.getSelector(Descriptor.ArgumentCount, &II);
+ ClassSelectors.insert(Sel);
+ }
+}
+
+void ObjCSuperCallChecker::initializeSelectors(ASTContext &Ctx) const {
+
+ { // Initialize selectors for: UIViewController
+ const SelectorDescriptor Selectors[] = {
+ { "addChildViewController", 1 },
+ { "viewDidAppear", 1 },
+ { "viewDidDisappear", 1 },
+ { "viewWillAppear", 1 },
+ { "viewWillDisappear", 1 },
+ { "removeFromParentViewController", 0 },
+ { "didReceiveMemoryWarning", 0 },
+ { "viewDidUnload", 0 },
+ { "viewDidLoad", 0 },
+ { "viewWillUnload", 0 },
+ { "updateViewConstraints", 0 },
+ { "encodeRestorableStateWithCoder", 1 },
+ { "restoreStateWithCoder", 1 }};
+
+ fillSelectors(Ctx, Selectors, "UIViewController");
+ }
+
+ { // Initialize selectors for: UIResponder
+ const SelectorDescriptor Selectors[] = {
+ { "resignFirstResponder", 0 }};
+
+ fillSelectors(Ctx, Selectors, "UIResponder");
+ }
+
+ { // Initialize selectors for: NSResponder
+ const SelectorDescriptor Selectors[] = {
+ { "encodeRestorableStateWithCoder", 1 },
+ { "restoreStateWithCoder", 1 }};
+
+ fillSelectors(Ctx, Selectors, "NSResponder");
+ }
+
+ { // Initialize selectors for: NSDocument
+ const SelectorDescriptor Selectors[] = {
+ { "encodeRestorableStateWithCoder", 1 },
+ { "restoreStateWithCoder", 1 }};
+
+ fillSelectors(Ctx, Selectors, "NSDocument");
+ }
+
+ IsInitialized = true;
}
void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
@@ -81,29 +170,15 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
BugReporter &BR) const {
ASTContext &Ctx = BR.getContext();
- if (!isUIViewControllerSubclass(Ctx, D))
- return;
-
- const char *SelectorNames[] =
- {"addChildViewController", "viewDidAppear", "viewDidDisappear",
- "viewWillAppear", "viewWillDisappear", "removeFromParentViewController",
- "didReceiveMemoryWarning", "viewDidUnload", "viewWillUnload",
- "viewDidLoad"};
- const unsigned SelectorArgumentCounts[] =
- {1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
- const size_t SelectorCount = llvm::array_lengthof(SelectorNames);
- assert(llvm::array_lengthof(SelectorArgumentCounts) == SelectorCount);
+ // We need to initialize the selector table once.
+ if (!IsInitialized)
+ initializeSelectors(Ctx);
- // Fill the Selectors SmallSet with all selectors we want to check.
- llvm::SmallSet<Selector, 16> Selectors;
- for (size_t i = 0; i < SelectorCount; i++) {
- unsigned ArgumentCount = SelectorArgumentCounts[i];
- const char *SelectorCString = SelectorNames[i];
+ // Find out whether this class has a superclass that we are supposed to check.
+ StringRef SuperclassName;
+ if (!isCheckableClass(D, SuperclassName))
+ return;
- // Get the selector.
- IdentifierInfo *II = &Ctx.Idents.get(SelectorCString);
- Selectors.insert(Ctx.Selectors.getSelector(ArgumentCount, &II));
- }
// Iterate over all instance methods.
for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
@@ -111,7 +186,7 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
I != E; ++I) {
Selector S = (*I)->getSelector();
// Find out whether this is a selector that we want to check.
- if (!Selectors.count(S))
+ if (!SelectorsForClass[SuperclassName].count(S))
continue;
ObjCMethodDecl *MD = *I;
@@ -130,12 +205,12 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
Mgr.getAnalysisDeclContext(D));
const char *Name = "Missing call to superclass";
- SmallString<256> Buf;
+ SmallString<320> Buf;
llvm::raw_svector_ostream os(Buf);
os << "The '" << S.getAsString()
- << "' instance method in UIViewController subclass '" << *D
- << "' is missing a [super " << S.getAsString() << "] call";
+ << "' instance method in " << SuperclassName.str() << " subclass '"
+ << *D << "' is missing a [super " << S.getAsString() << "] call";
BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
os.str(), DLoc);
@@ -161,15 +236,6 @@ void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
improvements like being able to allow for the super-call to be done in a called
method would be good too.
-*** trivial cases:
-UIResponder subclasses
-- resignFirstResponder
-
-NSResponder subclasses
-- cursorUpdate
-
-*** more difficult cases:
-
UIDocument subclasses
- finishedHandlingError:recovered: (is multi-arg)
- finishedHandlingError:recovered: (is multi-arg)
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 98d2a85ace36..8506e08b2b98 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -37,13 +37,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.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/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -122,9 +123,10 @@ static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
static void addSelfFlag(ProgramStateRef state, SVal val,
SelfFlagEnum flag, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
- if (SymbolRef sym = val.getAsSymbol())
+ if (SymbolRef sym = val.getAsSymbol()) {
state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag);
- C.addTransition(state);
+ C.addTransition(state);
+ }
}
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
@@ -253,7 +255,7 @@ void ObjCSelfInitChecker::checkPreCall(const CallEvent &CE,
for (unsigned i = 0; i < NumArgs; ++i) {
SVal argV = CE.getArgSVal(i);
if (isSelfVar(argV, C)) {
- unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ unsigned selfFlags = getSelfFlags(state->getSVal(argV.castAs<Loc>()), C);
C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
@@ -284,7 +286,7 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
// If the address of 'self' is being passed to the call, assume that the
// 'self' after the call will have the same flags.
// EX: log(&self)
- addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
+ addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C);
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
// If 'self' is passed to the call by value, assume that the function
@@ -302,11 +304,16 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
const Stmt *S,
CheckerContext &C) const {
+ if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
+ C.getCurrentAnalysisDeclContext()->getDecl())))
+ return;
+
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
ProgramStateRef state = C.getState();
if (isSelfVar(location, C))
- addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C);
+ addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self,
+ C);
}
@@ -411,10 +418,10 @@ static bool isSelfVar(SVal location, CheckerContext &C) {
AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
if (!analCtx->getSelfDecl())
return false;
- if (!isa<loc::MemRegionVal>(location))
+ if (!location.getAs<loc::MemRegionVal>())
return false;
- loc::MemRegionVal MRV = cast<loc::MemRegionVal>(location);
+ loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>();
if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
return (DR->getDecl() == analCtx->getSelfDecl());
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index 582269c33279..c66c7d019350 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -14,14 +14,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Expr.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
using namespace clang;
using namespace ento;
@@ -88,10 +89,11 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) {
Scan(M, *I);
// Scan the associated categories as well.
- for (const ObjCCategoryDecl *CD =
- ID->getClassInterface()->getCategoryList(); CD ;
- CD = CD->getNextClassCategory()) {
- if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ID->getClassInterface()->visible_categories_begin(),
+ CatEnd = ID->getClassInterface()->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (const ObjCCategoryImplDecl *CID = Cat->getImplementation())
Scan(M, CID);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index b5d9959b8531..bcbfacdb1774 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 47da87f0bcc6..07c82d461941 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index d9b638469525..ffb8cf20207b 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/ImmutableList.h"
@@ -98,7 +98,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
if (X.isUnknownOrUndef())
return;
- DefinedSVal retVal = cast<DefinedSVal>(X);
+ DefinedSVal retVal = X.castAs<DefinedSVal>();
if (state->contains<LockSet>(lockR)) {
if (!BT_doublelock)
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 304051c1394c..79409e85bda4 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -13,16 +13,17 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
@@ -31,8 +32,8 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include <cstdarg>
@@ -49,7 +50,6 @@ using llvm::StrInStrNoCase;
enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg,
DecRefBridgedTransfered,
IncRefMsg, IncRef, MakeCollectable, MayEscape,
- NewAutoreleasePool,
// Stop tracking the argument - the effect of the call is
// unknown.
@@ -782,6 +782,10 @@ public:
const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy);
+ /// Determine if there is a special return effect for this function or method.
+ Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy,
+ const Decl *D);
+
void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const ObjCMethodDecl *MD);
@@ -894,7 +898,6 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
case IncRefMsg:
case MakeCollectable:
case MayEscape:
- case NewAutoreleasePool:
case StopTracking:
case StopTrackingHard:
return StopTrackingHard;
@@ -1134,12 +1137,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
if (S)
break;
- if (RetTy->isPointerType()) {
- if (FD->getAttr<CFAuditedTransferAttr>()) {
- S = getCFCreateGetRuleSummary(FD);
- break;
- }
-
+ if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
@@ -1170,6 +1168,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
break;
}
+ if (FD->getAttr<CFAuditedTransferAttr>()) {
+ S = getCFCreateGetRuleSummary(FD);
+ break;
+ }
+
break;
}
@@ -1272,6 +1275,30 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
+Optional<RetEffect>
+RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
+ const Decl *D) {
+ if (cocoa::isCocoaObjectRef(RetTy)) {
+ if (D->getAttr<NSReturnsRetainedAttr>())
+ return ObjCAllocRetE;
+
+ if (D->getAttr<NSReturnsNotRetainedAttr>() ||
+ D->getAttr<NSReturnsAutoreleasedAttr>())
+ return RetEffect::MakeNotOwned(RetEffect::ObjC);
+
+ } else if (!RetTy->isPointerType()) {
+ return None;
+ }
+
+ if (D->getAttr<CFReturnsRetainedAttr>())
+ return RetEffect::MakeOwned(RetEffect::CF, true);
+
+ if (D->getAttr<CFReturnsNotRetainedAttr>())
+ return RetEffect::MakeNotOwned(RetEffect::CF);
+
+ return None;
+}
+
void
RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD) {
@@ -1286,39 +1313,15 @@ 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 (!GCEnabled) {
- Template->addArg(AF, parm_idx, DecRef);
- }
- } else if (pd->getAttr<CFConsumedAttr>()) {
+ if (pd->getAttr<NSConsumedAttr>())
+ Template->addArg(AF, parm_idx, DecRefMsg);
+ else if (pd->getAttr<CFConsumedAttr>())
Template->addArg(AF, parm_idx, DecRef);
- }
}
QualType RetTy = FD->getResultType();
-
- // Determine if there is a special return effect for this method.
- if (cocoa::isCocoaObjectRef(RetTy)) {
- if (FD->getAttr<NSReturnsRetainedAttr>()) {
- Template->setRetEffect(ObjCAllocRetE);
- }
- else if (FD->getAttr<CFReturnsRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- }
- else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
- }
- else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
- }
- } else if (RetTy->getAs<PointerType>()) {
- if (FD->getAttr<CFReturnsRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- }
- else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
- }
- }
+ if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
+ Template->setRetEffect(*RetE);
}
void
@@ -1329,13 +1332,10 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
assert(Summ && "Must have a valid summary to add annotations to");
RetainSummaryTemplate Template(Summ, *this);
- bool isTrackedLoc = false;
// Effects on the receiver.
- if (MD->getAttr<NSConsumesSelfAttr>()) {
- if (!GCEnabled)
- Template->setReceiverEffect(DecRefMsg);
- }
+ if (MD->getAttr<NSConsumesSelfAttr>())
+ Template->setReceiverEffect(DecRefMsg);
// Effects on the parameters.
unsigned parm_idx = 0;
@@ -1343,37 +1343,16 @@ 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 (!GCEnabled)
- Template->addArg(AF, parm_idx, DecRef);
- }
- else if(pd->getAttr<CFConsumedAttr>()) {
+ if (pd->getAttr<NSConsumedAttr>())
+ Template->addArg(AF, parm_idx, DecRefMsg);
+ else if (pd->getAttr<CFConsumedAttr>()) {
Template->addArg(AF, parm_idx, DecRef);
}
}
- // Determine if there is a special return effect for this method.
- if (cocoa::isCocoaObjectRef(MD->getResultType())) {
- if (MD->getAttr<NSReturnsRetainedAttr>()) {
- Template->setRetEffect(ObjCAllocRetE);
- return;
- }
- if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
- return;
- }
-
- isTrackedLoc = true;
- } else {
- isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
- }
-
- if (isTrackedLoc) {
- if (MD->getAttr<CFReturnsRetainedAttr>())
- Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- else if (MD->getAttr<CFReturnsNotRetainedAttr>())
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
- }
+ QualType RetTy = MD->getResultType();
+ if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
+ Template->setRetEffect(*RetE);
}
const RetainSummary *
@@ -1567,10 +1546,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
Summ = getPersistentSummary(NoRet, DecRefMsg);
addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
- // Create the "drain" selector.
- Summ = getPersistentSummary(NoRet, isGCEnabled() ? DoNothing : DecRef);
- addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);
-
// Create the -dealloc summary.
Summ = getPersistentSummary(NoRet, Dealloc);
addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
@@ -1579,10 +1554,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
Summ = getPersistentSummary(NoRet, Autorelease);
addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
- // Specially handle NSAutoreleasePool.
- addInstMethSummary("NSAutoreleasePool", "init",
- getPersistentSummary(NoRet, NewAutoreleasePool));
-
// For NSWindow, allocated objects are (initially) self-owned.
// FIXME: For now we opt for false negatives with NSWindow, as these objects
// self-own themselves. However, they only do this once they are displayed.
@@ -1601,10 +1572,11 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// as for NSWindow objects.
addClassMethSummary("NSPanel", "alloc", NoTrackYet);
- // Don't track allocated autorelease pools yet, as it is okay to prematurely
+ // Don't track allocated autorelease pools, as it is okay to prematurely
// exit a method.
addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
+ addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
addInstMethSummary("QCRenderer", AllocSumm,
@@ -1872,7 +1844,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
BugReport &BR) {
// FIXME: We will eventually need to handle non-statement-based events
// (__attribute__((cleanup))).
- if (!isa<StmtPoint>(N->getLocation()))
+ if (!N->getLocation().getAs<StmtPoint>())
return NULL;
// Check if the type state has changed.
@@ -1894,7 +1866,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
// This is the allocation site since the previous node had no bindings
// for this symbol.
if (!PrevT) {
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
if (isa<ObjCArrayLiteral>(S)) {
os << "NSArray literal is an object with a +0 retain count";
@@ -1984,7 +1956,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) {
// We only have summaries attached to nodes after evaluating CallExpr and
// ObjCMessageExprs.
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Iterate through the parameter expressions and see if the symbol
@@ -2033,7 +2005,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
// Specially handle CFMakeCollectable and friends.
if (contains(AEffects, MakeCollectable)) {
// Get the name of the function.
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
SVal X =
CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx);
const FunctionDecl *FD = X.getAsFunctionDecl();
@@ -2141,7 +2113,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (os.str().empty())
return 0; // We have nothing to say!
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
PathDiagnosticPiece *P = new PathDiagnosticEventPiece(Pos, os.str());
@@ -2278,7 +2250,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
}
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
- ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
+ const ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
os << " and returned from method '" << MD.getSelector().getAsString()
<< "' is potentially leaked when using garbage collection. Callers "
"of this method do not expect a returned object with a +1 retain "
@@ -2318,10 +2290,10 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// implicit call. (Currently there are no such allocations in Cocoa, though.)
const Stmt *AllocStmt;
ProgramPoint P = AllocNode->getLocation();
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
else
- AllocStmt = cast<PostStmt>(P).getStmt();
+ AllocStmt = P.castAs<PostStmt>().getStmt();
assert(AllocStmt && "All allocations must come from explicit calls");
Location = PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
n->getLocationContext());
@@ -2349,7 +2321,7 @@ class RetainCountChecker
: public Checker< check::Bind,
check::DeadSymbols,
check::EndAnalysis,
- check::EndPath,
+ check::EndFunction,
check::PostStmt<BlockExpr>,
check::PostStmt<CastExpr>,
check::PostStmt<ObjCArrayLiteral>,
@@ -2511,7 +2483,7 @@ public:
ProgramStateRef
checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const;
@@ -2526,7 +2498,7 @@ public:
SymbolRef Sym, ProgramStateRef state) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
@@ -2544,7 +2516,7 @@ public:
SymbolRef sid, RefVal V,
SmallVectorImpl<SymbolRef> &Leaked) const;
- std::pair<ExplodedNode *, ProgramStateRef >
+ ProgramStateRef
handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
const ProgramPointTag *Tag, CheckerContext &Ctx,
SymbolRef Sym, RefVal V) const;
@@ -2601,7 +2573,7 @@ void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
for ( ; I != E; ++I) {
- const VarRegion *VR = *I;
+ const VarRegion *VR = I.getCapturedRegion();
if (VR->getSuperRegion() == R) {
VR = MemMgr.getVarRegion(VR->getDecl(), LC);
}
@@ -2940,9 +2912,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case MakeCollectable:
E = C.isObjCGCEnabled() ? DecRef : DoNothing;
break;
- case NewAutoreleasePool:
- E = C.isObjCGCEnabled() ? DoNothing : NewAutoreleasePool;
- break;
}
// Handle all use-after-releases.
@@ -2982,10 +2951,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
}
break;
- case NewAutoreleasePool:
- assert(!C.isObjCGCEnabled());
- return state;
-
case MayEscape:
if (V.getKind() == RefVal::Owned) {
V = V ^ RefVal::NotOwned;
@@ -3175,7 +3140,8 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
Binding = getRefBinding(state, Sym);
// Invalidate the argument region.
- state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx);
+ state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx,
+ /*CausesPointerEscape*/ false);
// Restore the refcount status of the argument.
if (Binding)
@@ -3259,11 +3225,10 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// Update the autorelease counts.
static SimpleProgramPointTag
AutoreleaseTag("RetainCountChecker : Autorelease");
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag,
- C, Sym, X);
+ state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X);
// Did we cache out?
- if (!Pred)
+ if (!state)
return;
// Get the updated binding.
@@ -3374,7 +3339,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// does not understand.
ProgramStateRef state = C.getState();
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
+ if (Optional<loc::MemRegionVal> regionLoc = loc.getAs<loc::MemRegionVal>()) {
escapes = !regionLoc->getRegion()->hasStackStorage();
if (!escapes) {
@@ -3443,7 +3408,7 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
ProgramStateRef
RetainCountChecker::checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
@@ -3457,7 +3422,7 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state,
WhitelistedSymbols.insert(SR->getSymbol());
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ for (InvalidatedSymbols::const_iterator I=invalidated->begin(),
E = invalidated->end(); I!=E; ++I) {
SymbolRef sym = *I;
if (WhitelistedSymbols.count(sym))
@@ -3472,8 +3437,8 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state,
// Handle dead symbols and end-of-path.
//===----------------------------------------------------------------------===//
-std::pair<ExplodedNode *, ProgramStateRef >
-RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
+ProgramStateRef
+RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
ExplodedNode *Pred,
const ProgramPointTag *Tag,
CheckerContext &Ctx,
@@ -3482,7 +3447,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
// No autorelease counts? Nothing to be done.
if (!ACnt)
- return std::make_pair(Pred, state);
+ return state;
assert(!Ctx.isObjCGCEnabled() && "Autorelease counts in GC mode?");
unsigned Cnt = V.getCount();
@@ -3500,14 +3465,10 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
else
V = V ^ RefVal::NotOwned;
} else {
- V.setCount(Cnt - ACnt);
+ V.setCount(V.getCount() - ACnt);
V.setAutoreleaseCount(0);
}
- state = setRefBinding(state, Sym, V);
- ExplodedNode *N = Ctx.addTransition(state, Pred, Tag);
- if (N == 0)
- state = 0;
- return std::make_pair(N, state);
+ return setRefBinding(state, Sym, V);
}
// Woah! More autorelease counts then retain counts left.
@@ -3534,7 +3495,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
Ctx.emitReport(report);
}
- return std::make_pair((ExplodedNode *)0, (ProgramStateRef )0);
+ return 0;
}
ProgramStateRef
@@ -3559,9 +3520,6 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
CheckerContext &Ctx,
ExplodedNode *Pred) const {
- if (Leaked.empty())
- return Pred;
-
// Generate an intermediate node representing the leak point.
ExplodedNode *N = Ctx.addTransition(state, Pred);
@@ -3584,14 +3542,14 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
return N;
}
-void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
+void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
RefBindingsTy B = state->get<RefBindings>();
ExplodedNode *Pred = Ctx.getPredecessor();
for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, /*Tag=*/0,
- Ctx, I->first, I->second);
+ state = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, Ctx,
+ I->first, I->second);
if (!state)
return;
}
@@ -3631,6 +3589,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ProgramStateRef state = C.getState();
RefBindingsTy B = state->get<RefBindings>();
+ SmallVector<SymbolRef, 10> Leaked;
// Update counts from autorelease pools
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
@@ -3640,20 +3599,19 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
const ProgramPointTag *Tag = getDeadSymbolTag(Sym);
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, Tag, C,
- Sym, *T);
+ state = handleAutoreleaseCounts(state, Pred, Tag, C, Sym, *T);
if (!state)
return;
+
+ // Fetch the new reference count from the state, and use it to handle
+ // this symbol.
+ state = handleSymbolDeath(state, *I, *getRefBinding(state, Sym), Leaked);
}
}
- B = state->get<RefBindings>();
- SmallVector<SymbolRef, 10> Leaked;
-
- for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I != E; ++I) {
- if (const RefVal *T = B.lookup(*I))
- state = handleSymbolDeath(state, *I, *T, Leaked);
+ if (Leaked.empty()) {
+ C.addTransition(state);
+ return;
}
Pred = processLeaks(state, Leaked, C, Pred);
@@ -3663,10 +3621,13 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
return;
// Now generate a new node that nukes the old bindings.
+ // The only bindings left at this point are the leaked symbols.
RefBindingsTy::Factory &F = state->get_context<RefBindings>();
+ B = state->get<RefBindings>();
- for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I != E; ++I)
+ for (SmallVectorImpl<SymbolRef>::iterator I = Leaked.begin(),
+ E = Leaked.end();
+ I != E; ++I)
B = F.remove(B, *I);
state = state->set<RefBindings>(B);
@@ -3678,8 +3639,10 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
RefBindingsTy B = State->get<RefBindings>();
- if (!B.isEmpty())
- Out << Sep << NL;
+ if (B.isEmpty())
+ return;
+
+ Out << Sep << NL;
for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
Out << I->first << " : ";
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index f3560aad8de2..fe253b719b50 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -46,7 +46,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
if (!ER)
return;
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
// Zero index is always in bound, this also passes ElementRegions created for
// pointer casts.
if (Idx.isZeroConstant())
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 37ec1aa7bea0..7a5d99360108 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -14,19 +14,23 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
namespace {
-class ReturnUndefChecker :
- public Checker< check::PreStmt<ReturnStmt> > {
- mutable OwningPtr<BuiltinBug> BT;
+class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
+ mutable OwningPtr<BuiltinBug> BT_Undef;
+ mutable OwningPtr<BuiltinBug> BT_NullReference;
+
+ void emitUndef(CheckerContext &C, const Expr *RetE) const;
+ void checkReference(CheckerContext &C, const Expr *RetE,
+ DefinedOrUnknownSVal RetVal) const;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
@@ -34,43 +38,75 @@ public:
void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
-
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
-
- if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef())
- return;
-
- // "return;" is modeled to evaluate to an UndefinedValue. Allow UndefinedValue
- // to be returned in functions returning void to support the following pattern:
- // void foo() {
- // return;
- // }
- // void test() {
- // return foo();
- // }
+ SVal RetVal = C.getSVal(RetE);
+
const StackFrameContext *SFC = C.getStackFrame();
QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl());
- if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void))
+
+ if (RetVal.isUndef()) {
+ // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal
+ // to be returned in functions returning void to support this pattern:
+ // void foo() {
+ // return;
+ // }
+ // void test() {
+ // return foo();
+ // }
+ if (RT.isNull() || !RT->isVoidType())
+ emitUndef(C, RetE);
return;
+ }
- ExplodedNode *N = C.generateSink();
+ if (RT.isNull())
+ return;
+
+ if (RT->isReferenceType()) {
+ checkReference(C, RetE, RetVal.castAs<DefinedOrUnknownSVal>());
+ return;
+ }
+}
+static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
+ const Expr *TrackingE = 0) {
+ ExplodedNode *N = C.generateSink();
if (!N)
return;
-
- if (!BT)
- BT.reset(new BuiltinBug("Garbage return value",
- "Undefined or garbage value returned to caller"));
-
- BugReport *report =
- new BugReport(*BT, BT->getDescription(), N);
-
- report->addRange(RetE->getSourceRange());
- bugreporter::trackNullOrUndefValue(N, RetE, *report);
-
- C.emitReport(report);
+
+ BugReport *Report = new BugReport(BT, BT.getDescription(), N);
+
+ Report->addRange(RetE->getSourceRange());
+ bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report);
+
+ C.emitReport(Report);
+}
+
+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"));
+ 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);
+
+ if (StNonNull) {
+ // Going forward, assume the location is non-null.
+ C.addTransition(StNonNull);
+ return;
+ }
+
+ // The return value is known to be null. Emit a bug report.
+ if (!BT_NullReference)
+ BT_NullReference.reset(new BuiltinBug("Returning null reference"));
+
+ emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE));
}
void ento::registerReturnUndefChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index ee055adf6e4d..1ccf339bacc1 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -16,8 +16,8 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.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"
@@ -25,7 +25,7 @@ using namespace clang;
using namespace ento;
namespace {
-typedef llvm::SmallVector<SymbolRef, 2> SymbolVector;
+typedef SmallVector<SymbolRef, 2> SymbolVector;
struct StreamState {
private:
@@ -50,8 +50,7 @@ public:
class SimpleStreamChecker : public Checker<check::PostCall,
check::PreCall,
check::DeadSymbols,
- check::Bind,
- check::RegionChanges> {
+ check::PointerEscape> {
mutable IdentifierInfo *IIfopen, *IIfclose;
@@ -80,20 +79,11 @@ public:
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- /// Deal with symbol escape as a byproduct of a bind.
- void checkBind(SVal location, SVal val, const Stmt*S,
- CheckerContext &C) const;
-
- /// Deal with symbol escape as a byproduct of a region change.
- ProgramStateRef
- checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const;
- bool wantsRegionChangeUpdate(ProgramStateRef state) const {
- return true;
- }
+ /// Stop tracking addresses which escape.
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
};
} // end anonymous namespace
@@ -237,7 +227,7 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
ExplodedNode *ErrNode) const {
// Attach bug reports to the leak node.
// TODO: Identify the leaked file descriptor.
- for (llvm::SmallVector<SymbolRef, 2>::iterator
+ for (SmallVector<SymbolRef, 2>::iterator
I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
BugReport *R = new BugReport(*LeakBugType,
"Opened file is never closed; potential resource leak", ErrNode);
@@ -246,45 +236,6 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
}
}
-// Check various ways a symbol can be invalidated.
-// Stop tracking symbols when a value escapes as a result of checkBind.
-// A value escapes in three possible cases:
-// (1) We are binding to something that is not a memory region.
-// (2) We are binding to a MemRegion that does not have stack storage
-// (3) We are binding to a MemRegion with stack storage that the store
-// does not understand.
-void SimpleStreamChecker::checkBind(SVal loc, SVal val, const Stmt *S,
- CheckerContext &C) const {
- // Are we storing to something that causes the value to "escape"?
- bool escapes = true;
- ProgramStateRef state = C.getState();
-
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
- escapes = !regionLoc->getRegion()->hasStackStorage();
-
- if (!escapes) {
- // To test (3), generate a new state with the binding added. If it is
- // the same state, then it escapes (since the store cannot represent
- // the binding). Do this only if we know that the store is not supposed
- // to generate the same state.
- SVal StoredVal = state->getSVal(regionLoc->getRegion());
- if (StoredVal != val)
- escapes = (state == (state->bindLoc(*regionLoc, val)));
- }
- }
-
- // If our store can represent the binding and we aren't storing to something
- // that doesn't have local storage then just return the state and
- // continue as is.
- if (!escapes)
- return;
-
- // Otherwise, find all symbols referenced by 'val' that we are tracking
- // and stop tracking them.
- state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
- C.addTransition(state);
-}
-
bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
// If it's not in a system header, assume it might close a file.
if (!Call.isInSystemHeader())
@@ -300,38 +251,28 @@ bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
return true;
}
-// If the symbol we are tracking is invalidated, do not track the symbol as
+// If the pointer we are tracking escaped, do not track the symbol as
// we cannot reason about it anymore.
ProgramStateRef
-SimpleStreamChecker::checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const {
-
- if (!invalidated || invalidated->empty())
+SimpleStreamChecker::checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ // If we know that the call cannot close a file, there is nothing to do.
+ if ((Kind == PSK_DirectEscapeOnCall ||
+ Kind == PSK_IndirectEscapeOnCall) &&
+ guaranteedNotToCloseFile(*Call)) {
return State;
-
- // If it's a call which might close the file, we assume that all regions
- // (explicit and implicit) escaped. Otherwise, whitelist explicit pointers
- // (the parameters to the call); we still can track them.
- llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
- if (!Call || guaranteedNotToCloseFile(*Call)) {
- for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
- E = ExplicitRegions.end(); I != E; ++I) {
- if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
- WhitelistedSymbols.insert(R->getSymbol());
- }
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
- E = invalidated->end(); I!=E; ++I) {
- SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end();
+ I != E; ++I) {
+ SymbolRef Sym = *I;
+
// The symbol escaped. Optimistically, assume that the corresponding file
// handle will be closed somewhere else.
- State = State->remove<StreamMap>(sym);
+ State = State->remove<StreamMap>(Sym);
}
return State;
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 0c2f26683745..4fd778ef58ca 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -13,38 +13,40 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/SourceManager.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
- check::EndPath > {
+ check::EndFunction > {
mutable OwningPtr<BuiltinBug> BT_stackleak;
mutable OwningPtr<BuiltinBug> BT_returnstack;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
- void checkEndPath(CheckerContext &Ctx) const;
+ void checkEndFunction(CheckerContext &Ctx) const;
private:
void EmitStackError(CheckerContext &C, const MemRegion *R,
const Expr *RetE) const;
- static SourceRange GenName(raw_ostream &os, const MemRegion *R,
- SourceManager &SM);
+ static SourceRange genName(raw_ostream &os, const MemRegion *R,
+ ASTContext &Ctx);
};
}
-SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os,
- const MemRegion *R,
- SourceManager &SM) {
+SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
+ ASTContext &Ctx) {
// Get the base region, stripping away fields and elements.
R = R->getBaseRegion();
+ SourceManager &SM = Ctx.getSourceManager();
SourceRange range;
os << "Address of ";
@@ -77,8 +79,10 @@ SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os,
range = VR->getDecl()->getSourceRange();
}
else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) {
- os << "stack memory associated with temporary object of type '"
- << TOR->getValueType().getAsString() << '\'';
+ QualType Ty = TOR->getValueType().getLocalUnqualifiedType();
+ os << "stack memory associated with temporary object of type '";
+ Ty.print(os, Ctx.getPrintingPolicy());
+ os << "'";
range = TOR->getExpr()->getSourceRange();
}
else {
@@ -102,7 +106,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
// Generate a report for this bug.
SmallString<512> buf;
llvm::raw_svector_ostream os(buf);
- SourceRange range = GenName(os, R, C.getSourceManager());
+ SourceRange range = genName(os, R, C.getASTContext());
os << " returned to caller";
BugReport *report = new BugReport(*BT_returnstack, os.str(), N);
report->addRange(RetE->getSourceRange());
@@ -155,7 +159,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
EmitStackError(C, R, RetE);
}
-void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
+void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
// Iterate over all bindings to global variables and see if it contains
@@ -222,8 +226,7 @@ void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
// Generate a report for this bug.
SmallString<512> buf;
llvm::raw_svector_ostream os(buf);
- SourceRange range = GenName(os, cb.V[i].second,
- Ctx.getSourceManager());
+ SourceRange range = genName(os, cb.V[i].second, Ctx.getASTContext());
os << " is still referred to by the global variable '";
const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
os << *VR->getDecl()
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index c06ba7c304e6..ffdf2d54b4ce 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -57,9 +57,7 @@ struct StreamState {
};
class StreamChecker : public Checker<eval::Call,
- check::DeadSymbols,
- check::EndPath,
- check::PreStmt<ReturnStmt> > {
+ check::DeadSymbols > {
mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
*II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
@@ -75,8 +73,6 @@ public:
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(CheckerContext &Ctx) const;
- void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
private:
void Fopen(CheckerContext &C, const CallExpr *CE) const;
@@ -214,9 +210,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 =
- cast<DefinedSVal>(svalBuilder.conjureSymbolVal(0, CE, LCtx,
- C.blockCount()));
+ DefinedSVal RetVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount())
+ .castAs<DefinedSVal>();
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
@@ -264,7 +259,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
return;
// Check the legality of the 'whence' argument of 'fseek'.
SVal Whence = state->getSVal(CE->getArg(2), C.getLocationContext());
- const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
+ Optional<nonloc::ConcreteInt> CI = Whence.getAs<nonloc::ConcreteInt>();
if (!CI)
return;
@@ -342,7 +337,7 @@ void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
CheckerContext &C) const {
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
+ Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>();
if (!DV)
return 0;
@@ -405,9 +400,8 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
SymbolRef Sym = *I;
ProgramStateRef state = C.getState();
const StreamState *SS = state->get<StreamMap>(Sym);
- // TODO: Shouldn't we have a continue here?
if (!SS)
- return;
+ continue;
if (SS->isOpened()) {
ExplodedNode *N = C.generateSink();
@@ -423,47 +417,6 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
}
-void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
- ProgramStateRef state = Ctx.getState();
- StreamMapTy M = state->get<StreamMap>();
-
- for (StreamMapTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- StreamState SS = I->second;
- if (SS.isOpened()) {
- ExplodedNode *N = Ctx.addTransition(state);
- if (N) {
- if (!BT_ResourceLeak)
- BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak."));
- BugReport *R = new BugReport(*BT_ResourceLeak,
- BT_ResourceLeak->getDescription(), N);
- Ctx.emitReport(R);
- }
- }
- }
-}
-
-void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
- const Expr *RetE = S->getRetValue();
- if (!RetE)
- return;
-
- ProgramStateRef state = C.getState();
- SymbolRef Sym = state->getSVal(RetE, C.getLocationContext()).getAsSymbol();
-
- if (!Sym)
- return;
-
- const StreamState *SS = state->get<StreamMap>(Sym);
- if(!SS)
- return;
-
- if (SS->isOpened())
- state = state->set<StreamMap>(Sym, StreamState::getEscaped(S));
-
- C.addTransition(state);
-}
-
void ento::registerStreamChecker(CheckerManager &mgr) {
mgr.registerChecker<StreamChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 382be8475bb8..264f7f9fdb92 100644
--- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
index b97cd6c66b93..57c9ed4ce289 100644
--- a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
@@ -18,16 +18,17 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class TraversalDumper : public Checker< check::BranchCondition,
- check::EndPath > {
+ check::EndFunction > {
public:
void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
};
}
@@ -49,8 +50,8 @@ void TraversalDumper::checkBranchCondition(const Stmt *Condition,
<< Parent->getStmtClassName() << "\n";
}
-void TraversalDumper::checkEndPath(CheckerContext &C) const {
- llvm::outs() << "--END PATH--\n";
+void TraversalDumper::checkEndFunction(CheckerContext &C) const {
+ llvm::outs() << "--END FUNCTION--\n";
}
void ento::registerTraversalDumper(CheckerManager &mgr) {
@@ -60,9 +61,11 @@ void ento::registerTraversalDumper(CheckerManager &mgr) {
//------------------------------------------------------------------------------
namespace {
-class CallDumper : public Checker< check::PreCall > {
+class CallDumper : public Checker< check::PreCall,
+ check::PostCall > {
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
};
}
@@ -79,6 +82,26 @@ void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
Call.dump(llvm::outs());
}
+void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
+ const Expr *CallE = Call.getOriginExpr();
+ if (!CallE)
+ return;
+
+ unsigned Indentation = 0;
+ for (const LocationContext *LC = C.getLocationContext()->getParent();
+ LC != 0; LC = LC->getParent())
+ ++Indentation;
+
+ // It is mildly evil to print directly to llvm::outs() rather than emitting
+ // warnings, but this ensures things do not get filtered out by the rest of
+ // the static analyzer machinery.
+ llvm::outs().indent(Indentation);
+ if (Call.getResultType()->isVoidType())
+ llvm::outs() << "Returning void\n";
+ else
+ llvm::outs() << "Returning " << C.getSVal(CallE) << "\n";
+}
+
void ento::registerCallDumper(CheckerManager &mgr) {
mgr.registerChecker<CallDumper>();
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 70e141e574cd..8235e68937af 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
@@ -90,7 +90,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
- if (PostStmt *PS = dyn_cast<PostStmt>(&P))
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 30ccffaab055..93812f714856 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -12,11 +12,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Attr.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/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -67,18 +68,15 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
for (; I != E; ++I) {
// This VarRegion is the region associated with the block; we need
// the one associated with the encompassing context.
- const VarRegion *VR = *I;
+ const VarRegion *VR = I.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
continue;
// Get the VarRegion associated with VD in the local stack frame.
- const LocationContext *LC = C.getLocationContext();
- VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
- SVal VRVal = state->getSVal(VR);
-
- if (VRVal.isUndef())
+ if (Optional<UndefinedVal> V =
+ state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
BT.reset(new BuiltinBug("uninitialized variable captured by block"));
@@ -93,11 +91,13 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
BugReport *R = new BugReport(*BT, os.str(), N);
if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
R->addRange(Ex->getSourceRange());
- R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR));
+ R->addVisitor(new FindLastStoreBRVisitor(*V, VR,
+ /*EnableNullFPSuppression*/false));
R->disablePathPruning();
// need location of block
C.emitReport(R);
}
+ }
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 415bab57287e..673356319833 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -13,12 +13,13 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index b3a83e8e9179..176ee480826c 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
@@ -34,18 +34,28 @@ public:
void
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
CheckerContext &C) const {
- if (C.getState()->getSVal(A->getIdx(), C.getLocationContext()).isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT)
- BT.reset(new BuiltinBug("Array subscript is undefined"));
-
- // Generate a report for this bug.
- BugReport *R = new BugReport(*BT, BT->getName(), N);
- R->addRange(A->getIdx()->getSourceRange());
- bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
- C.emitReport(R);
- }
- }
+ const Expr *Index = A->getIdx();
+ if (!C.getSVal(Index).isUndef())
+ return;
+
+ // Sema generates anonymous array variables for copying array struct fields.
+ // Don't warn if we're in an implicitly-generated constructor.
+ const Decl *D = C.getLocationContext()->getDecl();
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D))
+ if (Ctor->isImplicitlyDefined())
+ return;
+
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ if (!BT)
+ BT.reset(new BuiltinBug("Array subscript is undefined"));
+
+ // Generate a report for this bug.
+ BugReport *R = new BugReport(*BT, BT->getName(), N);
+ R->addRange(A->getIdx()->getSourceRange());
+ bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
+ C.emitReport(R);
}
void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 410010a335c3..e04f49c3746d 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 171e15b85ae7..4ea07e29ebbb 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -13,20 +13,20 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.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"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
#include <fcntl.h>
using namespace clang;
using namespace ento;
-using llvm::Optional;
namespace {
class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
@@ -102,21 +102,20 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// Now check if oflags has O_CREAT set.
const Expr *oflagsEx = CE->getArg(1);
const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
- if (!isa<NonLoc>(V)) {
+ 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;
}
- NonLoc oflags = cast<NonLoc>(V);
- NonLoc ocreateFlag =
- cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),
- oflagsEx->getType()));
+ NonLoc oflags = V.castAs<NonLoc>();
+ NonLoc ocreateFlag = C.getSValBuilder()
+ .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
oflagsEx->getType());
if (maskedFlagsUC.isUnknownOrUndef())
return;
- DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
+ DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
// Check if maskedFlags is non-zero.
ProgramStateRef trueState, falseState;
@@ -201,7 +200,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state,
ProgramStateRef *trueState,
ProgramStateRef *falseState) {
llvm::tie(*trueState, *falseState) =
- state->assume(cast<DefinedSVal>(argVal));
+ state->assume(argVal.castAs<DefinedSVal>());
return (*falseState && !*trueState);
}
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 5a13ed0a2e17..91c2ffb5aabf 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -14,16 +14,16 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.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/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallSet.h"
// The number of CFGBlock pointers we want to reserve memory for. This is used
@@ -76,7 +76,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (!PM)
PM = &LC->getParentMap();
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB->getBlockID());
}
@@ -131,7 +131,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
bool foundUnreachable = false;
for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
ci != ce; ++ci) {
- if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
+ if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) {
foundUnreachable = true;
@@ -189,7 +189,7 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
// Find the Stmt* in a CFGBlock for reporting a warning
const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
- if (const CFGStmt *S = I->getAs<CFGStmt>())
+ if (Optional<CFGStmt> S = I->getAs<CFGStmt>())
return S->getStmt();
}
if (const Stmt *S = CB->getTerminator())
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 58f9ec0f9b9b..30aef060690d 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -15,13 +15,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.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/BugReporter/BugType.h"
-#include "clang/AST/CharUnits.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -109,7 +110,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
}
// Check if the size is zero.
- DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
+ DefinedSVal sizeD = sizeV.castAs<DefinedSVal>();
ProgramStateRef stateNotZero, stateZero;
llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
@@ -129,22 +130,22 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Convert the array length to size_t.
SValBuilder &svalBuilder = C.getSValBuilder();
QualType SizeTy = Ctx.getSizeType();
- NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy,
- SE->getType()));
+ NonLoc ArrayLength =
+ svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>();
// Get the element size.
CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
// Multiply the array length by the element size.
- SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength,
- cast<NonLoc>(EleSizeVal), SizeTy);
+ SVal ArraySizeVal = svalBuilder.evalBinOpNN(
+ state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy);
// Finally, assume that the array's extent matches the given size.
const LocationContext *LC = C.getLocationContext();
DefinedOrUnknownSVal Extent =
state->getRegion(VD, LC)->getExtent(svalBuilder);
- DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
+ DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
DefinedOrUnknownSVal sizeIsKnown =
svalBuilder.evalEQ(state, Extent, ArraySize);
state = state->assume(sizeIsKnown, true);
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index bdc96278f76a..06f01ad75422 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -15,11 +15,12 @@
#include "ClangSACheckers.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/SaveAndRestore.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Core/APSIntType.cpp b/lib/StaticAnalyzer/Core/APSIntType.cpp
index 884b0faa9ed4..c7e95268213e 100644
--- a/lib/StaticAnalyzer/Core/APSIntType.cpp
+++ b/lib/StaticAnalyzer/Core/APSIntType.cpp
@@ -13,20 +13,31 @@ using namespace clang;
using namespace ento;
APSIntType::RangeTestResultKind
-APSIntType::testInRange(const llvm::APSInt &Value) const {
+APSIntType::testInRange(const llvm::APSInt &Value,
+ bool AllowSignConversions) const {
+
// Negative numbers cannot be losslessly converted to unsigned type.
- if (IsUnsigned && Value.isSigned() && Value.isNegative())
+ if (IsUnsigned && !AllowSignConversions &&
+ Value.isSigned() && Value.isNegative())
return RTR_Below;
- // Signed integers can be converted to signed integers of the same width
- // or (if positive) unsigned integers with one fewer bit.
- // Unsigned integers can be converted to unsigned integers of the same width
- // or signed integers with one more bit.
unsigned MinBits;
- if (Value.isSigned())
- MinBits = Value.getMinSignedBits() - IsUnsigned;
- else
- MinBits = Value.getActiveBits() + !IsUnsigned;
+ if (AllowSignConversions) {
+ if (Value.isSigned() && !IsUnsigned)
+ MinBits = Value.getMinSignedBits();
+ else
+ MinBits = Value.getActiveBits();
+
+ } else {
+ // Signed integers can be converted to signed integers of the same width
+ // or (if positive) unsigned integers with one fewer bit.
+ // Unsigned integers can be converted to unsigned integers of the same width
+ // or signed integers with one more bit.
+ if (Value.isSigned())
+ MinBits = Value.getMinSignedBits() - IsUnsigned;
+ else
+ MinBits = Value.getActiveBits() + !IsUnsigned;
+ }
if (MinBits <= BitWidth)
return RTR_Within;
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 011d4c09a23f..747b73c4164b 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -25,7 +25,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
/*AddImplicitDtors=*/true,
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
- Options.shouldSynthesizeBodies()),
+ Options.shouldSynthesizeBodies(),
+ Options.shouldConditionalizeStaticInitializers()),
Ctx(ctx),
Diags(diags),
LangOpts(lang),
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index da88589c8696..ae707395fc5a 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -13,23 +13,68 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace llvm;
+AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
+ if (UserMode == UMK_NotSet) {
+ StringRef ModeStr(Config.GetOrCreateValue("mode", "deep").getValue());
+ UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
+ .Case("shallow", UMK_Shallow)
+ .Case("deep", UMK_Deep)
+ .Default(UMK_NotSet);
+ assert(UserMode != UMK_NotSet && "User mode is invalid.");
+ }
+ return UserMode;
+}
+
+IPAKind AnalyzerOptions::getIPAMode() {
+ if (IPAMode == IPAK_NotSet) {
+
+ // 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;
+ UserModeKind HighLevelMode = getUserMode();
+ if (HighLevelMode == UMK_Shallow)
+ DefaultIPA = "inlining";
+ else if (HighLevelMode == UMK_Deep)
+ DefaultIPA = "dynamic-bifurcate";
+ assert(DefaultIPA);
+
+ // Lookup the ipa configuration option, use the default from User Mode.
+ StringRef ModeStr(Config.GetOrCreateValue("ipa", DefaultIPA).getValue());
+ IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
+ .Case("none", IPAK_None)
+ .Case("basic-inlining", IPAK_BasicInlining)
+ .Case("inlining", IPAK_Inlining)
+ .Case("dynamic", IPAK_DynamicDispatch)
+ .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
+ .Default(IPAK_NotSet);
+ assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid.");
+
+ // Set the member variable.
+ IPAMode = IPAConfig;
+ }
+
+ return IPAMode;
+}
+
bool
AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
- if (IPAMode < Inlining)
+ if (getIPAMode() < IPAK_Inlining)
return false;
if (!CXXMemberInliningMode) {
static const char *ModeKey = "c++-inlining";
StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
- "methods").getValue());
+ "destructors").getValue());
CXXInlineableMemberKind &MutableMode =
const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
@@ -64,8 +109,7 @@ bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
.Default(DefaultVal);
}
-bool AnalyzerOptions::getBooleanOption(llvm::Optional<bool> &V,
- StringRef Name,
+bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
bool DefaultVal) {
if (!V.hasValue())
V = getBooleanOption(Name, DefaultVal);
@@ -90,14 +134,21 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() {
/*Default=*/true);
}
+bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
+ return getBooleanOption(InlineCXXContainerCtorsAndDtors,
+ "c++-container-inlining",
+ /*Default=*/false);
+}
+
+
bool AnalyzerOptions::mayInlineObjCMethod() {
return getBooleanOption(ObjCInliningMode,
"objc-inlining",
/* Default = */ true);
}
-bool AnalyzerOptions::shouldPruneNullReturnPaths() {
- return getBooleanOption(PruneNullReturnPaths,
+bool AnalyzerOptions::shouldSuppressNullReturnPaths() {
+ return getBooleanOption(SuppressNullReturnPaths,
"suppress-null-return-paths",
/* Default = */ true);
}
@@ -108,8 +159,20 @@ bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
/* Default = */ false);
}
+bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
+ return getBooleanOption(SuppressInlinedDefensiveChecks,
+ "suppress-inlined-defensive-checks",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
+ return getBooleanOption(SuppressFromCXXStandardLibrary,
+ "suppress-c++-stdlib",
+ /* Default = */ false);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
- llvm::SmallString<10> StrBuf;
+ SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
OS << DefaultVal;
@@ -127,12 +190,67 @@ unsigned AnalyzerOptions::getAlwaysInlineSize() {
return AlwaysInlineSize.getValue();
}
+unsigned AnalyzerOptions::getMaxInlinableSize() {
+ if (!MaxInlinableSize.hasValue()) {
+
+ int DefaultValue = 0;
+ UserModeKind HighLevelMode = getUserMode();
+ switch (HighLevelMode) {
+ default:
+ llvm_unreachable("Invalid mode.");
+ case UMK_Shallow:
+ DefaultValue = 4;
+ break;
+ case UMK_Deep:
+ DefaultValue = 50;
+ break;
+ }
+
+ MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue);
+ }
+ return MaxInlinableSize.getValue();
+}
+
unsigned AnalyzerOptions::getGraphTrimInterval() {
if (!GraphTrimInterval.hasValue())
GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
return GraphTrimInterval.getValue();
}
+unsigned AnalyzerOptions::getMaxTimesInlineLarge() {
+ if (!MaxTimesInlineLarge.hasValue())
+ MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
+ return MaxTimesInlineLarge.getValue();
+}
+
+unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
+ if (!MaxNodesPerTopLevelFunction.hasValue()) {
+ int DefaultValue = 0;
+ UserModeKind HighLevelMode = getUserMode();
+ switch (HighLevelMode) {
+ default:
+ llvm_unreachable("Invalid mode.");
+ case UMK_Shallow:
+ DefaultValue = 75000;
+ break;
+ case UMK_Deep:
+ DefaultValue = 150000;
+ break;
+ }
+ MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
+ }
+ return MaxNodesPerTopLevelFunction.getValue();
+}
+
bool AnalyzerOptions::shouldSynthesizeBodies() {
return getBooleanOption("faux-bodies", true);
}
+
+bool AnalyzerOptions::shouldPrunePaths() {
+ return getBooleanOption("prune-paths", true);
+}
+
+bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
+ return getBooleanOption("cfg-conditional-static-initializers", true);
+}
+
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index c898d65a5f95..8f8eb3bb8502 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,29 +12,38 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "BugReporter"
+
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Analysis/CFG.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/OwningPtr.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 <queue>
using namespace clang;
using namespace ento;
+STATISTIC(MaxBugClassSize,
+ "The maximum number of bug reports in the same equivalence class");
+STATISTIC(MaxValidBugClassSize,
+ "The maximum number of bug reports in the same equivalence class "
+ "where at least one report is valid (not suppressed)");
+
BugReporterVisitor::~BugReporterVisitor() {}
void BugReporterContext::anchor() {}
@@ -44,13 +53,13 @@ void BugReporterContext::anchor() {}
//===----------------------------------------------------------------------===//
static inline const Stmt *GetStmt(const ProgramPoint &P) {
- if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P))
+ if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
return SP->getStmt();
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
return BE->getSrc()->getTerminator();
- else if (const CallEnter *CE = dyn_cast<CallEnter>(&P))
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>())
return CE->getCallExpr();
- else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P))
+ if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
return CEE->getCalleeContext()->getCallSite();
return 0;
@@ -191,9 +200,8 @@ static void removeRedundantMsgs(PathPieces &path) {
/// Recursively scan through a path and prune out calls and macros pieces
/// that aren't needed. Return true if afterwards the path contains
-/// "interesting stuff" which means it should be pruned from the parent path.
-bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
- PathDiagnosticCallPiece *CallWithLoc) {
+/// "interesting stuff" which means it shouldn't be pruned from the parent path.
+bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) {
bool containsSomethingInteresting = false;
const unsigned N = pieces.size();
@@ -203,7 +211,9 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
pieces.pop_front();
- // Throw away pieces with invalid locations.
+ // Throw away pieces with invalid locations. Note that we can't throw away
+ // calls just yet because they might have something interesting inside them.
+ // If so, their locations will be adjusted as necessary later.
if (piece->getKind() != PathDiagnosticPiece::Call &&
piece->getLocation().asLocation().isInvalid())
continue;
@@ -217,25 +227,16 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
containsSomethingInteresting = true;
break;
}
- // Recursively clean out the subclass. Keep this call around if
- // it contains any informative diagnostics.
- PathDiagnosticCallPiece *NewCallWithLoc =
- call->getLocation().asLocation().isValid()
- ? call : CallWithLoc;
-
- if (!RemoveUneededCalls(call->path, R, NewCallWithLoc))
- continue;
- if (NewCallWithLoc == CallWithLoc && CallWithLoc) {
- call->callEnter = CallWithLoc->callEnter;
- }
+ if (!RemoveUnneededCalls(call->path, R))
+ continue;
containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::Macro: {
PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
- if (!RemoveUneededCalls(macro->subPieces, R))
+ if (!RemoveUnneededCalls(macro->subPieces, R))
continue;
containsSomethingInteresting = true;
break;
@@ -258,36 +259,66 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
return containsSomethingInteresting;
}
+/// Recursively scan through a path and make sure that all call pieces have
+/// valid locations. Note that all other pieces with invalid locations should
+/// have already been pruned out.
+static void adjustCallLocations(PathPieces &Pieces,
+ PathDiagnosticLocation *LastCallLocation = 0) {
+ for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
+ PathDiagnosticCallPiece *Call = dyn_cast<PathDiagnosticCallPiece>(*I);
+
+ if (!Call) {
+ assert((*I)->getLocation().asLocation().isValid());
+ continue;
+ }
+
+ if (LastCallLocation) {
+ if (!Call->callEnter.asLocation().isValid() ||
+ Call->getCaller()->isImplicit())
+ Call->callEnter = *LastCallLocation;
+ if (!Call->callReturn.asLocation().isValid() ||
+ Call->getCaller()->isImplicit())
+ Call->callReturn = *LastCallLocation;
+ }
+
+ // Recursively clean out the subclass. Keep this call around if
+ // it contains any informative diagnostics.
+ PathDiagnosticLocation *ThisCallLocation;
+ if (Call->callEnterWithin.asLocation().isValid() &&
+ !Call->getCallee()->isImplicit())
+ ThisCallLocation = &Call->callEnterWithin;
+ else
+ ThisCallLocation = &Call->callEnter;
+
+ assert(ThisCallLocation && "Outermost call has an invalid location");
+ adjustCallLocations(Call->path, ThisCallLocation);
+ }
+}
+
//===----------------------------------------------------------------------===//
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
-typedef llvm::DenseMap<const ExplodedNode*,
-const ExplodedNode*> NodeBackMap;
-
namespace {
class NodeMapClosure : public BugReport::NodeResolver {
- NodeBackMap& M;
+ InterExplodedGraphMap &M;
public:
- NodeMapClosure(NodeBackMap *m) : M(*m) {}
- ~NodeMapClosure() {}
+ NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
const ExplodedNode *getOriginalNode(const ExplodedNode *N) {
- NodeBackMap::iterator I = M.find(N);
- return I == M.end() ? 0 : I->second;
+ return M.lookup(N);
}
};
class PathDiagnosticBuilder : public BugReporterContext {
BugReport *R;
PathDiagnosticConsumer *PDC;
- OwningPtr<ParentMap> PM;
NodeMapClosure NMC;
public:
const LocationContext *LC;
PathDiagnosticBuilder(GRBugReporter &br,
- BugReport *r, NodeBackMap *Backmap,
+ BugReport *r, InterExplodedGraphMap &Backmap,
PathDiagnosticConsumer *pdc)
: BugReporterContext(br),
R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext())
@@ -552,7 +583,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
ProgramPoint P = N->getLocation();
do {
- if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SMgr);
GRBugReporter& BR = PDB.getBugReporter();
@@ -563,7 +594,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
break;
}
- if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
// Flush all locations, and pop the active path.
bool VisitedEntireCall = PD.isWithinCall();
PD.popActivePath();
@@ -591,7 +622,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
break;
}
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
const CFGBlock *Src = BE->getSrc();
const CFGBlock *Dst = BE->getDst();
const Stmt *T = Src->getTerminator();
@@ -1267,7 +1298,81 @@ static void reversePropagateInterestingSymbols(BugReport &R,
}
}
}
-
+
+//===----------------------------------------------------------------------===//
+// Functions for determining if a loop was executed 0 times.
+//===----------------------------------------------------------------------===//
+
+/// Return true if the terminator is a loop and the destination is the
+/// false branch.
+static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
+ switch (Term->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ break;
+ default:
+ // Note that we intentionally do not include do..while here.
+ return false;
+ }
+
+ // Did we take the false branch?
+ const CFGBlock *Src = BE->getSrc();
+ assert(Src->succ_size() == 2);
+ return (*(Src->succ_begin()+1) == BE->getDst());
+}
+
+static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS) {
+ while (SubS) {
+ if (SubS == S)
+ return true;
+ SubS = PM.getParent(SubS);
+ }
+ return false;
+}
+
+static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
+ const ExplodedNode *N) {
+ while (N) {
+ Optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
+ if (SP) {
+ const Stmt *S = SP->getStmt();
+ if (!isContainedByStmt(PM, Term, S))
+ return S;
+ }
+ N = GetPredecessorNode(N);
+ }
+ return 0;
+}
+
+static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
+ const Stmt *LoopBody = 0;
+ switch (Term->getStmtClass()) {
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast<ForStmt>(Term);
+ if (isContainedByStmt(PM, FS->getInc(), S))
+ return true;
+ LoopBody = FS->getBody();
+ break;
+ }
+ case Stmt::ObjCForCollectionStmtClass: {
+ const ObjCForCollectionStmt *FC = cast<ObjCForCollectionStmt>(Term);
+ LoopBody = FC->getBody();
+ break;
+ }
+ case Stmt::WhileStmtClass:
+ LoopBody = cast<WhileStmt>(Term)->getBody();
+ break;
+ default:
+ return false;
+ }
+ return isContainedByStmt(PM, LoopBody, S);
+}
+
+//===----------------------------------------------------------------------===//
+// Top-level logic for generating extensive path diagnostics.
+//===----------------------------------------------------------------------===//
+
static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
@@ -1284,14 +1389,14 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
ProgramPoint P = N->getLocation();
do {
- if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
if (const Expr *Ex = PS->getStmtAs<Expr>())
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
N->getState().getPtr(), Ex,
N->getLocationContext());
}
- if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
const Stmt *S = CE->getCalleeContext()->getCallSite();
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
@@ -1315,7 +1420,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
// Pop the call hierarchy if we are done walking the contents
// of a function call.
- if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
// Add an edge to the start of the function.
const Decl *D = CE->getCalleeContext()->getDecl();
PathDiagnosticLocation pos =
@@ -1360,7 +1465,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PDB.LC = N->getLocationContext();
// Block edges.
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
// Does this represent entering a call? If so, look at propagating
// interesting symbols across call boundaries.
if (NextNode) {
@@ -1397,16 +1502,39 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(BL);
}
}
-
- if (const Stmt *Term = BE->getSrc()->getTerminator())
+
+ const CFGBlock *BSrc = BE->getSrc();
+ ParentMap &PM = PDB.getParentMap();
+
+ if (const Stmt *Term = BSrc->getTerminator()) {
+ // Are we jumping past the loop body without ever executing the
+ // loop (because the condition was false)?
+ if (isLoopJumpPastBody(Term, &*BE) &&
+ !isInLoopBody(PM,
+ getStmtBeforeCond(PM,
+ BSrc->getTerminatorCondition(),
+ N),
+ Term)) {
+ PathDiagnosticLocation L(Term, SM, PDB.LC);
+ PathDiagnosticEventPiece *PE =
+ new PathDiagnosticEventPiece(L, "Loop body executed 0 times");
+ PE->setPrunable(true);
+
+ EB.addEdge(PE->getLocation(), true);
+ PD.getActivePath().push_front(PE);
+ }
+
+ // In any case, add the terminator as the current statement
+ // context for control edges.
EB.addContext(Term);
+ }
break;
}
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- CFGElement First = BE->getFirstElement();
- if (const CFGStmt *S = First.getAs<CFGStmt>()) {
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ Optional<CFGElement> First = BE->getFirstElement();
+ if (Optional<CFGStmt> S = First ? First->getAs<CFGStmt>() : None) {
const Stmt *stmt = S->getStmt();
if (IsControlFlowExpr(stmt)) {
// Add the proper context for '&&', '||', and '?'.
@@ -1502,8 +1630,9 @@ const Decl *BugReport::getDeclWithIssue() const {
void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
hash.AddPointer(&BT);
hash.AddString(Description);
- if (UniqueingLocation.isValid()) {
- UniqueingLocation.Profile(hash);
+ PathDiagnosticLocation UL = getUniqueingLocation();
+ if (UL.isValid()) {
+ UL.Profile(hash);
} else if (Location.isValid()) {
Location.Profile(hash);
} else {
@@ -1623,7 +1752,7 @@ const Stmt *BugReport::getStmt() const {
ProgramPoint ProgP = ErrorNode->getLocation();
const Stmt *S = NULL;
- if (BlockEntrance *BE = dyn_cast<BlockEntrance>(&ProgP)) {
+ if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
if (BE->getBlock() == &Exit)
S = GetPreviousStmt(ErrorNode);
@@ -1667,6 +1796,9 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
return PathDiagnosticLocation::createOperatorLoc(B, SM);
+ if (ErrorNode->getLocation().getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SM, LC);
+
return PathDiagnosticLocation::createBegin(S, SM, LC);
}
} else {
@@ -1741,141 +1873,174 @@ void BugReporter::FlushReports() {
// PathDiagnostics generation.
//===----------------------------------------------------------------------===//
-static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
- std::pair<ExplodedNode*, unsigned> >
-MakeReportGraph(const ExplodedGraph* G,
- SmallVectorImpl<const ExplodedNode*> &nodes) {
+namespace {
+/// A wrapper around a report graph, which contains only a single path, and its
+/// node maps.
+class ReportGraph {
+public:
+ InterExplodedGraphMap BackMap;
+ OwningPtr<ExplodedGraph> Graph;
+ const ExplodedNode *ErrorNode;
+ size_t Index;
+};
+
+/// A wrapper around a trimmed graph and its node maps.
+class TrimmedGraph {
+ InterExplodedGraphMap InverseMap;
+
+ typedef llvm::DenseMap<const ExplodedNode *, unsigned> PriorityMapTy;
+ PriorityMapTy PriorityMap;
+
+ typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair;
+ SmallVector<NodeIndexPair, 32> ReportNodes;
- // Create the trimmed graph. It will contain the shortest paths from the
- // error nodes to the root. In the new graph we should only have one
- // error node unless there are two or more error nodes with the same minimum
- // path length.
- ExplodedGraph* GTrim;
- InterExplodedGraphMap* NMap;
+ OwningPtr<ExplodedGraph> G;
- llvm::DenseMap<const void*, const void*> InverseMap;
- llvm::tie(GTrim, NMap) = G->Trim(nodes.data(), nodes.data() + nodes.size(),
- &InverseMap);
+ /// A helper class for sorting ExplodedNodes by priority.
+ template <bool Descending>
+ class PriorityCompare {
+ const PriorityMapTy &PriorityMap;
- // Create owning pointers for GTrim and NMap just to ensure that they are
- // released when this function exists.
- OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim);
- OwningPtr<InterExplodedGraphMap> AutoReleaseNMap(NMap);
+ public:
+ PriorityCompare(const PriorityMapTy &M) : PriorityMap(M) {}
+
+ bool operator()(const ExplodedNode *LHS, const ExplodedNode *RHS) const {
+ PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
+ PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
+ PriorityMapTy::const_iterator E = PriorityMap.end();
+
+ if (LI == E)
+ return Descending;
+ if (RI == E)
+ return !Descending;
+
+ return Descending ? LI->second > RI->second
+ : LI->second < RI->second;
+ }
+
+ bool operator()(const NodeIndexPair &LHS, const NodeIndexPair &RHS) const {
+ return (*this)(LHS.first, RHS.first);
+ }
+ };
+
+public:
+ TrimmedGraph(const ExplodedGraph *OriginalGraph,
+ ArrayRef<const ExplodedNode *> Nodes);
+
+ bool popNextReportGraph(ReportGraph &GraphWrapper);
+};
+}
+
+TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
+ ArrayRef<const ExplodedNode *> Nodes) {
+ // The trimmed graph is created in the body of the constructor to ensure
+ // that the DenseMaps have been initialized already.
+ InterExplodedGraphMap ForwardMap;
+ G.reset(OriginalGraph->trim(Nodes, &ForwardMap, &InverseMap));
// Find the (first) error node in the trimmed graph. We just need to consult
- // the node map (NMap) which maps from nodes in the original graph to nodes
+ // the node map which maps from nodes in the original graph to nodes
// in the new graph.
+ llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
- std::queue<const ExplodedNode*> WS;
- typedef llvm::DenseMap<const ExplodedNode*, unsigned> IndexMapTy;
- IndexMapTy IndexMap;
-
- for (unsigned nodeIndex = 0 ; nodeIndex < nodes.size(); ++nodeIndex) {
- const ExplodedNode *originalNode = nodes[nodeIndex];
- if (const ExplodedNode *N = NMap->getMappedNode(originalNode)) {
- WS.push(N);
- IndexMap[originalNode] = nodeIndex;
+ for (unsigned i = 0, count = Nodes.size(); i < count; ++i) {
+ if (const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
+ ReportNodes.push_back(std::make_pair(NewNode, i));
+ RemainingNodes.insert(NewNode);
}
}
- assert(!WS.empty() && "No error node found in the trimmed graph.");
-
- // Create a new (third!) graph with a single path. This is the graph
- // that will be returned to the caller.
- ExplodedGraph *GNew = new ExplodedGraph();
+ assert(!RemainingNodes.empty() && "No error node found in the trimmed graph");
- // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS
- // to the root node, and then construct a new graph that contains only
- // a single path.
- llvm::DenseMap<const void*,unsigned> Visited;
+ // Perform a forward BFS to find all the shortest paths.
+ std::queue<const ExplodedNode *> WS;
- unsigned cnt = 0;
- const ExplodedNode *Root = 0;
+ assert(G->num_roots() == 1);
+ WS.push(*G->roots_begin());
+ unsigned Priority = 0;
while (!WS.empty()) {
const ExplodedNode *Node = WS.front();
WS.pop();
- if (Visited.find(Node) != Visited.end())
- continue;
+ PriorityMapTy::iterator PriorityEntry;
+ bool IsNew;
+ llvm::tie(PriorityEntry, IsNew) =
+ PriorityMap.insert(std::make_pair(Node, Priority));
+ ++Priority;
- Visited[Node] = cnt++;
-
- if (Node->pred_empty()) {
- Root = Node;
- break;
+ if (!IsNew) {
+ assert(PriorityEntry->second <= Priority);
+ continue;
}
- for (ExplodedNode::const_pred_iterator I=Node->pred_begin(),
- E=Node->pred_end(); I!=E; ++I)
+ if (RemainingNodes.erase(Node))
+ if (RemainingNodes.empty())
+ break;
+
+ for (ExplodedNode::const_pred_iterator I = Node->succ_begin(),
+ E = Node->succ_end();
+ I != E; ++I)
WS.push(*I);
}
- assert(Root);
+ // Sort the error paths from longest to shortest.
+ std::sort(ReportNodes.begin(), ReportNodes.end(),
+ PriorityCompare<true>(PriorityMap));
+}
- // Now walk from the root down the BFS path, always taking the successor
- // with the lowest number.
- ExplodedNode *Last = 0, *First = 0;
- NodeBackMap *BM = new NodeBackMap();
- unsigned NodeIndex = 0;
+bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
+ if (ReportNodes.empty())
+ return false;
- for ( const ExplodedNode *N = Root ;;) {
- // Lookup the number associated with the current node.
- llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
- assert(I != Visited.end());
+ const ExplodedNode *OrigN;
+ llvm::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
+ assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
+ "error node not accessible from root");
+ // Create a new graph with a single path. This is the graph
+ // that will be returned to the caller.
+ ExplodedGraph *GNew = new ExplodedGraph();
+ GraphWrapper.Graph.reset(GNew);
+ GraphWrapper.BackMap.clear();
+
+ // Now walk from the error node up the BFS path, always taking the
+ // predeccessor with the lowest number.
+ ExplodedNode *Succ = 0;
+ while (true) {
// Create the equivalent node in the new graph with the same state
// and location.
- ExplodedNode *NewN = GNew->getNode(N->getLocation(), N->getState());
+ ExplodedNode *NewN = GNew->getNode(OrigN->getLocation(), OrigN->getState());
// Store the mapping to the original node.
- llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
+ InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
assert(IMitr != InverseMap.end() && "No mapping to original node.");
- (*BM)[NewN] = (const ExplodedNode*) IMitr->second;
+ GraphWrapper.BackMap[NewN] = IMitr->second;
// Link up the new node with the previous node.
- if (Last)
- NewN->addPredecessor(Last, *GNew);
+ if (Succ)
+ Succ->addPredecessor(NewN, *GNew);
+ else
+ GraphWrapper.ErrorNode = NewN;
- Last = NewN;
+ Succ = NewN;
// Are we at the final node?
- IndexMapTy::iterator IMI =
- IndexMap.find((const ExplodedNode*)(IMitr->second));
- if (IMI != IndexMap.end()) {
- First = NewN;
- NodeIndex = IMI->second;
+ if (OrigN->pred_empty()) {
+ GNew->addRoot(NewN);
break;
}
- // Find the next successor node. We choose the node that is marked
- // with the lowest DFS number.
- ExplodedNode::const_succ_iterator SI = N->succ_begin();
- ExplodedNode::const_succ_iterator SE = N->succ_end();
- N = 0;
-
- for (unsigned MinVal = 0; SI != SE; ++SI) {
-
- I = Visited.find(*SI);
-
- if (I == Visited.end())
- continue;
-
- if (!N || I->second < MinVal) {
- N = *SI;
- MinVal = I->second;
- }
- }
-
- assert(N);
+ // Find the next predeccessor node. We choose the node that is marked
+ // with the lowest BFS number.
+ OrigN = *std::min_element(OrigN->pred_begin(), OrigN->pred_end(),
+ PriorityCompare<false>(PriorityMap));
}
- assert(First);
-
- return std::make_pair(std::make_pair(GNew, BM),
- std::make_pair(First, NodeIndex));
+ return true;
}
+
/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
/// and collapses PathDiagosticPieces that are expanded by macros.
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
@@ -1978,128 +2143,128 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
assert(!bugReports.empty());
bool HasValid = false;
- SmallVector<const ExplodedNode *, 10> errorNodes;
+ bool HasInvalid = false;
+ SmallVector<const ExplodedNode *, 32> errorNodes;
for (ArrayRef<BugReport*>::iterator I = bugReports.begin(),
E = bugReports.end(); I != E; ++I) {
if ((*I)->isValid()) {
HasValid = true;
errorNodes.push_back((*I)->getErrorNode());
} else {
+ // Keep the errorNodes list in sync with the bugReports list.
+ HasInvalid = true;
errorNodes.push_back(0);
}
}
- // If all the reports have been marked invalid, we're done.
+ // If all the reports have been marked invalid by a previous path generation,
+ // we're done.
if (!HasValid)
return false;
- // Construct a new graph that contains only a single path from the error
- // node to a root.
- const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
- std::pair<ExplodedNode*, unsigned> >&
- GPair = MakeReportGraph(&getGraph(), errorNodes);
-
- // Find the BugReport with the original location.
- assert(GPair.second.second < bugReports.size());
- BugReport *R = bugReports[GPair.second.second];
- assert(R && "No original report found for sliced graph.");
- assert(R->isValid() && "Report selected from trimmed graph marked invalid.");
-
- OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first);
- OwningPtr<NodeBackMap> BackMap(GPair.first.second);
- const ExplodedNode *N = GPair.second.first;
-
- // Start building the path diagnostic...
- PathDiagnosticBuilder PDB(*this, R, BackMap.get(), &PC);
-
- // Register additional node visitors.
- R->addVisitor(new NilReceiverBRVisitor());
- R->addVisitor(new ConditionBRVisitor());
-
- BugReport::VisitorList visitors;
- unsigned originalReportConfigToken, finalReportConfigToken;
-
- // While generating diagnostics, it's possible the visitors will decide
- // new symbols and regions are interesting, or add other visitors based on
- // the information they find. If they do, we need to regenerate the path
- // based on our new report configuration.
- do {
- // Get a clean copy of all the visitors.
- for (BugReport::visitor_iterator I = R->visitor_begin(),
- E = R->visitor_end(); I != E; ++I)
- visitors.push_back((*I)->clone());
-
- // Clear out the active path from any previous work.
- PD.resetPath();
- originalReportConfigToken = R->getConfigurationChangeToken();
-
- // Generate the very last diagnostic piece - the piece is visible before
- // the trace is expanded.
- if (PDB.getGenerationScheme() != PathDiagnosticConsumer::None) {
+ typedef PathDiagnosticConsumer::PathGenerationScheme PathGenerationScheme;
+ PathGenerationScheme ActiveScheme = PC.getGenerationScheme();
+
+ TrimmedGraph TrimG(&getGraph(), errorNodes);
+ ReportGraph ErrorGraph;
+
+ while (TrimG.popNextReportGraph(ErrorGraph)) {
+ // Find the BugReport with the original location.
+ assert(ErrorGraph.Index < bugReports.size());
+ BugReport *R = bugReports[ErrorGraph.Index];
+ assert(R && "No original report found for sliced graph.");
+ assert(R->isValid() && "Report selected by trimmed graph marked invalid.");
+
+ // Start building the path diagnostic...
+ PathDiagnosticBuilder PDB(*this, R, ErrorGraph.BackMap, &PC);
+ const ExplodedNode *N = ErrorGraph.ErrorNode;
+
+ // Register additional node visitors.
+ R->addVisitor(new NilReceiverBRVisitor());
+ R->addVisitor(new ConditionBRVisitor());
+ R->addVisitor(new LikelyFalsePositiveSuppressionBRVisitor());
+
+ BugReport::VisitorList visitors;
+ unsigned origReportConfigToken, finalReportConfigToken;
+
+ // While generating diagnostics, it's possible the visitors will decide
+ // new symbols and regions are interesting, or add other visitors based on
+ // the information they find. If they do, we need to regenerate the path
+ // based on our new report configuration.
+ do {
+ // Get a clean copy of all the visitors.
+ for (BugReport::visitor_iterator I = R->visitor_begin(),
+ E = R->visitor_end(); I != E; ++I)
+ visitors.push_back((*I)->clone());
+
+ // Clear out the active path from any previous work.
+ PD.resetPath();
+ origReportConfigToken = R->getConfigurationChangeToken();
+
+ // Generate the very last diagnostic piece - the piece is visible before
+ // the trace is expanded.
PathDiagnosticPiece *LastPiece = 0;
for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
- I != E; ++I) {
+ I != E; ++I) {
if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
assert (!LastPiece &&
- "There can only be one final piece in a diagnostic.");
+ "There can only be one final piece in a diagnostic.");
LastPiece = Piece;
}
}
- if (!LastPiece)
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
- if (LastPiece)
- PD.setEndOfPath(LastPiece);
- else
- return false;
- }
- switch (PDB.getGenerationScheme()) {
- case PathDiagnosticConsumer::Extensive:
- if (!GenerateExtensivePathDiagnostic(PD, PDB, N, visitors)) {
- assert(!R->isValid() && "Failed on valid report");
- // Try again. We'll filter out the bad report when we trim the graph.
- // FIXME: It would be more efficient to use the same intermediate
- // trimmed graph, and just repeat the shortest-path search.
- return generatePathDiagnostic(PD, PC, bugReports);
- }
- break;
- case PathDiagnosticConsumer::Minimal:
- if (!GenerateMinimalPathDiagnostic(PD, PDB, N, visitors)) {
- assert(!R->isValid() && "Failed on valid report");
- // Try again. We'll filter out the bad report when we trim the graph.
- return generatePathDiagnostic(PD, PC, bugReports);
+ if (ActiveScheme != PathDiagnosticConsumer::None) {
+ if (!LastPiece)
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ assert(LastPiece);
+ PD.setEndOfPath(LastPiece);
}
- break;
- case PathDiagnosticConsumer::None:
- if (!GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors)) {
- assert(!R->isValid() && "Failed on valid report");
- // Try again. We'll filter out the bad report when we trim the graph.
- return generatePathDiagnostic(PD, PC, bugReports);
+
+ switch (ActiveScheme) {
+ case PathDiagnosticConsumer::Extensive:
+ GenerateExtensivePathDiagnostic(PD, PDB, N, visitors);
+ break;
+ case PathDiagnosticConsumer::Minimal:
+ GenerateMinimalPathDiagnostic(PD, PDB, N, visitors);
+ break;
+ case PathDiagnosticConsumer::None:
+ GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors);
+ break;
}
- break;
- }
- // Clean up the visitors we used.
- llvm::DeleteContainerPointers(visitors);
+ // Clean up the visitors we used.
+ llvm::DeleteContainerPointers(visitors);
- // Did anything change while generating this path?
- finalReportConfigToken = R->getConfigurationChangeToken();
- } while(finalReportConfigToken != originalReportConfigToken);
+ // Did anything change while generating this path?
+ finalReportConfigToken = R->getConfigurationChangeToken();
+ } while (finalReportConfigToken != origReportConfigToken);
- // Finally, prune the diagnostic path of uninteresting stuff.
- if (!PD.path.empty()) {
- // Remove messages that are basically the same.
- removeRedundantMsgs(PD.getMutablePieces());
+ if (!R->isValid())
+ continue;
- if (R->shouldPrunePath()) {
- bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces(),
- R);
- assert(hasSomethingInteresting);
- (void) hasSomethingInteresting;
+ // Finally, prune the diagnostic path of uninteresting stuff.
+ if (!PD.path.empty()) {
+ // Remove messages that are basically the same.
+ removeRedundantMsgs(PD.getMutablePieces());
+
+ if (R->shouldPrunePath() &&
+ getEngine().getAnalysisManager().options.shouldPrunePaths()) {
+ bool stillHasNotes = RemoveUnneededCalls(PD.getMutablePieces(), R);
+ assert(stillHasNotes);
+ (void)stillHasNotes;
+ }
+
+ adjustCallLocations(PD.getMutablePieces());
}
+
+ // We found a report and didn't suppress it.
+ return true;
}
- return true;
+ // We suppressed all the reports in this equivalence class.
+ assert(!HasInvalid && "Inconsistent suppression");
+ (void)HasInvalid;
+ return false;
}
void BugReporter::Register(BugType *BT) {
@@ -2265,7 +2430,12 @@ void BugReporter::FlushReport(BugReport *exampleReport,
exampleReport->getBugType().getName(),
exampleReport->getDescription(),
exampleReport->getShortDescription(/*Fallback=*/false),
- BT.getCategory()));
+ BT.getCategory(),
+ exampleReport->getUniqueingLocation(),
+ exampleReport->getUniqueingDecl()));
+
+ MaxBugClassSize = std::max(bugReports.size(),
+ static_cast<size_t>(MaxBugClassSize));
// Generate the full path diagnostic, using the generation scheme
// specified by the PathDiagnosticConsumer. Note that we have to generate
@@ -2275,6 +2445,9 @@ void BugReporter::FlushReport(BugReport *exampleReport,
if (!generatePathDiagnostic(*D.get(), PD, bugReports))
return;
+ MaxValidBugClassSize = std::max(bugReports.size(),
+ static_cast<size_t>(MaxValidBugClassSize));
+
// If the path is empty, generate a single step path with the location
// of the issue.
if (D->path.empty()) {
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 328e8a650df1..f600362da94b 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -12,22 +12,23 @@
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
-
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
+using llvm::FoldingSetNodeID;
+
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -39,37 +40,33 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) {
return false;
}
-const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
+const Expr *bugreporter::getDerefExpr(const Stmt *S) {
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
- const PostStmt *Loc = N->getLocationAs<PostStmt>();
- if (!Loc)
- return 0;
-
- const Expr *S = dyn_cast<Expr>(Loc->getStmt());
- if (!S)
+ const Expr *E = dyn_cast<Expr>(S);
+ if (!E)
return 0;
- S = S->IgnoreParenCasts();
+ E = E->IgnoreParenCasts();
while (true) {
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) {
assert(B->isAssignmentOp());
- S = B->getLHS()->IgnoreParenCasts();
+ E = B->getLHS()->IgnoreParenCasts();
continue;
}
- else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
+ else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) {
if (U->getOpcode() == UO_Deref)
return U->getSubExpr()->IgnoreParenCasts();
}
- else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
+ else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
return ME->getBase()->IgnoreParenCasts();
}
}
- else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(S)) {
+ else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
return IvarRef->getBase()->IgnoreParenCasts();
}
- else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
+ else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) {
return AE->getBase();
}
break;
@@ -137,13 +134,15 @@ class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> {
const StackFrameContext *StackFrame;
enum {
Initial,
- MaybeSuppress,
+ MaybeUnsuppress,
Satisfied
} Mode;
+ bool EnableNullFPSuppression;
+
public:
- ReturnVisitor(const StackFrameContext *Frame)
- : StackFrame(Frame), Mode(Initial) {}
+ ReturnVisitor(const StackFrameContext *Frame, bool Suppressed)
+ : StackFrame(Frame), Mode(Initial), EnableNullFPSuppression(Suppressed) {}
static void *getTag() {
static int Tag = 0;
@@ -153,6 +152,7 @@ public:
virtual void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(ReturnVisitor::getTag());
ID.AddPointer(StackFrame);
+ ID.AddBoolean(EnableNullFPSuppression);
}
/// Adds a ReturnVisitor if the given statement represents a call that was
@@ -163,16 +163,17 @@ public:
/// the statement is a call that was inlined, we add the visitor to the
/// bug report, so it can print a note later.
static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S,
- BugReport &BR) {
+ BugReport &BR,
+ bool InEnableNullFPSuppression) {
if (!CallEvent::isCallStmt(S))
return;
// First, find when we processed the statement.
do {
- if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>())
+ if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>())
if (CEE->getCalleeContext()->getCallSite() == S)
break;
- if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>())
+ if (Optional<StmtPoint> SP = Node->getLocationAs<StmtPoint>())
if (SP->getStmt() == S)
break;
@@ -180,19 +181,41 @@ public:
} while (Node);
// Next, step over any post-statement checks.
- while (Node && isa<PostStmt>(Node->getLocation()))
+ while (Node && Node->getLocation().getAs<PostStmt>())
Node = Node->getFirstPred();
+ if (!Node)
+ return;
// Finally, see if we inlined the call.
- if (Node) {
- if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) {
- const StackFrameContext *CalleeContext = CEE->getCalleeContext();
- if (CalleeContext->getCallSite() == S) {
- BR.markInteresting(CalleeContext);
- BR.addVisitor(new ReturnVisitor(CalleeContext));
- }
- }
- }
+ Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>();
+ if (!CEE)
+ return;
+
+ const StackFrameContext *CalleeContext = CEE->getCalleeContext();
+ if (CalleeContext->getCallSite() != S)
+ return;
+
+ // Check the return value.
+ ProgramStateRef State = Node->getState();
+ SVal RetVal = State->getSVal(S, Node->getLocationContext());
+
+ // Handle cases where a reference is returned and then immediately used.
+ if (cast<Expr>(S)->isGLValue())
+ if (Optional<Loc> LValue = RetVal.getAs<Loc>())
+ RetVal = State->getSVal(*LValue);
+
+ // See if the return value is NULL. If so, suppress the report.
+ SubEngine *Eng = State->getStateManager().getOwningEngine();
+ assert(Eng && "Cannot file a bug report without an owning engine");
+ AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+
+ bool EnableNullFPSuppression = false;
+ if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths())
+ if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
+ EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
+
+ BR.markInteresting(CalleeContext);
+ BR.addVisitor(new ReturnVisitor(CalleeContext, EnableNullFPSuppression));
}
/// Returns true if any counter-suppression heuristics are enabled for
@@ -209,7 +232,7 @@ public:
if (N->getLocationContext() != StackFrame)
return 0;
- const StmtPoint *SP = N->getLocationAs<StmtPoint>();
+ Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
if (!SP)
return 0;
@@ -229,35 +252,49 @@ public:
const Expr *RetE = Ret->getRetValue();
assert(RetE && "Tracking a return value for a void function");
+
+ // Handle cases where a reference is returned and then immediately used.
+ Optional<Loc> LValue;
+ if (RetE->isGLValue()) {
+ if ((LValue = V.getAs<Loc>())) {
+ SVal RValue = State->getRawSVal(*LValue, RetE->getType());
+ if (RValue.getAs<DefinedSVal>())
+ V = RValue;
+ }
+ }
+
+ // Ignore aggregate rvalues.
+ if (V.getAs<nonloc::LazyCompoundVal>() ||
+ V.getAs<nonloc::CompoundVal>())
+ return 0;
+
RetE = RetE->IgnoreParenCasts();
// If we can't prove the return value is 0, just mark it interesting, and
// make sure to track it into any further inner functions.
- if (State->assume(cast<DefinedSVal>(V), true)) {
+ if (!State->isNull(V).isConstrainedTrue()) {
BR.markInteresting(V);
- ReturnVisitor::addVisitorIfNecessary(N, RetE, BR);
+ ReturnVisitor::addVisitorIfNecessary(N, RetE, BR,
+ EnableNullFPSuppression);
return 0;
}
// If we're returning 0, we should track where that 0 came from.
- bugreporter::trackNullOrUndefValue(N, RetE, BR);
+ bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false,
+ EnableNullFPSuppression);
// Build an appropriate message based on the return value.
SmallString<64> Msg;
llvm::raw_svector_ostream Out(Msg);
- if (isa<Loc>(V)) {
- // If we are pruning null-return paths as unlikely error paths, mark the
- // report invalid. We still want to emit a path note, however, in case
+ if (V.getAs<Loc>()) {
+ // If we have counter-suppression enabled, make sure we keep visiting
+ // future nodes. We want to emit a path note as well, in case
// the report is resurrected as valid later on.
ExprEngine &Eng = BRC.getBugReporter().getEngine();
AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (Options.shouldPruneNullReturnPaths()) {
- if (hasCounterSuppression(Options))
- Mode = MaybeSuppress;
- else
- BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
- }
+ if (EnableNullFPSuppression && hasCounterSuppression(Options))
+ Mode = MaybeUnsuppress;
if (RetE->getType()->isObjCObjectPointerType())
Out << "Returning nil";
@@ -267,21 +304,37 @@ public:
Out << "Returning zero";
}
- // FIXME: We should have a more generalized location printing mechanism.
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
- if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
- Out << " (loaded from '" << *DD << "')";
+ if (LValue) {
+ if (const MemRegion *MR = LValue->getAsRegion()) {
+ if (MR->canPrintPretty()) {
+ Out << " (reference to '";
+ MR->printPretty(Out);
+ Out << "')";
+ }
+ }
+ } else {
+ // FIXME: We should have a more generalized location printing mechanism.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
+ Out << " (loaded from '" << *DD << "')";
+ }
PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame);
return new PathDiagnosticEventPiece(L, Out.str());
}
- PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext &BRC,
- BugReport &BR) {
+ PathDiagnosticPiece *visitNodeMaybeUnsuppress(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+#ifndef NDEBUG
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ assert(hasCounterSuppression(Options));
+#endif
+
// Are we at the entry node for this call?
- const CallEnter *CE = N->getLocationAs<CallEnter>();
+ Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
return 0;
@@ -290,41 +343,36 @@ public:
Mode = Satisfied;
- ExprEngine &Eng = BRC.getBugReporter().getEngine();
- AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (Options.shouldAvoidSuppressingNullArgumentPaths()) {
- // Don't automatically suppress a report if one of the arguments is
- // known to be a null pointer. Instead, start tracking /that/ null
- // value back to its origin.
- ProgramStateManager &StateMgr = BRC.getStateManager();
- CallEventManager &CallMgr = StateMgr.getCallEventManager();
-
- ProgramStateRef State = N->getState();
- CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
- for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
- SVal ArgV = Call->getArgSVal(I);
- if (!isa<Loc>(ArgV))
- continue;
+ // Don't automatically suppress a report if one of the arguments is
+ // known to be a null pointer. Instead, start tracking /that/ null
+ // value back to its origin.
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
- const Expr *ArgE = Call->getArgExpr(I);
- if (!ArgE)
- continue;
-
- // Is it possible for this argument to be non-null?
- if (State->assume(cast<Loc>(ArgV), true))
- continue;
-
- if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true))
- return 0;
-
- // If we /can't/ track the null pointer, we should err on the side of
- // false negatives, and continue towards marking this report invalid.
- // (We will still look at the other arguments, though.)
- }
+ ProgramStateRef State = N->getState();
+ CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
+ for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
+ Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
+ if (!ArgV)
+ continue;
+
+ const Expr *ArgE = Call->getArgExpr(I);
+ if (!ArgE)
+ continue;
+
+ // Is it possible for this argument to be non-null?
+ if (!State->isNull(*ArgV).isConstrainedTrue())
+ continue;
+
+ if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true,
+ EnableNullFPSuppression))
+ BR.removeInvalidation(ReturnVisitor::getTag(), StackFrame);
+
+ // If we /can't/ track the null pointer, we should err on the side of
+ // false negatives, and continue towards marking this report invalid.
+ // (We will still look at the other arguments, though.)
}
- // There is no reason not to suppress this report; go ahead and do it.
- BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
return 0;
}
@@ -335,14 +383,22 @@ public:
switch (Mode) {
case Initial:
return visitNodeInitial(N, PrevN, BRC, BR);
- case MaybeSuppress:
- return visitNodeMaybeSuppress(N, PrevN, BRC, BR);
+ case MaybeUnsuppress:
+ return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR);
case Satisfied:
return 0;
}
llvm_unreachable("Invalid visit mode!");
}
+
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ if (EnableNullFPSuppression)
+ BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ return 0;
+ }
};
} // end anonymous namespace
@@ -352,6 +408,7 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(&tag);
ID.AddPointer(R);
ID.Add(V);
+ ID.AddBoolean(EnableNullFPSuppression);
}
PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
@@ -359,7 +416,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
BugReport &BR) {
- if (satisfied)
+ if (Satisfied)
return NULL;
const ExplodedNode *StoreSite = 0;
@@ -368,7 +425,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// First see if we reached the declaration of the region.
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- if (const PostStmt *P = Pred->getLocationAs<PostStmt>()) {
+ if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) {
if (DS->getSingleDecl() == VR->getDecl()) {
StoreSite = Pred;
@@ -378,19 +435,36 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
}
}
- // Otherwise, check that Succ has this binding and Pred does not, i.e. this is
- // where the binding first occurred.
+ // If this is a post initializer expression, initializing the region, we
+ // should track the initializer expression.
+ if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) {
+ const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
+ if (FieldReg && FieldReg == R) {
+ StoreSite = Pred;
+ InitE = PIP->getInitializer()->getInit();
+ }
+ }
+
+ // Otherwise, see if this is the store site:
+ // (1) Succ has this binding and Pred does not, i.e. this is
+ // where the binding first occurred.
+ // (2) Succ has this binding and is a PostStore node for this region, i.e.
+ // the same binding was re-assigned here.
if (!StoreSite) {
if (Succ->getState()->getSVal(R) != V)
return NULL;
- if (Pred->getState()->getSVal(R) == V)
- return NULL;
+
+ if (Pred->getState()->getSVal(R) == V) {
+ Optional<PostStore> PS = Succ->getLocationAs<PostStore>();
+ if (!PS || PS->getLocationValue() != R)
+ return NULL;
+ }
StoreSite = Succ;
// If this is an assignment expression, we can track the value
// being assigned.
- if (const PostStmt *P = Succ->getLocationAs<PostStmt>())
+ if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>())
if (BO->isAssignmentOp())
InitE = BO->getRHS();
@@ -399,34 +473,41 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// FIXME: Handle CXXThisRegion as well. (This is not a priority because
// 'this' should never be NULL, but this visitor isn't just for NULL and
// UndefinedVal.)
- if (const CallEnter *CE = Succ->getLocationAs<CallEnter>()) {
- const VarRegion *VR = cast<VarRegion>(R);
- const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
-
- ProgramStateManager &StateMgr = BRC.getStateManager();
- CallEventManager &CallMgr = StateMgr.getCallEventManager();
-
- CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
- Succ->getState());
- InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
- IsParam = true;
+ if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
+
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
+
+ CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
+ Succ->getState());
+ InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
+ IsParam = true;
+ }
}
+
+ // If this is a CXXTempObjectRegion, the Expr responsible for its creation
+ // is wrapped inside of it.
+ if (const CXXTempObjectRegion *TmpR = dyn_cast<CXXTempObjectRegion>(R))
+ InitE = TmpR->getExpr();
}
if (!StoreSite)
return NULL;
- satisfied = true;
+ Satisfied = true;
// If we have an expression that provided the value, try to track where it
// came from.
if (InitE) {
- if (V.isUndef() || isa<loc::ConcreteInt>(V)) {
+ if (V.isUndef() || V.getAs<loc::ConcreteInt>()) {
if (!IsParam)
InitE = InitE->IgnoreParenCasts();
- bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam);
+ bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam,
+ EnableNullFPSuppression);
} else {
ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(),
- BR);
+ BR, EnableNullFPSuppression);
}
}
@@ -437,73 +518,103 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
- if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) {
- if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
-
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Variable '" << *VR->getDecl() << "' ";
+ if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
+ const Stmt *S = PS->getStmt();
+ const char *action = 0;
+ const DeclStmt *DS = dyn_cast<DeclStmt>(S);
+ const VarRegion *VR = dyn_cast<VarRegion>(R);
+
+ if (DS) {
+ action = "initialized to ";
+ } else if (isa<BlockExpr>(S)) {
+ action = "captured by block as ";
+ if (VR) {
+ // See if we can get the BlockVarRegion.
+ ProgramStateRef State = StoreSite->getState();
+ SVal V = State->getSVal(S, PS->getLocationContext());
+ if (const BlockDataRegion *BDR =
+ dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
+ if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
+ if (Optional<KnownSVal> KV =
+ State->getSVal(OriginalR).getAs<KnownSVal>())
+ BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR,
+ EnableNullFPSuppression));
+ }
+ }
}
- else
- return NULL;
+ }
+
+ if (action) {
+ if (!R)
+ return 0;
- if (isa<loc::ConcreteInt>(V)) {
+ os << '\'';
+ R->printPretty(os);
+ os << "' ";
+
+ if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
if (R->isBoundable()) {
if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
if (TR->getValueType()->isObjCObjectPointerType()) {
- os << "initialized to nil";
+ os << action << "nil";
b = true;
}
}
}
if (!b)
- os << "initialized to a null pointer value";
- }
- else if (isa<nonloc::ConcreteInt>(V)) {
- os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
+ os << action << "a null pointer value";
+ } else if (Optional<nonloc::ConcreteInt> CVal =
+ V.getAs<nonloc::ConcreteInt>()) {
+ os << action << CVal->getValue();
}
- else if (V.isUndef()) {
- if (isa<VarRegion>(R)) {
- const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
- if (VD->getInit())
- os << "initialized to a garbage value";
- else
- os << "declared without an initial value";
+ else if (DS) {
+ if (V.isUndef()) {
+ if (isa<VarRegion>(R)) {
+ const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ if (VD->getInit())
+ os << "initialized to a garbage value";
+ else
+ os << "declared without an initial value";
+ }
+ }
+ else {
+ os << "initialized here";
}
- }
- else {
- os << "initialized here";
}
}
- } else if (isa<CallEnter>(StoreSite->getLocation())) {
- const ParmVarDecl *Param = cast<ParmVarDecl>(cast<VarRegion>(R)->getDecl());
+ } else if (StoreSite->getLocation().getAs<CallEnter>()) {
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
- os << "Passing ";
+ os << "Passing ";
- if (isa<loc::ConcreteInt>(V)) {
- if (Param->getType()->isObjCObjectPointerType())
- os << "nil object reference";
- else
- os << "null pointer value";
- } else if (V.isUndef()) {
- os << "uninitialized value";
- } else if (isa<nonloc::ConcreteInt>(V)) {
- os << "the value " << cast<nonloc::ConcreteInt>(V).getValue();
- } else {
- os << "value";
- }
+ if (V.getAs<loc::ConcreteInt>()) {
+ if (Param->getType()->isObjCObjectPointerType())
+ os << "nil object reference";
+ else
+ os << "null pointer value";
+ } else if (V.isUndef()) {
+ os << "uninitialized value";
+ } else if (Optional<nonloc::ConcreteInt> CI =
+ V.getAs<nonloc::ConcreteInt>()) {
+ os << "the value " << CI->getValue();
+ } else {
+ os << "value";
+ }
- // Printed parameter indexes are 1-based, not 0-based.
- unsigned Idx = Param->getFunctionScopeIndex() + 1;
- os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '";
+ // Printed parameter indexes are 1-based, not 0-based.
+ unsigned Idx = Param->getFunctionScopeIndex() + 1;
+ os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '";
- R->printPretty(os);
- os << '\'';
+ R->printPretty(os);
+ os << '\'';
+ }
}
if (os.str().empty()) {
- if (isa<loc::ConcreteInt>(V)) {
+ if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
if (R->isBoundable()) {
if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
@@ -519,10 +630,9 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
}
else if (V.isUndef()) {
os << "Uninitialized value stored to ";
- }
- else if (isa<nonloc::ConcreteInt>(V)) {
- os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
- << " is assigned to ";
+ } else if (Optional<nonloc::ConcreteInt> CV =
+ V.getAs<nonloc::ConcreteInt>()) {
+ os << "The value " << CV->getValue() << " is assigned to ";
}
else
os << "Value assigned to ";
@@ -535,7 +645,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// Construct a new PathDiagnosticPiece.
ProgramPoint P = StoreSite->getLocation();
PathDiagnosticLocation L;
- if (isa<CallEnter>(P))
+ if (P.getAs<CallEnter>() && InitE)
L = PathDiagnosticLocation(InitE, BRC.getSourceManager(),
P.getLocationContext());
else
@@ -558,32 +668,38 @@ const char *TrackConstraintBRVisitor::getTag() {
return "TrackConstraintBRVisitor";
}
+bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
+ if (IsZeroCheck)
+ return N->getState()->isNull(Constraint).isUnderconstrained();
+ return N->getState()->assume(Constraint, !Assumption);
+}
+
PathDiagnosticPiece *
TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) {
- if (isSatisfied)
+ if (IsSatisfied)
return NULL;
// Check if in the previous state it was feasible for this constraint
// to *not* be true.
- if (PrevN->getState()->assume(Constraint, !Assumption)) {
+ if (isUnderconstrained(PrevN)) {
- isSatisfied = true;
+ IsSatisfied = true;
// As a sanity check, make sure that the negation of the constraint
// was infeasible in the current state. If it is feasible, we somehow
// missed the transition point.
- if (N->getState()->assume(Constraint, !Assumption))
+ if (isUnderconstrained(N))
return NULL;
// We found the transition point for the constraint. We now need to
// pretty-print the constraint. (work-in-progress)
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+ SmallString<64> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
- if (isa<Loc>(Constraint)) {
+ if (Constraint.getAs<Loc>()) {
os << "Assuming pointer value is ";
os << (Assumption ? "non-null" : "null");
}
@@ -606,25 +722,151 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
return NULL;
}
-bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
- BugReport &report, bool IsArg) {
+SuppressInlineDefensiveChecksVisitor::
+SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
+ : V(Value), IsSatisfied(false), IsTrackingTurnedOn(false) {
+
+ // Check if the visitor is disabled.
+ SubEngine *Eng = N->getState()->getStateManager().getOwningEngine();
+ assert(Eng && "Cannot file a bug report without an owning engine");
+ AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+ if (!Options.shouldSuppressInlinedDefensiveChecks())
+ IsSatisfied = true;
+
+ assert(N->getState()->isNull(V).isConstrainedTrue() &&
+ "The visitor only tracks the cases where V is constrained to 0");
+}
+
+void SuppressInlineDefensiveChecksVisitor::Profile(FoldingSetNodeID &ID) const {
+ static int id = 0;
+ ID.AddPointer(&id);
+ ID.Add(V);
+}
+
+const char *SuppressInlineDefensiveChecksVisitor::getTag() {
+ return "IDCVisitor";
+}
+
+PathDiagnosticPiece *
+SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ if (IsSatisfied)
+ return 0;
+
+ // 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;
+
+ // Check if in the previous state it was feasible for this value
+ // to *not* be null.
+ if (!Pred->getState()->isNull(V).isConstrainedTrue()) {
+ IsSatisfied = true;
+
+ assert(Succ->getState()->isNull(V).isConstrainedTrue());
+
+ // Check if this is inlined defensive checks.
+ const LocationContext *CurLC =Succ->getLocationContext();
+ const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
+ if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
+ BR.markInvalid("Suppress IDC", CurLC);
+ }
+ return 0;
+}
+
+static const MemRegion *getLocationRegionIfReference(const Expr *E,
+ const ExplodedNode *N) {
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ if (!VD->getType()->isReferenceType())
+ return 0;
+ ProgramStateManager &StateMgr = N->getState()->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ return MRMgr.getVarRegion(VD, N->getLocationContext());
+ }
+ }
+
+ // FIXME: This does not handle other kinds of null references,
+ // for example, references from FieldRegions:
+ // struct Wrapper { int &ref; };
+ // Wrapper w = { *(int *)0 };
+ // w.ref = 1;
+
+ return 0;
+}
+
+static const Expr *peelOffOuterExpr(const Expr *Ex,
+ const ExplodedNode *N) {
+ Ex = Ex->IgnoreParenCasts();
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Ex))
+ return peelOffOuterExpr(EWC->getSubExpr(), N);
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Ex))
+ return peelOffOuterExpr(OVE->getSourceExpr(), N);
+
+ // 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
+ // we took (true/false) by looking at the ExplodedGraph.
+ const ExplodedNode *NI = N;
+ do {
+ ProgramPoint ProgPoint = NI->getLocation();
+ if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
+ const CFGBlock *srcBlk = BE->getSrc();
+ if (const Stmt *term = srcBlk->getTerminator()) {
+ if (term == CO) {
+ bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());
+ if (TookTrueBranch)
+ return peelOffOuterExpr(CO->getTrueExpr(), N);
+ else
+ return peelOffOuterExpr(CO->getFalseExpr(), N);
+ }
+ }
+ }
+ NI = NI->getFirstPred();
+ } while (NI);
+ }
+ return Ex;
+}
+
+bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
+ const Stmt *S,
+ BugReport &report, bool IsArg,
+ bool EnableNullFPSuppression) {
if (!S || !N)
return false;
- if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
- S = OVE->getSourceExpr();
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ Ex = Ex->IgnoreParenCasts();
+ const Expr *PeeledEx = peelOffOuterExpr(Ex, N);
+ if (Ex != PeeledEx)
+ S = PeeledEx;
+ }
+
+ const Expr *Inner = 0;
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ Ex = Ex->IgnoreParenCasts();
+ if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
+ Inner = Ex;
+ }
if (IsArg) {
- assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
+ assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
} else {
// Walk through nodes until we get one that matches the statement exactly.
+ // Alternately, if we hit a known lvalue for the statement, we know we've
+ // gone too far (though we can likely track the lvalue better anyway).
do {
const ProgramPoint &pp = N->getLocation();
- if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
- if (ps->getStmt() == S)
+ if (Optional<StmtPoint> ps = pp.getAs<StmtPoint>()) {
+ if (ps->getStmt() == S || ps->getStmt() == Inner)
break;
- } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
- if (CEE->getCalleeContext()->getCallSite() == S)
+ } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
+ if (CEE->getCalleeContext()->getCallSite() == S ||
+ CEE->getCalleeContext()->getCallSite() == Inner)
break;
}
N = N->getFirstPred();
@@ -636,129 +878,167 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
ProgramStateRef state = N->getState();
- // See if the expression we're interested refers to a variable.
+ // The message send could be nil due to the receiver being nil.
+ // At this point in the path, the receiver should be live since we are at the
+ // message send expr. If it is nil, start tracking it.
+ if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(S, N))
+ trackNullOrUndefValue(N, Receiver, report, IsArg, EnableNullFPSuppression);
+
+
+ // 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 (const Expr *Ex = dyn_cast<Expr>(S)) {
- // Strip off parens and casts. Note that this will never have issues with
- // C++ user-defined implicit conversions, because those have a constructor
- // or function call inside.
- Ex = Ex->IgnoreParenCasts();
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
- // FIXME: Right now we only track VarDecls because it's non-trivial to
- // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- ProgramStateManager &StateMgr = state->getStateManager();
- MemRegionManager &MRMgr = StateMgr.getRegionManager();
- const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());
-
- // Mark both the variable region and its contents as interesting.
- SVal V = state->getRawSVal(loc::MemRegionVal(R));
-
- // If the value matches the default for the variable region, that
- // might mean that it's been cleared out of the state. Fall back to
- // the full argument expression (with casts and such intact).
- if (IsArg) {
- bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
- if (!UseArgValue) {
- const SymbolRegionValue *SRV =
- dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
- if (SRV)
- UseArgValue = (SRV->getRegion() == R);
- }
- if (UseArgValue)
- V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
+ const MemRegion *R = 0;
+
+ // Find the ExplodedNode where the lvalue (the value of 'Ex')
+ // was computed. We need this for getting the location value.
+ const ExplodedNode *LVNode = N;
+ while (LVNode) {
+ if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
+ if (P->getStmt() == Inner)
+ break;
+ }
+ LVNode = LVNode->getFirstPred();
+ }
+ assert(LVNode && "Unable to find the lvalue node.");
+ ProgramStateRef LVState = LVNode->getState();
+ SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext());
+
+ if (LVState->isNull(LVal).isConstrainedTrue()) {
+ // In case of C++ references, we want to differentiate between a null
+ // reference and reference to null pointer.
+ // If the LVal is null, check if we are dealing with null reference.
+ // For those, we want to track the location of the reference.
+ if (const MemRegion *RR = getLocationRegionIfReference(Inner, N))
+ R = RR;
+ } else {
+ R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
+
+ // If this is a C++ reference to a null pointer, we are tracking the
+ // pointer. In additon, we should find the store at which the reference
+ // got initialized.
+ if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) {
+ if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>())
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, RR,
+ EnableNullFPSuppression));
+ }
+ }
+
+ if (R) {
+ // Mark both the variable region and its contents as interesting.
+ SVal V = state->getRawSVal(loc::MemRegionVal(R));
+
+ // If the value matches the default for the variable region, that
+ // might mean that it's been cleared out of the state. Fall back to
+ // the full argument expression (with casts and such intact).
+ if (IsArg) {
+ bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
+ if (!UseArgValue) {
+ const SymbolRegionValue *SRV =
+ dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
+ if (SRV)
+ UseArgValue = (SRV->getRegion() == R);
}
+ if (UseArgValue)
+ V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ }
- report.markInteresting(R);
- report.markInteresting(V);
- report.addVisitor(new UndefOrNullArgVisitor(R));
+ report.markInteresting(R);
+ report.markInteresting(V);
+ report.addVisitor(new UndefOrNullArgVisitor(R));
- // If the contents are symbolic, find out when they became null.
- if (V.getAsLocSymbol()) {
- BugReporterVisitor *ConstraintTracker
- = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false);
- report.addVisitor(ConstraintTracker);
- }
+ if (isa<SymbolicRegion>(R)) {
+ TrackConstraintBRVisitor *VI =
+ new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
+ report.addVisitor(VI);
+ }
- report.addVisitor(new FindLastStoreBRVisitor(V, R));
- return true;
+ // If the contents are symbolic, find out when they became null.
+ if (V.getAsLocSymbol()) {
+ BugReporterVisitor *ConstraintTracker =
+ new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
+ report.addVisitor(ConstraintTracker);
+
+ // Add visitor, which will suppress inline defensive checks.
+ if (N->getState()->isNull(V).isConstrainedTrue() &&
+ EnableNullFPSuppression) {
+ BugReporterVisitor *IDCSuppressor =
+ new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
+ N);
+ report.addVisitor(IDCSuppressor);
+ }
}
+
+ if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, R,
+ EnableNullFPSuppression));
+ return true;
}
}
- // If the expression does NOT refer to a variable, we can still track
- // constraints on its contents.
+ // If the expression is not an "lvalue expression", we can still
+ // track the constraints on its contents.
SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ // If the value came from an inlined function call, we should at least make
+ // sure that function isn't pruned in our output.
+ if (const Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParenCasts();
+
+ ReturnVisitor::addVisitorIfNecessary(N, S, report, EnableNullFPSuppression);
+
// Uncomment this to find cases where we aren't properly getting the
// base value that was dereferenced.
// assert(!V.isUnknownOrUndef());
-
// Is it a symbolic value?
- if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
+ if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) {
// At this point we are dealing with the region's LValue.
// However, if the rvalue is a symbolic region, we should track it as well.
SVal RVal = state->getSVal(L->getRegion());
const MemRegion *RegionRVal = RVal.getAsRegion();
report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));
-
if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
report.markInteresting(RegionRVal);
report.addVisitor(new TrackConstraintBRVisitor(
loc::MemRegionVal(RegionRVal), false));
}
- } else {
- // Otherwise, if the value came from an inlined function call,
- // we should at least make sure that function isn't pruned in our output.
- if (const Expr *E = dyn_cast<Expr>(S))
- S = E->IgnoreParenCasts();
- ReturnVisitor::addVisitorIfNecessary(N, S, report);
}
return true;
}
-BugReporterVisitor *
-FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N,
- const MemRegion *R) {
- assert(R && "The memory region is null.");
-
- ProgramStateRef state = N->getState();
- SVal V = state->getSVal(R);
- if (V.isUnknown())
+const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
+ const ExplodedNode *N) {
+ const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
+ if (!ME)
return 0;
-
- return new FindLastStoreBRVisitor(V, R);
+ 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;
}
-
PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) {
- const PostStmt *P = N->getLocationAs<PostStmt>();
+ Optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
return 0;
- const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
- if (!ME)
- return 0;
- const Expr *Receiver = ME->getInstanceReceiver();
+
+ const Expr *Receiver = getNilReceiver(P->getStmt(), N);
if (!Receiver)
return 0;
- ProgramStateRef state = N->getState();
- const SVal &V = state->getSVal(Receiver, N->getLocationContext());
- const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
- if (!DV)
- return 0;
- state = state->assume(*DV, true);
- if (state)
- return 0;
// The receiver was nil, and hence the method was skipped.
// Register a BugReporterVisitor to issue a message telling us how
// the receiver was null.
- bugreporter::trackNullOrUndefValue(N, Receiver, BR);
+ bugreporter::trackNullOrUndefValue(N, Receiver, BR, /*IsArg*/ false,
+ /*EnableNullFPSuppression*/ false);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
@@ -768,7 +1048,8 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
// Registers every VarDecl inside a Stmt with a last store visitor.
void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
- const Stmt *S) {
+ const Stmt *S,
+ bool EnableNullFPSuppression) {
const ExplodedNode *N = BR.getErrorNode();
std::deque<const Stmt *> WorkList;
WorkList.push_back(S);
@@ -788,9 +1069,10 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
// What did we load?
SVal V = state->getSVal(S, N->getLocationContext());
- if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
+ if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
// Register a new visitor with the BugReport.
- BR.addVisitor(new FindLastStoreBRVisitor(V, R));
+ BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R,
+ EnableNullFPSuppression));
}
}
}
@@ -842,14 +1124,14 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) {
+ 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;
}
- if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) {
+ if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) {
// FIXME: Assuming that BugReporter is a GRBugReporter is a layering
// violation.
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
@@ -929,11 +1211,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
}
}
-bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out,
+bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
BugReporterContext &BRC,
BugReport &report,
const ExplodedNode *N,
- llvm::Optional<bool> &prunable) {
+ Optional<bool> &prunable) {
const Expr *OriginalExpr = Ex;
Ex = Ex->IgnoreParenCasts();
@@ -992,7 +1274,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const ExplodedNode *N) {
bool shouldInvert = false;
- llvm::Optional<bool> shouldPrune;
+ Optional<bool> shouldPrune;
SmallString<128> LhsString, RhsString;
{
@@ -1161,6 +1443,58 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
return event;
}
+
+// FIXME: Copied from ExprEngineCallAndReturn.cpp.
+static bool isInStdNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND)
+ return false;
+
+ while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent()))
+ ND = Parent;
+
+ return ND->getName() == "std";
+}
+
+
+PathDiagnosticPiece *
+LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ // Here we suppress false positives coming from system headers. This list is
+ // based on known issues.
+
+ // Skip reports within the 'std' namespace. Although these can sometimes be
+ // the user's fault, we currently don't report them very well, and
+ // Note that this will not help for any other data structure libraries, like
+ // TR1, Boost, or llvm/ADT.
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ if (Options.shouldSuppressFromCXXStandardLibrary()) {
+ const LocationContext *LCtx = N->getLocationContext();
+ if (isInStdNamespace(LCtx->getDecl())) {
+ BR.markInvalid(getTag(), 0);
+ return 0;
+ }
+ }
+
+ // Skip reports within the sys/queue.h macros as we do not have the ability to
+ // reason about data structure shapes.
+ SourceManager &SM = BRC.getSourceManager();
+ FullSourceLoc Loc = BR.getLocation(SM).asLocation();
+ while (Loc.isMacroID()) {
+ if (SM.isInSystemMacro(Loc) &&
+ (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h"))) {
+ BR.markInvalid(getTag(), 0);
+ return 0;
+ }
+ Loc = Loc.getSpellingLoc();
+ }
+
+ return 0;
+}
+
PathDiagnosticPiece *
UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
@@ -1171,7 +1505,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
ProgramPoint ProgLoc = N->getLocation();
// We are only interested in visiting CallEnter nodes.
- CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc);
+ Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
if (!CEnter)
return 0;
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index c5cb317bd18d..45b2e219d9e3 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -14,11 +14,12 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -124,7 +125,7 @@ static bool isPointerToConst(QualType Ty) {
// Try to retrieve the function declaration and find the function parameter
// types which are pointers/references to a non-pointer const.
// We will not invalidate the corresponding argument regions.
-static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs,
const CallEvent &Call) {
unsigned Idx = 0;
for (CallEvent::param_type_iterator I = Call.param_type_begin(),
@@ -136,69 +137,35 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
}
ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
- ProgramStateRef Orig) const {
+ ProgramStateRef Orig) const {
ProgramStateRef Result = (Orig ? Orig : getState());
- SmallVector<const MemRegion *, 8> RegionsToInvalidate;
- getExtraInvalidatedRegions(RegionsToInvalidate);
+ SmallVector<SVal, 8> ConstValues;
+ SmallVector<SVal, 8> ValuesToInvalidate;
+
+ getExtraInvalidatedValues(ValuesToInvalidate);
// Indexes of arguments whose values will be preserved by the call.
- llvm::SmallSet<unsigned, 1> PreserveArgs;
+ llvm::SmallSet<unsigned, 4> PreserveArgs;
if (!argumentsMayEscape())
findPtrToConstParams(PreserveArgs, *this);
for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
if (PreserveArgs.count(Idx))
- continue;
-
- SVal V = getArgSVal(Idx);
-
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
- V = Wrapped->getLoc();
- else if (!isa<Loc>(V))
- continue;
-
- if (const MemRegion *R = V.getAsRegion()) {
- // Invalidate the value of the variable passed by reference.
-
- // Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underlying region
- // is a variable region then strip off the ElementRegion.
- // FIXME: We really need to think about this for the general case
- // as sometimes we are reasoning about arrays and other times
- // about (char*), etc., is just a form of passing raw bytes.
- // e.g., void *p = alloca(); foo((char*)p);
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Checking for 'integral type' is probably too promiscuous, but
- // we'll leave it in for now until we have a systematic way of
- // handling all of these cases. Eventually we need to come up
- // with an interface to StoreManager so that this logic can be
- // appropriately delegated to the respective StoreManagers while
- // still allowing us to do checker-specific logic (e.g.,
- // invalidating reference counts), probably via callbacks.
- if (ER->getElementType()->isIntegralOrEnumerationType()) {
- const MemRegion *superReg = ER->getSuperRegion();
- if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
- isa<ObjCIvarRegion>(superReg))
- R = cast<TypedRegion>(superReg);
- }
- // FIXME: What about layers of ElementRegions?
- }
-
- // Mark this region for invalidation. We batch invalidate regions
- // below for efficiency.
- RegionsToInvalidate.push_back(R);
- }
+ ConstValues.push_back(getArgSVal(Idx));
+ else
+ ValuesToInvalidate.push_back(getArgSVal(Idx));
}
// Invalidate designated regions using the batch invalidation API.
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
// global variables.
- return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
+ return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
BlockCount, getLocationContext(),
- /*Symbols=*/0, this);
+ /*CausedByPointerEscape*/ true,
+ /*Symbols=*/0, this, ConstValues);
}
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
@@ -268,7 +235,6 @@ bool CallEvent::isCallStmt(const Stmt *S) {
|| isa<CXXNewExpr>(S);
}
-/// \brief Returns the result type, adjusted for references.
QualType CallEvent::getDeclaredResultType(const Decl *D) {
assert(D);
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
@@ -405,9 +371,8 @@ const FunctionDecl *CXXInstanceCall::getDecl() const {
return getSVal(CE->getCallee()).getAsFunctionDecl();
}
-void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const {
- if (const MemRegion *R = getCXXThisVal().getAsRegion())
- Regions.push_back(R);
+void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values) const {
+ Values.push_back(getCXXThisVal());
}
SVal CXXInstanceCall::getCXXThisVal() const {
@@ -417,7 +382,7 @@ SVal CXXInstanceCall::getCXXThisVal() const {
return UnknownVal();
SVal ThisVal = getSVal(Base);
- assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
+ assert(ThisVal.isUnknownOrUndef() || ThisVal.getAs<Loc>());
return ThisVal;
}
@@ -560,10 +525,10 @@ CallEvent::param_iterator BlockCall::param_end() const {
return D->param_end();
}
-void BlockCall::getExtraInvalidatedRegions(RegionList &Regions) const {
+void BlockCall::getExtraInvalidatedValues(ValueList &Values) const {
// FIXME: This also needs to invalidate captured globals.
if (const MemRegion *R = getBlockRegion())
- Regions.push_back(R);
+ Values.push_back(loc::MemRegionVal(R));
}
void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -581,9 +546,9 @@ SVal CXXConstructorCall::getCXXThisVal() const {
return UnknownVal();
}
-void CXXConstructorCall::getExtraInvalidatedRegions(RegionList &Regions) const {
+void CXXConstructorCall::getExtraInvalidatedValues(ValueList &Values) const {
if (Data)
- Regions.push_back(static_cast<const MemRegion *>(Data));
+ Values.push_back(loc::MemRegionVal(static_cast<const MemRegion *>(Data)));
}
void CXXConstructorCall::getInitialStackFrameContents(
@@ -635,9 +600,8 @@ CallEvent::param_iterator ObjCMethodCall::param_end() const {
}
void
-ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const {
- if (const MemRegion *R = getReceiverSVal().getAsRegion())
- Regions.push_back(R);
+ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values) const {
+ Values.push_back(getReceiverSVal());
}
SVal ObjCMethodCall::getSelfSVal() const {
@@ -834,7 +798,34 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
// Lookup the method implementation.
if (ReceiverT)
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) {
- const ObjCMethodDecl *MD = IDecl->lookupPrivateMethod(Sel);
+ // Repeatedly calling lookupPrivateMethod() is expensive, especially
+ // when in many cases it returns null. We cache the results so
+ // that repeated queries on the same ObjCIntefaceDecl and Selector
+ // don't incur the same cost. On some test cases, we can see the
+ // same query being issued thousands of times.
+ //
+ // NOTE: This cache is essentially a "global" variable, but it
+ // only gets lazily created when we get here. The value of the
+ // cache probably comes from it being global across ExprEngines,
+ // where the same queries may get issued. If we are worried about
+ // concurrency, or possibly loading/unloading ASTs, etc., we may
+ // need to revisit this someday. In terms of memory, this table
+ // stays around until clang quits, which also may be bad if we
+ // need to release memory.
+ typedef std::pair<const ObjCInterfaceDecl*, Selector>
+ PrivateMethodKey;
+ typedef llvm::DenseMap<PrivateMethodKey,
+ Optional<const ObjCMethodDecl *> >
+ PrivateMethodCache;
+
+ static PrivateMethodCache PMC;
+ Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)];
+
+ // Query lookupPrivateMethod() if the cache does not hit.
+ if (!Val.hasValue())
+ Val = IDecl->lookupPrivateMethod(Sel);
+
+ const ObjCMethodDecl *MD = Val.getValue();
if (CanBeSubClassed)
return RuntimeDefinition(MD, Receiver);
else
@@ -931,8 +922,9 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
// destructors, though this could change in the future.
const CFGBlock *B = CalleeCtx->getCallSiteBlock();
CFGElement E = (*B)[CalleeCtx->getIndex()];
- assert(isa<CFGImplicitDtor>(E) && "All other CFG elements should have exprs");
- assert(!isa<CFGTemporaryDtor>(E) && "We don't handle temporaries yet");
+ assert(E.getAs<CFGImplicitDtor>() &&
+ "All other CFG elements should have exprs");
+ assert(!E.getAs<CFGTemporaryDtor>() && "We don't handle temporaries yet");
SValBuilder &SVB = State->getStateManager().getSValBuilder();
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl());
@@ -940,11 +932,12 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
SVal ThisVal = State->getSVal(ThisPtr);
const Stmt *Trigger;
- if (const CFGAutomaticObjDtor *AutoDtor = dyn_cast<CFGAutomaticObjDtor>(&E))
+ if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>())
Trigger = AutoDtor->getTriggerStmt();
else
Trigger = Dtor->getBody();
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
- isa<CFGBaseDtor>(E), State, CallerCtx);
+ E.getAs<CFGBaseDtor>().hasValue(), State,
+ CallerCtx);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 3672952b8f6e..8adf3262b379 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/Analysis/ProgramPoint.h"
-#include "clang/AST/DeclBase.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
@@ -30,7 +30,7 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
!LocationCheckers.empty() ||
!BindCheckers.empty() ||
!EndAnalysisCheckers.empty() ||
- !EndPathCheckers.empty() ||
+ !EndFunctionCheckers.empty() ||
!BranchConditionCheckers.empty() ||
!LiveSymbolsCheckers.empty() ||
!DeadSymbolsCheckers.empty() ||
@@ -353,17 +353,17 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
/// \brief Run checkers for end of path.
// Note, We do not chain the checker output (like in expandGraphWithCheckers)
// for this callback since end of path nodes are expected to be final.
-void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred,
- ExprEngine &Eng) {
+void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
+ ExprEngine &Eng) {
// We define the builder outside of the loop bacause if at least one checkers
// creates a sucsessor for Pred, we do not need to generate an
// autotransition for it.
NodeBuilder Bldr(Pred, Dst, BC);
- for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
- CheckEndPathFunc checkFn = EndPathCheckers[i];
+ for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e; ++i) {
+ CheckEndFunctionFunc checkFn = EndFunctionCheckers[i];
const ProgramPoint &L = BlockEntrance(BC.Block,
Pred->getLocationContext(),
@@ -469,10 +469,10 @@ bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) {
/// \brief Run checkers for region changes.
ProgramStateRef
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) {
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
@@ -484,6 +484,27 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
return state;
}
+/// \brief Run checkers to process symbol escape event.
+ProgramStateRef
+CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst) {
+ assert((Call != NULL ||
+ (Kind != PSK_DirectEscapeOnCall &&
+ Kind != PSK_IndirectEscapeOnCall)) &&
+ "Call must not be NULL when escaping on call");
+ for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) {
+ // If any checker declares the state infeasible (or if it starts that
+ // way), bail out.
+ if (!State)
+ return NULL;
+ State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, IsConst);
+ }
+ return State;
+}
+
/// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef
CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
@@ -618,8 +639,8 @@ void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
EndAnalysisCheckers.push_back(checkfn);
}
-void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
- EndPathCheckers.push_back(checkfn);
+void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) {
+ EndFunctionCheckers.push_back(checkfn);
}
void CheckerManager::_registerForBranchCondition(
@@ -641,6 +662,15 @@ void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
RegionChangesCheckers.push_back(info);
}
+void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){
+ PointerEscapeCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForConstPointerEscape(
+ CheckPointerEscapeFunc checkfn) {
+ PointerEscapeCheckers.push_back(checkfn);
+}
+
void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
EvalAssumeCheckers.push_back(checkfn);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
index 9791e2ecbf92..47299030cc45 100644
--- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
@@ -10,6 +10,7 @@
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -109,7 +110,7 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
}
}
-void CheckerRegistry::printHelp(llvm::raw_ostream &out,
+void CheckerRegistry::printHelp(raw_ostream &out,
size_t maxNameChars) const {
// FIXME: Alphabetical sort puts 'experimental' in the middle.
// Would it be better to name it '~experimental' or something else
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index ec2379212dc6..b09b2c2ddfab 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -14,14 +14,14 @@
#define DEBUG_TYPE "CoreEngine"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtCXX.h"
-#include "llvm/Support/Casting.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Casting.h"
using namespace clang;
using namespace ento;
@@ -114,7 +114,7 @@ namespace {
}
virtual void enqueue(const WorkListUnit& U) {
- if (isa<BlockEntrance>(U.getNode()->getLocation()))
+ if (U.getNode()->getLocation().getAs<BlockEntrance>())
Queue.push_front(U);
else
Stack.push_back(U);
@@ -230,11 +230,11 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
// Dispatch on the location type.
switch (Loc.getKind()) {
case ProgramPoint::BlockEdgeKind:
- HandleBlockEdge(cast<BlockEdge>(Loc), Pred);
+ HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
break;
case ProgramPoint::BlockEntranceKind:
- HandleBlockEntrance(cast<BlockEntrance>(Loc), Pred);
+ HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
break;
case ProgramPoint::BlockExitKind:
@@ -242,7 +242,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
break;
case ProgramPoint::CallEnterKind: {
- CallEnter CEnter = cast<CallEnter>(Loc);
+ CallEnter CEnter = Loc.castAs<CallEnter>();
SubEng.processCallEnter(CEnter, Pred);
break;
}
@@ -259,10 +259,10 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
break;
}
default:
- assert(isa<PostStmt>(Loc) ||
- isa<PostInitializer>(Loc) ||
- isa<PostImplicitCall>(Loc) ||
- isa<CallExitEnd>(Loc));
+ assert(Loc.getAs<PostStmt>() ||
+ Loc.getAs<PostInitializer>() ||
+ Loc.getAs<PostImplicitCall>() ||
+ Loc.getAs<CallExitEnd>());
HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
break;
}
@@ -331,9 +331,9 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
WList->setBlockCounter(Counter);
// Process the entrance of the block.
- if (CFGElement E = L.getFirstElement()) {
+ if (Optional<CFGElement> E = L.getFirstElement()) {
NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
- SubEng.processCFGElement(E, Pred, 0, &Ctx);
+ SubEng.processCFGElement(*E, Pred, 0, &Ctx);
}
else
HandleBlockExit(L.getBlock(), Pred);
@@ -346,6 +346,11 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
default:
llvm_unreachable("Analysis for this terminator not implemented.");
+ // Model static initializers.
+ case Stmt::DeclStmtClass:
+ HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
+ return;
+
case Stmt::BinaryOperatorClass: // '&&' and '||'
HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
return;
@@ -456,6 +461,19 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
enqueue(Dst);
}
+
+void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
+ ExplodedNode *Pred) {
+ assert(B->succ_size() == 2);
+ NodeBuilderContext Ctx(*this, B, Pred);
+ ExplodedNodeSet Dst;
+ SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
+ *(B->succ_begin()), *(B->succ_begin()+1));
+ // Enqueue the new frontier onto the worklist.
+ enqueue(Dst);
+}
+
+
void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
ExplodedNode *Pred) {
assert(B);
@@ -495,7 +513,7 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
assert (!N->isSink());
// Check if this node entered a callee.
- if (isa<CallEnter>(N->getLocation())) {
+ if (N->getLocation().getAs<CallEnter>()) {
// Still use the index of the CallExpr. It's needed to create the callee
// StackFrameContext.
WList->enqueue(N, Block, Idx);
@@ -503,19 +521,19 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
}
// Do not create extra nodes. Move to the next CFG element.
- if (isa<PostInitializer>(N->getLocation()) ||
- isa<PostImplicitCall>(N->getLocation())) {
+ if (N->getLocation().getAs<PostInitializer>() ||
+ N->getLocation().getAs<PostImplicitCall>()) {
WList->enqueue(N, Block, Idx+1);
return;
}
- if (isa<EpsilonPoint>(N->getLocation())) {
+ if (N->getLocation().getAs<EpsilonPoint>()) {
WList->enqueue(N, Block, Idx);
return;
}
// At this point, we know we're processing a normal statement.
- CFGStmt CS = cast<CFGStmt>((*Block)[Idx]);
+ CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
PostStmt Loc(CS.getStmt(), N->getLocationContext());
if (Loc == N->getLocation()) {
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index bab89c545c34..fe352aa8b4cf 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -16,6 +16,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -36,9 +37,6 @@ static const Expr *ignoreTransparentExprs(const Expr *E) {
case Stmt::SubstNonTypeTemplateParmExprClass:
E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
break;
- case Stmt::CXXDefaultArgExprClass:
- E = cast<CXXDefaultArgExpr>(E)->getExpr();
- break;
default:
// This is the base case: we can't look through more than we already have.
return E;
@@ -74,7 +72,6 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
switch (S->getStmtClass()) {
case Stmt::CXXBindTemporaryExprClass:
- case Stmt::CXXDefaultArgExprClass:
case Stmt::ExprWithCleanupsClass:
case Stmt::GenericSelectionExprClass:
case Stmt::OpaqueValueExprClass:
@@ -149,19 +146,6 @@ Environment EnvironmentManager::bindExpr(Environment Env,
return Environment(F.add(Env.ExprBindings, E, V));
}
-EnvironmentEntry EnvironmentEntry::makeLocation() const {
- EnvironmentEntry Result = *this;
- reinterpret_cast<uintptr_t &>(Result.first) |= 0x1;
- return Result;
-}
-
-Environment EnvironmentManager::bindExprAndLocation(Environment Env,
- const EnvironmentEntry &E,
- SVal location, SVal V) {
- return Environment(F.add(F.add(Env.ExprBindings, E.makeLocation(), location),
- E, V));
-}
-
namespace {
class MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
@@ -178,14 +162,6 @@ public:
};
} // end anonymous namespace
-// In addition to mapping from EnvironmentEntry - > SVals in the Environment,
-// we also maintain a mapping from EnvironmentEntry -> SVals (locations)
-// that were used during a load and store.
-static inline bool IsLocation(const EnvironmentEntry &E) {
- const Stmt *S = E.getStmt();
- return (bool) (((uintptr_t) S) & 0x1);
-}
-
// removeDeadBindings:
// - Remove subexpression bindings.
// - Remove dead block expression bindings.
@@ -202,8 +178,6 @@ EnvironmentManager::removeDeadBindings(Environment Env,
// individually removing all the subexpression bindings (which will greatly
// outnumber block-level expression bindings).
Environment NewEnv = getInitialEnvironment();
-
- SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations;
MarkLiveCallback CB(SymReaper);
ScanReachableSymbols RSScaner(ST, CB);
@@ -217,15 +191,6 @@ EnvironmentManager::removeDeadBindings(Environment Env,
I != E; ++I) {
const EnvironmentEntry &BlkExpr = I.getKey();
- // For recorded locations (used when evaluating loads and stores), we
- // consider them live only when their associated normal expression is
- // also live.
- // NOTE: This assumes that loads/stores that evaluated to UnknownVal
- // still have an entry in the map.
- if (IsLocation(BlkExpr)) {
- deferredLocations.push_back(std::make_pair(BlkExpr, I.getData()));
- continue;
- }
const SVal &X = I.getData();
if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
@@ -233,26 +198,18 @@ EnvironmentManager::removeDeadBindings(Environment Env,
EBMapRef = EBMapRef.add(BlkExpr, X);
// If the block expr's value is a memory region, then mark that region.
- if (isa<loc::MemRegionVal>(X)) {
- const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion();
- SymReaper.markLive(R);
- }
+ if (Optional<loc::MemRegionVal> R = X.getAs<loc::MemRegionVal>())
+ SymReaper.markLive(R->getRegion());
// Mark all symbols in the block expr's value live.
RSScaner.scan(X);
continue;
+ } else {
+ SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+ for (; SI != SE; ++SI)
+ SymReaper.maybeDead(*SI);
}
}
-
- // Go through he deferred locations and add them to the new environment if
- // the correspond Stmt* is in the map as well.
- for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator
- I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) {
- const EnvironmentEntry &En = I->first;
- const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1);
- if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext())))
- EBMapRef = EBMapRef.add(En, I->second);
- }
NewEnv.ExprBindings = EBMapRef.asImmutableMap();
return NewEnv;
@@ -260,30 +217,14 @@ EnvironmentManager::removeDeadBindings(Environment Env,
void Environment::print(raw_ostream &Out, const char *NL,
const char *Sep) const {
- printAux(Out, false, NL, Sep);
- printAux(Out, true, NL, Sep);
-}
-
-void Environment::printAux(raw_ostream &Out, bool printLocations,
- const char *NL,
- const char *Sep) const{
-
bool isFirst = true;
for (Environment::iterator I = begin(), E = end(); I != E; ++I) {
const EnvironmentEntry &En = I.getKey();
- if (IsLocation(En)) {
- if (!printLocations)
- continue;
- }
- else {
- if (printLocations)
- continue;
- }
if (isFirst) {
Out << NL << NL
- << (printLocations ? "Load/Store locations:" : "Expressions:")
+ << "Expressions:"
<< NL;
isFirst = false;
} else {
@@ -291,9 +232,6 @@ void Environment::printAux(raw_ostream &Out, bool printLocations,
}
const Stmt *S = En.getStmt();
- if (printLocations) {
- S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1));
- }
Out << " (" << (const void*) En.getLocationContext() << ','
<< (const void*) S << ") ";
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index c284bd7dfad4..af9518acc79d 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/Stmt.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/ParentMap.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include <vector>
@@ -56,19 +56,42 @@ ExplodedGraph::~ExplodedGraph() {}
// Node reclamation.
//===----------------------------------------------------------------------===//
+bool ExplodedGraph::isInterestingLValueExpr(const Expr *Ex) {
+ if (!Ex->isLValue())
+ return false;
+ return isa<DeclRefExpr>(Ex) ||
+ isa<MemberExpr>(Ex) ||
+ isa<ObjCIvarRefExpr>(Ex);
+}
+
bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
- // Reclaim all nodes that match *all* the following criteria:
+ // First, we only consider nodes for reclamation of the following
+ // conditions apply:
//
// (1) 1 predecessor (that has one successor)
// (2) 1 successor (that has one predecessor)
+ //
+ // If a node has no successor it is on the "frontier", while a node
+ // with no predecessor is a root.
+ //
+ // After these prerequisites, we discard all "filler" nodes that
+ // are used only for intermediate processing, and are not essential
+ // for analyzer history:
+ //
+ // (a) PreStmtPurgeDeadSymbols
+ //
+ // We then discard all other nodes where *all* of the following conditions
+ // apply:
+ //
// (3) The ProgramPoint is for a PostStmt, but not a PostStore.
// (4) There is no 'tag' for the ProgramPoint.
// (5) The 'store' is the same as the predecessor.
// (6) The 'GDM' is the same as the predecessor.
// (7) The LocationContext is the same as the predecessor.
- // (8) The PostStmt isn't for a non-consumed Stmt or Expr.
- // (9) The successor is not a CallExpr StmtPoint (so that we would be able to
- // find it when retrying a call with no inlining).
+ // (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).
// FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
// Conditions 1 and 2.
@@ -83,14 +106,18 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
if (succ->pred_size() != 1)
return false;
- // Condition 3.
+ // Now reclaim any nodes that are (by definition) not essential to
+ // analysis history and are not consulted by any client code.
ProgramPoint progPoint = node->getLocation();
- if (!isa<PostStmt>(progPoint) || isa<PostStore>(progPoint))
+ if (progPoint.getAs<PreStmtPurgeDeadSymbols>())
+ return !progPoint.getTag();
+
+ // Condition 3.
+ if (!progPoint.getAs<PostStmt>() || progPoint.getAs<PostStore>())
return false;
// Condition 4.
- PostStmt ps = cast<PostStmt>(progPoint);
- if (ps.getTag())
+ if (progPoint.getTag())
return false;
// Conditions 5, 6, and 7.
@@ -99,23 +126,30 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
progPoint.getLocationContext() != pred->getLocationContext())
return false;
-
+
+ // All further checks require expressions. As per #3, we know that we have
+ // a PostStmt.
+ const Expr *Ex = dyn_cast<Expr>(progPoint.castAs<PostStmt>().getStmt());
+ if (!Ex)
+ return false;
+
// Condition 8.
+ // Do not collect nodes for "interesting" lvalue expressions since they are
+ // used extensively for generating path diagnostics.
+ if (isInterestingLValueExpr(Ex))
+ return false;
+
+ // Condition 9.
// Do not collect nodes for non-consumed Stmt or Expr to ensure precise
// diagnostic generation; specifically, so that we could anchor arrows
// pointing to the beginning of statements (as written in code).
- if (!isa<Expr>(ps.getStmt()))
+ ParentMap &PM = progPoint.getLocationContext()->getParentMap();
+ if (!PM.isConsumedExpr(Ex))
return false;
-
- if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) {
- ParentMap &PM = progPoint.getLocationContext()->getParentMap();
- if (!PM.isConsumedExpr(Ex))
- return false;
- }
-
- // Condition 9.
+
+ // Condition 10.
const ProgramPoint SuccLoc = succ->getLocation();
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&SuccLoc))
+ if (Optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>())
if (CallEvent::isCallStmt(SP->getStmt()))
return false;
@@ -297,45 +331,31 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
return V;
}
-std::pair<ExplodedGraph*, InterExplodedGraphMap*>
-ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
- llvm::DenseMap<const void*, const void*> *InverseMap) const {
-
- if (NBeg == NEnd)
- return std::make_pair((ExplodedGraph*) 0,
- (InterExplodedGraphMap*) 0);
+ExplodedGraph *
+ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
+ InterExplodedGraphMap *ForwardMap,
+ InterExplodedGraphMap *InverseMap) const{
- assert (NBeg < NEnd);
-
- OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
-
- ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
-
- return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
-}
-
-ExplodedGraph*
-ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
- const ExplodedNode* const* EndSources,
- InterExplodedGraphMap* M,
- llvm::DenseMap<const void*, const void*> *InverseMap) const {
+ if (Nodes.empty())
+ return 0;
typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
Pass1Ty Pass1;
- typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
- Pass2Ty& Pass2 = M->M;
+ typedef InterExplodedGraphMap Pass2Ty;
+ InterExplodedGraphMap Pass2Scratch;
+ Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch;
SmallVector<const ExplodedNode*, 10> WL1, WL2;
// ===- Pass 1 (reverse DFS) -===
- for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
+ for (ArrayRef<const NodeTy *>::iterator I = Sinks.begin(), E = Sinks.end();
+ I != E; ++I) {
if (*I)
WL1.push_back(*I);
}
- // Process the first worklist until it is empty. Because it is a std::list
- // it acts like a FIFO queue.
+ // Process the first worklist until it is empty.
while (!WL1.empty()) {
const ExplodedNode *N = WL1.back();
WL1.pop_back();
@@ -398,7 +418,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
if (PI == Pass2.end())
continue;
- NewN->addPredecessor(PI->second, *G);
+ NewN->addPredecessor(const_cast<ExplodedNode *>(PI->second), *G);
}
// In the case that some of the intended successors of NewN have already
@@ -409,7 +429,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI != Pass2.end()) {
- PI->second->addPredecessor(NewN, *G);
+ const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G);
continue;
}
@@ -422,13 +442,3 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
return G;
}
-void InterExplodedGraphMap::anchor() { }
-
-ExplodedNode*
-InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const {
- llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
- M.find(N);
-
- return I == M.end() ? 0 : I->second;
-}
-
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 045591c9074b..ab4dbd752519 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -15,21 +15,21 @@
#define DEBUG_TYPE "ExprEngine"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
@@ -56,7 +56,8 @@ STATISTIC(NumTimesRetriedWithoutInlining,
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
SetOfConstDecls *VisitedCalleesIn,
- FunctionSummariesTy *FS)
+ FunctionSummariesTy *FS,
+ InliningModes HowToInlineIn)
: AMgr(mgr),
AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
Engine(*this, FS),
@@ -66,11 +67,11 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
- EntryNode(NULL),
- currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
+ currStmtIdx(0), currBldrCtx(0),
ObjCNoRet(mgr.getASTContext()),
ObjCGCEnabled(gcEnabled), BR(mgr, *this),
- VisitedCallees(VisitedCalleesIn)
+ VisitedCallees(VisitedCalleesIn),
+ HowToInline(HowToInlineIn)
{
unsigned TrimInterval = mgr.options.getGraphTrimInterval();
if (TrimInterval != 0) {
@@ -117,8 +118,8 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
svalBuilder.makeZeroVal(T),
getContext().IntTy);
- DefinedOrUnknownSVal *Constraint =
- dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
+ Optional<DefinedOrUnknownSVal> Constraint =
+ Constraint_untested.getAs<DefinedOrUnknownSVal>();
if (!Constraint)
break;
@@ -137,7 +138,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ if (Optional<Loc> LV = V.getAs<Loc>()) {
// Assume that the pointer value in 'self' is non-null.
state = state->assume(*LV, true);
assert(state && "'self' cannot be null");
@@ -153,7 +154,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
if (SFC->getParent() == 0) {
loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC);
SVal V = state->getSVal(L);
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ if (Optional<Loc> LV = V.getAs<Loc>()) {
state = state->assume(*LV, true);
assert(state && "'this' cannot be null");
}
@@ -164,20 +165,63 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
return state;
}
-/// If the value of the given expression is a NonLoc, copy it into a new
-/// temporary region, and replace the value of the expression with that.
-static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
- const LocationContext *LC,
- const Expr *E) {
- SVal V = State->getSVal(E, LC);
-
- if (isa<NonLoc>(V)) {
- MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
- const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC);
- State = State->bindLoc(loc::MemRegionVal(R), V);
- State = State->BindExpr(E, LC, loc::MemRegionVal(R));
+ProgramStateRef
+ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
+ const LocationContext *LC,
+ const Expr *Ex,
+ const Expr *Result) {
+ SVal V = State->getSVal(Ex, LC);
+ if (!Result) {
+ // If we don't have an explicit result expression, we're in "if needed"
+ // mode. Only create a region if the current value is a NonLoc.
+ if (!V.getAs<NonLoc>())
+ return State;
+ Result = Ex;
+ } else {
+ // We need to create a region no matter what. For sanity, make sure we don't
+ // try to stuff a Loc into a non-pointer temporary region.
+ assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()));
}
+ ProgramStateManager &StateMgr = State->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ StoreManager &StoreMgr = StateMgr.getStoreManager();
+
+ // We need to be careful about treating a derived type's value as
+ // bindings for a base type. Unless we're creating a temporary pointer region,
+ // start by stripping and recording base casts.
+ SmallVector<const CastExpr *, 4> Casts;
+ const Expr *Inner = Ex->IgnoreParens();
+ if (!Loc::isLocType(Result->getType())) {
+ while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) {
+ if (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase)
+ Casts.push_back(CE);
+ else if (CE->getCastKind() != CK_NoOp)
+ break;
+
+ Inner = CE->getSubExpr()->IgnoreParens();
+ }
+ }
+
+ // 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 = MRMgr.getCXXTempObjectRegion(Inner, LC);
+ SVal Reg = loc::MemRegionVal(TR);
+
+ if (V.isUnknown())
+ V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(),
+ currBldrCtx->blockCount());
+ State = State->bindLoc(Reg, V);
+
+ // Re-apply the casts (from innermost to outermost) for type sanity.
+ for (SmallVectorImpl<const CastExpr *>::reverse_iterator I = Casts.rbegin(),
+ E = Casts.rend();
+ I != E; ++I) {
+ Reg = StoreMgr.evalDerivedToBase(Reg, *I);
+ }
+
+ State = State->BindExpr(Result, LC, Reg);
return State;
}
@@ -198,7 +242,7 @@ bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) {
ProgramStateRef
ExprEngine::processRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) {
@@ -221,19 +265,17 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
currBldrCtx = Ctx;
switch (E.getKind()) {
- case CFGElement::Invalid:
- llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
- ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred);
+ ProcessStmt(const_cast<Stmt*>(E.castAs<CFGStmt>().getStmt()), Pred);
return;
case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred);
+ ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
- ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
+ ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
}
currBldrCtx = 0;
@@ -249,7 +291,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
return false;
// Is this the beginning of a basic block?
- if (isa<BlockEntrance>(Pred->getLocation()))
+ if (Pred->getLocation().getAs<BlockEntrance>())
return true;
// Is this on a non-expression?
@@ -268,22 +310,39 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
const Stmt *ReferenceStmt,
- const StackFrameContext *LC,
+ const LocationContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K) {
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
- ReferenceStmt == 0)
+ ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt))
&& "PostStmt is not generally supported by the SymbolReaper yet");
+ assert(LC && "Must pass the current (or expiring) LocationContext");
+
+ if (!DiagnosticStmt) {
+ DiagnosticStmt = ReferenceStmt;
+ assert(DiagnosticStmt && "Required for clearing a LocationContext");
+ }
+
NumRemoveDeadBindings++;
- CleanedState = Pred->getState();
- SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager());
+ ProgramStateRef CleanedState = Pred->getState();
+
+ // LC is the location context being destroyed, but SymbolReaper wants a
+ // location context that is still live. (If this is the top-level stack
+ // frame, this will be null.)
+ if (!ReferenceStmt) {
+ assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind &&
+ "Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext");
+ LC = LC->getParent();
+ }
+
+ const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0;
+ SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager());
getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
// Create a state in which dead bindings are removed from the environment
// and the store. TODO: The function should just return new env and store,
// not a new state.
- const StackFrameContext *SFC = LC->getCurrentStackFrame();
CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
// Process any special transfer function for dead symbols.
@@ -336,19 +395,17 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
- currStmt = S.getStmt();
+ const Stmt *currStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currStmt->getLocStart(),
"Error evaluating statement");
// Remove dead bindings and symbols.
- EntryNode = Pred;
ExplodedNodeSet CleanedStates;
- if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){
- removeDead(EntryNode, CleanedStates, currStmt,
- Pred->getStackFrame(), currStmt);
+ if (shouldRemoveDeadBindings(AMgr, S, Pred, Pred->getLocationContext())){
+ removeDead(Pred, CleanedStates, currStmt, Pred->getLocationContext());
} else
- CleanedStates.Add(EntryNode);
+ CleanedStates.Add(Pred);
// Visit the statement.
ExplodedNodeSet Dst;
@@ -362,11 +419,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
// Enqueue the new nodes onto the work list.
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
-
- // NULL out these variables to cleanup.
- CleanedState = NULL;
- EntryNode = NULL;
- currStmt = 0;
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
@@ -377,7 +429,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
BMI->getSourceLocation(),
"Error evaluating initializer");
- // We don't set EntryNode and currStmt. And we don't clean up state.
+ // We don't clean up dead bindings here.
const StackFrameContext *stackFrame =
cast<StackFrameContext>(Pred->getLocationContext());
const CXXConstructorDecl *decl =
@@ -386,24 +438,52 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ProgramStateRef State = Pred->getState();
SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
- PostInitializer PP(BMI, stackFrame);
ExplodedNodeSet Tmp(Pred);
+ SVal FieldLoc;
// Evaluate the initializer, if necessary
if (BMI->isAnyMemberInitializer()) {
// Constructors build the object directly in the field,
// but non-objects must be copied in from the initializer.
- const Expr *Init = BMI->getInit();
+ const Expr *Init = BMI->getInit()->IgnoreImplicit();
if (!isa<CXXConstructExpr>(Init)) {
- SVal FieldLoc;
- if (BMI->isIndirectMemberInitializer())
+ const ValueDecl *Field;
+ if (BMI->isIndirectMemberInitializer()) {
+ Field = BMI->getIndirectMember();
FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
- else
+ } else {
+ Field = BMI->getMember();
FieldLoc = State->getLValue(BMI->getMember(), thisVal);
+ }
- SVal InitVal = State->getSVal(BMI->getInit(), stackFrame);
+ SVal InitVal;
+ if (BMI->getNumArrayIndices() > 0) {
+ // Handle arrays of trivial type. We can represent this with a
+ // primitive load/copy from the base array region.
+ const ArraySubscriptExpr *ASE;
+ while ((ASE = dyn_cast<ArraySubscriptExpr>(Init)))
+ Init = ASE->getBase()->IgnoreImplicit();
+
+ SVal LValue = State->getSVal(Init, stackFrame);
+ if (Optional<Loc> LValueLoc = LValue.getAs<Loc>())
+ InitVal = State->getSVal(*LValueLoc);
+
+ // If we fail to get the value for some reason, use a symbolic value.
+ if (InitVal.isUnknownOrUndef()) {
+ SValBuilder &SVB = getSValBuilder();
+ InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame,
+ Field->getType(),
+ currBldrCtx->blockCount());
+ }
+ } else {
+ InitVal = State->getSVal(BMI->getInit(), stackFrame);
+ }
+ assert(Tmp.size() == 1 && "have not generated any new nodes yet");
+ assert(*Tmp.begin() == Pred && "have not generated any new nodes yet");
Tmp.clear();
+
+ PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
}
} else {
@@ -413,6 +493,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
// Construct PostInitializer nodes whether the state changed or not,
// so that the diagnostics don't get confused.
+ PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
ExplodedNodeSet Dst;
NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
@@ -429,16 +510,16 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
ExplodedNodeSet Dst;
switch (D.getKind()) {
case CFGElement::AutomaticObjectDtor:
- ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), Pred, Dst);
+ ProcessAutomaticObjDtor(D.castAs<CFGAutomaticObjDtor>(), Pred, Dst);
break;
case CFGElement::BaseDtor:
- ProcessBaseDtor(cast<CFGBaseDtor>(D), Pred, Dst);
+ ProcessBaseDtor(D.castAs<CFGBaseDtor>(), Pred, Dst);
break;
case CFGElement::MemberDtor:
- ProcessMemberDtor(cast<CFGMemberDtor>(D), Pred, Dst);
+ ProcessMemberDtor(D.castAs<CFGMemberDtor>(), Pred, Dst);
break;
case CFGElement::TemporaryDtor:
- ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), Pred, Dst);
+ ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst);
break;
default:
llvm_unreachable("Unexpected dtor kind.");
@@ -451,18 +532,20 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- ProgramStateRef state = Pred->getState();
const VarDecl *varDecl = Dtor.getVarDecl();
-
QualType varType = varDecl->getType();
- if (const ReferenceType *refType = varType->getAs<ReferenceType>())
- varType = refType->getPointeeType();
+ ProgramStateRef state = Pred->getState();
+ SVal dest = state->getLValue(varDecl, Pred->getLocationContext());
+ const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
- Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
+ if (const ReferenceType *refType = varType->getAs<ReferenceType>()) {
+ varType = refType->getPointeeType();
+ Region = state->getSVal(Region).getAsRegion();
+ }
- VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(),
- Dtor.getTriggerStmt(), /*IsBase=*/false, Pred, Dst);
+ VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false,
+ Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
@@ -476,11 +559,13 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
// Create the base object region.
- QualType BaseTy = D.getBaseSpecifier()->getType();
- SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
+ const CXXBaseSpecifier *Base = D.getBaseSpecifier();
+ QualType BaseTy = Base->getType();
+ SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy,
+ Base->isVirtual());
- VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(),
- CurDtor->getBody(), /*IsBase=*/true, Pred, Dst);
+ VisitCXXDestructor(BaseTy, BaseVal.castAs<loc::MemRegionVal>().getRegion(),
+ CurDtor->getBody(), /*IsBase=*/ true, Pred, Dst);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
@@ -492,10 +577,11 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
Loc ThisVal = getSValBuilder().getCXXThis(CurDtor,
LCtx->getCurrentStackFrame());
- SVal FieldVal = State->getLValue(Member, cast<Loc>(State->getSVal(ThisVal)));
+ SVal FieldVal =
+ State->getLValue(Member, State->getSVal(ThisVal).castAs<Loc>());
VisitCXXDestructor(Member->getType(),
- cast<loc::MemRegionVal>(FieldVal).getRegion(),
+ FieldVal.castAs<loc::MemRegionVal>().getRegion(),
CurDtor->getBody(), /*IsBase=*/false, Pred, Dst);
}
@@ -511,16 +597,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet Dst;
StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);
- // Expressions to ignore.
- if (const Expr *Ex = dyn_cast<Expr>(S))
- S = Ex->IgnoreParens();
-
- // FIXME: add metadata to the CFG so that we can disable
- // this check when we KNOW that there is no block-level subexpression.
- // The motivation is that this check requires a hashtable lookup.
-
- if (S != currStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
- return;
+ assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
@@ -637,7 +714,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
case Stmt::CXXBindTemporaryExprClass:
- case Stmt::CXXDefaultArgExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXNullPtrLiteralExprClass: {
Bldr.takeNodes(Pred);
@@ -648,6 +724,43 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
+ case Stmt::CXXDefaultArgExprClass: {
+ Bldr.takeNodes(Pred);
+ ExplodedNodeSet PreVisit;
+ getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
+
+ ExplodedNodeSet Tmp;
+ StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
+
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
+ const Expr *ArgE = DefaultE->getExpr();
+
+ // Avoid creating and destroying a lot of APSInts.
+ SVal V;
+ llvm::APSInt Result;
+
+ for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
+ I != E; ++I) {
+ ProgramStateRef State = (*I)->getState();
+
+ if (ArgE->EvaluateAsInt(Result, getContext()))
+ V = svalBuilder.makeIntVal(Result);
+ else
+ V = State->getSVal(ArgE, LCtx);
+
+ State = State->BindExpr(DefaultE, LCtx, V);
+ if (DefaultE->isGLValue())
+ State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
+ DefaultE);
+ Bldr2.generateNode(S, *I, State);
+ }
+
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+ Bldr.addNodes(Dst);
+ break;
+ }
+
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
// FIXME: explicitly model with a region and the actual contents
@@ -780,16 +893,23 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXNewExprClass: {
Bldr.takeNodes(Pred);
- const CXXNewExpr *NE = cast<CXXNewExpr>(S);
- VisitCXXNewExpr(NE, Pred, Dst);
+ ExplodedNodeSet PostVisit;
+ VisitCXXNewExpr(cast<CXXNewExpr>(S), Pred, PostVisit);
+ getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXDeleteExprClass: {
Bldr.takeNodes(Pred);
+ ExplodedNodeSet PreVisit;
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
- VisitCXXDeleteExpr(CDE, Pred, Dst);
+ getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
+
+ for (ExplodedNodeSet::iterator i = PreVisit.begin(),
+ e = PreVisit.end(); i != e ; ++i)
+ VisitCXXDeleteExpr(CDE, *i, Dst);
+
Bldr.addNodes(Dst);
break;
}
@@ -1012,11 +1132,11 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
// processing the call.
if (L.isPurgeKind())
continue;
- if (isa<PreImplicitCall>(&L))
+ if (L.getAs<PreImplicitCall>())
continue;
- if (isa<CallEnter>(&L))
+ if (L.getAs<CallEnter>())
continue;
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&L))
+ if (Optional<StmtPoint> SP = L.getAs<StmtPoint>())
if (SP->getStmt() == CE)
continue;
break;
@@ -1034,7 +1154,8 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
// Add the special flag to GDM to signal retrying with no inlining.
// Note, changing the state ensures that we are not going to cache out.
ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
- NewNodeState = NewNodeState->set<ReplayWithoutInlining>((void*)CE);
+ NewNodeState =
+ NewNodeState->set<ReplayWithoutInlining>(const_cast<Stmt *>(CE));
// Make the new node a successor of BeforeProcessingCall.
bool IsNew = false;
@@ -1155,7 +1276,7 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
for (; I != E; ++I) {
CFGElement Elem = *I;
- CFGStmt *CS = dyn_cast<CFGStmt>(&Elem);
+ Optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
if (!CS)
continue;
if (CS->getStmt() != Condition)
@@ -1215,8 +1336,8 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
if (PredI->isSink())
continue;
- ProgramStateRef PrevState = Pred->getState();
- SVal X = PrevState->getSVal(Condition, Pred->getLocationContext());
+ ProgramStateRef PrevState = PredI->getState();
+ SVal X = PrevState->getSVal(Condition, PredI->getLocationContext());
if (X.isUnknownOrUndef()) {
// Give it a chance to recover from unknown.
@@ -1228,7 +1349,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
// underlying value and use that instead.
SVal recovered = RecoverCastedSymbol(getStateManager(),
PrevState, Condition,
- Pred->getLocationContext(),
+ PredI->getLocationContext(),
getContext());
if (!recovered.isUnknown()) {
@@ -1245,20 +1366,23 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
continue;
}
- DefinedSVal V = cast<DefinedSVal>(X);
+ DefinedSVal V = X.castAs<DefinedSVal>();
+
+ ProgramStateRef StTrue, StFalse;
+ tie(StTrue, StFalse) = PrevState->assume(V);
// Process the true branch.
if (builder.isFeasible(true)) {
- if (ProgramStateRef state = PrevState->assume(V, true))
- builder.generateNode(state, true, PredI);
+ if (StTrue)
+ builder.generateNode(StTrue, true, PredI);
else
builder.markInfeasible(true);
}
// Process the false branch.
if (builder.isFeasible(false)) {
- if (ProgramStateRef state = PrevState->assume(V, false))
- builder.generateNode(state, false, PredI);
+ if (StFalse)
+ builder.generateNode(StFalse, false, PredI);
else
builder.markInfeasible(false);
}
@@ -1266,6 +1390,34 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
currBldrCtx = 0;
}
+/// The GDM component containing the set of global variables which have been
+/// previously initialized with explicit initializers.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
+ llvm::ImmutableSet<const VarDecl *>)
+
+void ExprEngine::processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext &BuilderCtx,
+ ExplodedNode *Pred,
+ clang::ento::ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) {
+ currBldrCtx = &BuilderCtx;
+
+ const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ ProgramStateRef state = Pred->getState();
+ bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
+ BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF);
+
+ if (!initHasRun) {
+ state = state->add<InitializedGlobalsSet>(VD);
+ }
+
+ builder.generateNode(state, initHasRun, Pred);
+ builder.markInfeasible(!initHasRun);
+
+ currBldrCtx = 0;
+}
+
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
@@ -1282,8 +1434,8 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
typedef IndirectGotoNodeBuilder::iterator iterator;
- if (isa<loc::GotoLabel>(V)) {
- const LabelDecl *L = cast<loc::GotoLabel>(V).getLabel();
+ if (Optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) {
+ const LabelDecl *L = LV->getLabel();
for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
if (I.getLabel() == L) {
@@ -1295,7 +1447,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
llvm_unreachable("No block with label.");
}
- if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
+ if (V.getAs<loc::ConcreteInt>() || V.getAs<UndefinedVal>()) {
// Dispatch to the first target and mark it as a sink.
//ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
// FIXME: add checker visit.
@@ -1325,10 +1477,10 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
// Notify checkers.
for (ExplodedNodeSet::iterator I = AfterRemovedDead.begin(),
E = AfterRemovedDead.end(); I != E; ++I) {
- getCheckerManager().runCheckersForEndPath(BC, Dst, *I, *this);
+ getCheckerManager().runCheckersForEndFunction(BC, Dst, *I, *this);
}
} else {
- getCheckerManager().runCheckersForEndPath(BC, Dst, Pred, *this);
+ getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this);
}
Engine.enqueueEndOfFunction(Dst);
@@ -1349,7 +1501,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
return;
}
- DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
+ DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>();
ProgramStateRef DefaultSt = state;
@@ -1390,7 +1542,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// If CondV evaluates to a constant, then we know that this
// is the *only* case that we can take, so stop evaluating the
// others.
- if (isa<nonloc::ConcreteInt>(CondV))
+ if (CondV.getAs<nonloc::ConcreteInt>())
return;
}
@@ -1484,7 +1636,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
// results in boolean contexts.
SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
currBldrCtx->blockCount());
- state = state->assume(cast<DefinedOrUnknownSVal>(V), true);
+ state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
@@ -1576,6 +1728,122 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
}
}
+namespace {
+class CollectReachableSymbolsCallback : public SymbolVisitor {
+ InvalidatedSymbols Symbols;
+public:
+ CollectReachableSymbolsCallback(ProgramStateRef State) {}
+ const InvalidatedSymbols &getSymbols() const { return Symbols; }
+
+ bool VisitSymbol(SymbolRef Sym) {
+ Symbols.insert(Sym);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+// A value escapes in three possible cases:
+// (1) We are binding to something that is not a memory region.
+// (2) We are binding to a MemrRegion that does not have stack storage.
+// (3) We are binding to a MemRegion with stack storage that the store
+// does not understand.
+ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
+ SVal Loc, SVal Val) {
+ // Are we storing to something that causes the value to "escape"?
+ bool escapes = true;
+
+ // TODO: Move to StoreManager.
+ if (Optional<loc::MemRegionVal> regionLoc = Loc.getAs<loc::MemRegionVal>()) {
+ escapes = !regionLoc->getRegion()->hasStackStorage();
+
+ if (!escapes) {
+ // To test (3), generate a new state with the binding added. If it is
+ // the same state, then it escapes (since the store cannot represent
+ // the binding).
+ // Do this only if we know that the store is not supposed to generate the
+ // same state.
+ SVal StoredVal = State->getSVal(regionLoc->getRegion());
+ if (StoredVal != Val)
+ escapes = (State == (State->bindLoc(*regionLoc, Val)));
+ }
+ }
+
+ // If our store can represent the binding and we aren't storing to something
+ // that doesn't have local storage then just return and have the simulation
+ // state continue as is.
+ if (!escapes)
+ return State;
+
+ // Otherwise, find all symbols referenced by 'val' that we are tracking
+ // and stop tracking them.
+ CollectReachableSymbolsCallback Scanner =
+ State->scanReachableSymbols<CollectReachableSymbolsCallback>(Val);
+ const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols();
+ State = getCheckerManager().runCheckersForPointerEscape(State,
+ EscapedSymbols,
+ /*CallEvent*/ 0,
+ PSK_EscapeOnBind);
+
+ return State;
+}
+
+ProgramStateRef
+ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call,
+ bool IsConst) {
+
+ if (!Invalidated || Invalidated->empty())
+ return State;
+
+ if (!Call)
+ return getCheckerManager().runCheckersForPointerEscape(State,
+ *Invalidated,
+ 0,
+ PSK_EscapeOther);
+
+ // Note: Due to current limitations of RegionStore, we only process the top
+ // level const pointers correctly. The lower level const pointers are
+ // currently treated as non-const.
+ if (IsConst)
+ return getCheckerManager().runCheckersForPointerEscape(State,
+ *Invalidated,
+ Call,
+ PSK_DirectEscapeOnCall,
+ true);
+
+ // If the symbols were invalidated by a call, we want to find out which ones
+ // were invalidated directly due to being arguments to the call.
+ InvalidatedSymbols SymbolsDirectlyInvalidated;
+ for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
+ E = ExplicitRegions.end(); I != E; ++I) {
+ if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
+ SymbolsDirectlyInvalidated.insert(R->getSymbol());
+ }
+
+ InvalidatedSymbols SymbolsIndirectlyInvalidated;
+ for (InvalidatedSymbols::const_iterator I=Invalidated->begin(),
+ E = Invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (SymbolsDirectlyInvalidated.count(sym))
+ continue;
+ SymbolsIndirectlyInvalidated.insert(sym);
+ }
+
+ if (!SymbolsDirectlyInvalidated.empty())
+ State = getCheckerManager().runCheckersForPointerEscape(State,
+ SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall);
+
+ // Notify about the symbols that get indirectly invalidated by the call.
+ if (!SymbolsIndirectlyInvalidated.empty())
+ State = getCheckerManager().runCheckersForPointerEscape(State,
+ SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall);
+
+ return State;
+}
+
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
@@ -1593,36 +1861,42 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
StoreE, *this, *PP);
+
+ StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx);
+
// If the location is not a 'Loc', it will already be handled by
// the checkers. There is nothing left to do.
- if (!isa<Loc>(location)) {
- Dst = CheckedSet;
+ if (!location.getAs<Loc>()) {
+ const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0);
+ ProgramStateRef state = Pred->getState();
+ state = processPointerEscapedOnBind(state, location, Val);
+ Bldr.generateNode(L, state, Pred);
return;
}
- ExplodedNodeSet TmpDst;
- StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState();
+ state = processPointerEscapedOnBind(state, location, Val);
+
// When binding the value, pass on the hint that this is a initialization.
// For initializations, we do not need to inform clients of region
// changes.
- state = state->bindLoc(cast<Loc>(location),
+ state = state->bindLoc(location.castAs<Loc>(),
Val, /* notifyChanges = */ !atDeclInit);
-
+
const MemRegion *LocReg = 0;
- if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) {
+ if (Optional<loc::MemRegionVal> LocRegVal =
+ location.getAs<loc::MemRegionVal>()) {
LocReg = LocRegVal->getRegion();
}
const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
Bldr.generateNode(L, state, PredI);
}
- Dst.insert(TmpDst);
}
/// evalStore - Handle the semantics of a store via an assignment.
@@ -1665,7 +1939,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
const ProgramPointTag *tag,
QualType LoadTy)
{
- assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
+ assert(!location.getAs<NonLoc>() && "location cannot be a NonLoc.");
// Are we loading from a region? This actually results in two loads; one
// to fetch the address of the referenced value and one to fetch the
@@ -1720,20 +1994,15 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
state = (*NI)->getState();
const LocationContext *LCtx = (*NI)->getLocationContext();
- if (location.isUnknown()) {
- // This is important. We must nuke the old binding.
- Bldr.generateNode(NodeEx, *NI,
- state->BindExpr(BoundEx, LCtx, UnknownVal()),
- tag, ProgramPoint::PostLoadKind);
- }
- else {
+ SVal V = UnknownVal();
+ if (location.isValid()) {
if (LoadTy.isNull())
LoadTy = BoundEx->getType();
- SVal V = state->getSVal(cast<Loc>(location), LoadTy);
- Bldr.generateNode(NodeEx, *NI,
- state->bindExprAndLocation(BoundEx, LCtx, location, V),
- tag, ProgramPoint::PostLoadKind);
+ V = state->getSVal(location.castAs<Loc>(), LoadTy);
}
+
+ Bldr.generateNode(NodeEx, *NI, state->BindExpr(BoundEx, LCtx, V), tag,
+ ProgramPoint::PostLoadKind);
}
}
@@ -1793,26 +2062,29 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
// when the expression fails to evaluate to anything meaningful and
// (as an optimization) we don't generate a node.
ProgramPoint P = Pred->getLocation();
- if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
+ if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) {
continue;
}
ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(Ex, Pred->getLocationContext());
- nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
+ Optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
geteagerlyAssumeBinOpBifurcationTags();
+ ProgramStateRef StateTrue, StateFalse;
+ tie(StateTrue, StateFalse) = state->assume(*SEV);
+
// First assume that the condition is true.
- if (ProgramStateRef StateTrue = state->assume(*SEV, true)) {
+ if (StateTrue) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
}
// Next, assume that the condition is false.
- if (ProgramStateRef StateFalse = state->assume(*SEV, false)) {
+ if (StateFalse) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
@@ -1836,10 +2108,10 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
SVal X = state->getSVal(*OI, Pred->getLocationContext());
- assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
+ assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef.
- if (isa<Loc>(X))
- state = state->bindLoc(cast<Loc>(X), UnknownVal());
+ if (Optional<Loc> LV = X.getAs<Loc>())
+ state = state->bindLoc(*LV, UnknownVal());
}
Bldr.generateNode(A, Pred, state);
@@ -1889,7 +2161,7 @@ struct DOTGraphTraits<ExplodedNode*> :
return "";
}
- static void printLocation(llvm::raw_ostream &Out, SourceLocation SLoc) {
+ static void printLocation(raw_ostream &Out, SourceLocation SLoc) {
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getExpansionLineNumber(SLoc)
@@ -1910,7 +2182,7 @@ struct DOTGraphTraits<ExplodedNode*> :
switch (Loc.getKind()) {
case ProgramPoint::BlockEntranceKind: {
Out << "Block Entrance: B"
- << cast<BlockEntrance>(Loc).getBlock()->getBlockID();
+ << Loc.castAs<BlockEntrance>().getBlock()->getBlockID();
if (const NamedDecl *ND =
dyn_cast<NamedDecl>(Loc.getLocationContext()->getDecl())) {
Out << " (";
@@ -1949,73 +2221,46 @@ struct DOTGraphTraits<ExplodedNode*> :
break;
case ProgramPoint::PreImplicitCallKind: {
- ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
+ ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PreCall: ";
// FIXME: Get proper printing options.
- PC->getDecl()->print(Out, LangOptions());
- printLocation(Out, PC->getLocation());
+ PC.getDecl()->print(Out, LangOptions());
+ printLocation(Out, PC.getLocation());
break;
}
case ProgramPoint::PostImplicitCallKind: {
- ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
+ ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PostCall: ";
// FIXME: Get proper printing options.
- PC->getDecl()->print(Out, LangOptions());
- printLocation(Out, PC->getLocation());
+ PC.getDecl()->print(Out, LangOptions());
+ printLocation(Out, PC.getLocation());
break;
}
- default: {
- if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
- const Stmt *S = L->getStmt();
-
- Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
+ case ProgramPoint::PostInitializerKind: {
+ Out << "PostInitializer: ";
+ const CXXCtorInitializer *Init =
+ Loc.castAs<PostInitializer>().getInitializer();
+ if (const FieldDecl *FD = Init->getAnyMember())
+ Out << *FD;
+ else {
+ QualType Ty = Init->getTypeSourceInfo()->getType();
+ Ty = Ty.getLocalUnqualifiedType();
LangOptions LO; // FIXME.
- S->printPretty(Out, 0, PrintingPolicy(LO));
- printLocation(Out, S->getLocStart());
-
- if (isa<PreStmt>(Loc))
- Out << "\\lPreStmt\\l;";
- else if (isa<PostLoad>(Loc))
- Out << "\\lPostLoad\\l;";
- else if (isa<PostStore>(Loc))
- Out << "\\lPostStore\\l";
- else if (isa<PostLValue>(Loc))
- Out << "\\lPostLValue\\l";
-
-#if 0
- // FIXME: Replace with a general scheme to determine
- // the name of the check.
- if (GraphPrintCheckerState->isImplicitNullDeref(N))
- Out << "\\|Implicit-Null Dereference.\\l";
- else if (GraphPrintCheckerState->isExplicitNullDeref(N))
- Out << "\\|Explicit-Null Dereference.\\l";
- else if (GraphPrintCheckerState->isUndefDeref(N))
- Out << "\\|Dereference of undefialied value.\\l";
- else if (GraphPrintCheckerState->isUndefStore(N))
- Out << "\\|Store to Undefined Loc.";
- else if (GraphPrintCheckerState->isUndefResult(N))
- Out << "\\|Result of operation is undefined.";
- else if (GraphPrintCheckerState->isNoReturnCall(N))
- Out << "\\|Call to function marked \"noreturn\".";
- else if (GraphPrintCheckerState->isBadCall(N))
- Out << "\\|Call to NULL/Undefined.";
- else if (GraphPrintCheckerState->isUndefArg(N))
- Out << "\\|Argument in call is undefined";
-#endif
-
- break;
+ Ty.print(Out, LO);
}
+ break;
+ }
- const BlockEdge &E = cast<BlockEdge>(Loc);
+ case ProgramPoint::BlockEdgeKind: {
+ const BlockEdge &E = Loc.castAs<BlockEdge>();
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
<< E.getDst()->getBlockID() << ')';
if (const Stmt *T = E.getSrc()->getTerminator()) {
-
SourceLocation SLoc = T->getLocStart();
Out << "\\|Terminator: ";
@@ -2074,6 +2319,48 @@ struct DOTGraphTraits<ExplodedNode*> :
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
#endif
+ break;
+ }
+
+ default: {
+ const Stmt *S = Loc.castAs<StmtPoint>().getStmt();
+
+ Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
+ LangOptions LO; // FIXME.
+ S->printPretty(Out, 0, PrintingPolicy(LO));
+ printLocation(Out, S->getLocStart());
+
+ if (Loc.getAs<PreStmt>())
+ Out << "\\lPreStmt\\l;";
+ else if (Loc.getAs<PostLoad>())
+ Out << "\\lPostLoad\\l;";
+ else if (Loc.getAs<PostStore>())
+ Out << "\\lPostStore\\l";
+ else if (Loc.getAs<PostLValue>())
+ Out << "\\lPostLValue\\l";
+
+#if 0
+ // FIXME: Replace with a general scheme to determine
+ // the name of the check.
+ if (GraphPrintCheckerState->isImplicitNullDeref(N))
+ Out << "\\|Implicit-Null Dereference.\\l";
+ else if (GraphPrintCheckerState->isExplicitNullDeref(N))
+ Out << "\\|Explicit-Null Dereference.\\l";
+ else if (GraphPrintCheckerState->isUndefDeref(N))
+ Out << "\\|Dereference of undefialied value.\\l";
+ else if (GraphPrintCheckerState->isUndefStore(N))
+ Out << "\\|Store to Undefined Loc.";
+ else if (GraphPrintCheckerState->isUndefResult(N))
+ Out << "\\|Result of operation is undefined.";
+ else if (GraphPrintCheckerState->isNoReturnCall(N))
+ Out << "\\|Call to function marked \"noreturn\".";
+ else if (GraphPrintCheckerState->isBadCall(N))
+ Out << "\\|Call to NULL/Undefined.";
+ else if (GraphPrintCheckerState->isUndefArg(N))
+ Out << "\\|Argument in call is undefined";
+#endif
+
+ break;
}
}
@@ -2108,7 +2395,7 @@ GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
void ExprEngine::ViewGraph(bool trim) {
#ifndef NDEBUG
if (trim) {
- std::vector<ExplodedNode*> Src;
+ std::vector<const ExplodedNode*> Src;
// Flush any outstanding reports to make sure we cover all the nodes.
// This does not cause them to get displayed.
@@ -2122,7 +2409,7 @@ void ExprEngine::ViewGraph(bool trim) {
if (N) Src.push_back(N);
}
- ViewGraph(&Src[0], &Src[0]+Src.size());
+ ViewGraph(Src);
}
else {
GraphPrintCheckerState = this;
@@ -2136,12 +2423,12 @@ void ExprEngine::ViewGraph(bool trim) {
#endif
}
-void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
+void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
- std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
+ OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes));
if (!TrimmedG.get())
llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 00b2f4a6bee9..3a3c9713dd20 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ExprCXX.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -66,12 +67,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// TODO: This can be removed after we enable history tracking with
// SymSymExpr.
unsigned Count = currBldrCtx->blockCount();
- if (isa<Loc>(LeftV) &&
+ if (LeftV.getAs<Loc>() &&
RHS->getType()->isIntegerType() && RightV.isUnknown()) {
RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(),
Count);
}
- if (isa<Loc>(RightV) &&
+ if (RightV.getAs<Loc>() &&
LHS->getType()->isIntegerType() && LeftV.isUnknown()) {
LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(),
Count);
@@ -305,7 +306,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast: {
+ case CK_ObjCObjectLValueCast:
+ case CK_ZeroToOCLEvent: {
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
@@ -423,15 +425,10 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
- // FIXME: static variables may have an initializer, but the second
- // time a function is called those values may not be current.
- // This may need to be reflected in the CFG.
-
// Assumption: The CFG has one DeclStmt per Decl.
- const Decl *D = *DS->decl_begin();
-
- if (!D || !isa<VarDecl>(D)) {
+ const VarDecl *VD = dyn_cast_or_null<VarDecl>(*DS->decl_begin());
+
+ if (!VD) {
//TODO:AZ: remove explicit insertion after refactoring is done.
Dst.insert(Pred);
return;
@@ -442,31 +439,33 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
- const VarDecl *VD = dyn_cast<VarDecl>(D);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
ExplodedNode *N = *I;
ProgramStateRef state = N->getState();
-
- // Decls without InitExpr are not initialized explicitly.
const LocationContext *LC = N->getLocationContext();
-
+
+ // Decls without InitExpr are not initialized explicitly.
if (const Expr *InitEx = VD->getInit()) {
+
+ // Note in the state that the initialization has occurred.
+ ExplodedNode *UpdatedN = N;
SVal InitVal = state->getSVal(InitEx, LC);
- if (InitVal == state->getLValue(VD, LC) ||
- (VD->getType()->isArrayType() &&
- isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) {
+ if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) {
// We constructed the object directly in the variable.
// No need to bind anything.
- B.generateNode(DS, N, state);
+ B.generateNode(DS, UpdatedN, state);
} else {
// We bound the temp obj region to the CXXConstructExpr. Now recover
// the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
- !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
- InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
- assert(isa<nonloc::LazyCompoundVal>(InitVal));
+ if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
+ !VD->getType()->isReferenceType()) {
+ if (Optional<loc::MemRegionVal> M =
+ InitVal.getAs<loc::MemRegionVal>()) {
+ InitVal = state->getSVal(M->getRegion());
+ assert(InitVal.getAs<nonloc::LazyCompoundVal>());
+ }
}
// Recover some path-sensitivity if a scalar value evaluated to
@@ -480,9 +479,11 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty,
currBldrCtx->blockCount());
}
- B.takeNodes(N);
+
+
+ B.takeNodes(UpdatedN);
ExplodedNodeSet Dst2;
- evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
+ evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, LC), InitVal, true);
B.addNodes(Dst2);
}
}
@@ -501,16 +502,16 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
ExplodedNode *N = Pred;
- while (!isa<BlockEntrance>(N->getLocation())) {
+ while (!N->getLocation().getAs<BlockEntrance>()) {
ProgramPoint P = N->getLocation();
- assert(isa<PreStmt>(P)|| isa<PreStmtPurgeDeadSymbols>(P));
+ assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>());
(void) P;
assert(N->pred_size() == 1);
N = *N->pred_begin();
}
assert(N->pred_size() == 1);
N = *N->pred_begin();
- BlockEdge BE = cast<BlockEdge>(N->getLocation());
+ BlockEdge BE = N->getLocation().castAs<BlockEdge>();
SVal X;
// Determine the value of the expression by introspecting how we
@@ -532,28 +533,32 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
// in SrcBlock is the value of the enclosing expression.
// However, we still need to constrain that value to be 0 or 1.
assert(!SrcBlock->empty());
- CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin());
+ CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>();
const Expr *RHS = cast<Expr>(Elem.getStmt());
SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext());
- DefinedOrUnknownSVal DefinedRHS = cast<DefinedOrUnknownSVal>(RHSVal);
- ProgramStateRef StTrue, StFalse;
- llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS);
- if (StTrue) {
- if (StFalse) {
- // We can't constrain the value to 0 or 1; the best we can do is a cast.
- X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType());
+ if (RHSVal.isUndef()) {
+ X = RHSVal;
+ } else {
+ DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>();
+ ProgramStateRef StTrue, StFalse;
+ llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS);
+ if (StTrue) {
+ if (StFalse) {
+ // We can't constrain the value to 0 or 1.
+ // The best we can do is a cast.
+ X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType());
+ } else {
+ // The value is known to be true.
+ X = getSValBuilder().makeIntVal(1, B->getType());
+ }
} else {
- // The value is known to be true.
- X = getSValBuilder().makeIntVal(1, B->getType());
+ // The value is known to be false.
+ assert(StFalse && "Infeasible path!");
+ X = getSValBuilder().makeIntVal(0, B->getType());
}
- } else {
- // The value is known to be false.
- assert(StFalse && "Infeasible path!");
- X = getSValBuilder().makeIntVal(0, B->getType());
}
}
-
Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X));
}
@@ -581,8 +586,10 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
ei = IE->rend(); it != ei; ++it) {
- vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it), LCtx),
- vals);
+ SVal V = state->getSVal(cast<Expr>(*it), LCtx);
+ if (dyn_cast_or_null<CXXTempObjectRegion>(V.getAsRegion()))
+ V = UnknownVal();
+ vals = getBasicVals().consVals(V, vals);
}
B.generateNode(IE, Pred,
@@ -615,14 +622,16 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) {
ProgramPoint PP = N->getLocation();
- if (isa<PreStmtPurgeDeadSymbols>(PP) || isa<BlockEntrance>(PP)) {
+ if (PP.getAs<PreStmtPurgeDeadSymbols>() || PP.getAs<BlockEntrance>()) {
assert(N->pred_size() == 1);
continue;
}
- SrcBlock = cast<BlockEdge>(&PP)->getSrc();
+ SrcBlock = PP.castAs<BlockEdge>().getSrc();
break;
}
+ assert(SrcBlock && "missing function entry");
+
// Find the last expression in the predecessor block. That is the
// expression that is used for the value of the ternary expression.
bool hasValue = false;
@@ -631,7 +640,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
for (CFGBlock::const_reverse_iterator I = SrcBlock->rbegin(),
E = SrcBlock->rend(); I != E; ++I) {
CFGElement CE = *I;
- if (CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
const Expr *ValEx = cast<Expr>(CS->getStmt());
hasValue = true;
V = state->getSVal(ValEx, LCtx);
@@ -785,11 +794,11 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
llvm_unreachable("Invalid Opcode.");
case UO_Not:
// FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, LCtx, evalComplement(cast<NonLoc>(V)));
+ state = state->BindExpr(U, LCtx, evalComplement(V.castAs<NonLoc>()));
break;
case UO_Minus:
// FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, LCtx, evalMinus(cast<NonLoc>(V)));
+ state = state->BindExpr(U, LCtx, evalMinus(V.castAs<NonLoc>()));
break;
case UO_LNot:
// C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
@@ -797,14 +806,16 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
SVal Result;
- if (isa<Loc>(V)) {
+ if (Optional<Loc> LV = V.getAs<Loc>()) {
Loc X = svalBuilder.makeNull();
- Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
- U->getType());
+ Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
}
- else {
+ else if (Ex->getType()->isFloatingType()) {
+ // FIXME: handle floating point types.
+ Result = UnknownVal();
+ } else {
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
+ Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X,
U->getType());
}
@@ -846,7 +857,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested));
continue;
}
- DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
+ DefinedSVal V2 = V2_untested.castAs<DefinedSVal>();
// Handle all other values.
BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub;
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index b3baa7905782..ed90dc589181 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
using namespace clang;
using namespace ento;
@@ -30,23 +30,90 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
- // Bind the temporary object to the value of the expression. Then bind
- // the expression to the location of the object.
SVal V = state->getSVal(tempExpr, LCtx);
// If the value is already a CXXTempObjectRegion, it is fine as it is.
// Otherwise, create a new CXXTempObjectRegion, and copy the value into it.
+ // This is an optimization for when an rvalue is constructed and then
+ // immediately materialized.
const MemRegion *MR = V.getAsRegion();
- if (!MR || !isa<CXXTempObjectRegion>(MR)) {
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
+ if (const CXXTempObjectRegion *TR =
+ dyn_cast_or_null<CXXTempObjectRegion>(MR)) {
+ if (getContext().hasSameUnqualifiedType(TR->getValueType(), ME->getType()))
+ state = state->BindExpr(ME, LCtx, V);
+ }
+
+ if (state == Pred->getState())
+ state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
+ Bldr.generateNode(ME, Pred, state);
+}
+
+// FIXME: This is the sort of code that should eventually live in a Core
+// checker rather than as a special case in ExprEngine.
+void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
+ const CallEvent &Call) {
+ SVal ThisVal;
+ bool AlwaysReturnsLValue;
+ if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
+ assert(Ctor->getDecl()->isTrivial());
+ assert(Ctor->getDecl()->isCopyOrMoveConstructor());
+ ThisVal = Ctor->getCXXThisVal();
+ AlwaysReturnsLValue = false;
+ } else {
+ assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
+ assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
+ OO_Equal);
+ ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
+ AlwaysReturnsLValue = true;
+ }
- SVal L = loc::MemRegionVal(R);
- state = state->bindLoc(L, V);
- V = L;
+ const LocationContext *LCtx = Pred->getLocationContext();
+
+ ExplodedNodeSet Dst;
+ Bldr.takeNodes(Pred);
+
+ SVal V = Call.getArgSVal(0);
+
+ // If the value being copied is not unknown, load from its location to get
+ // an aggregate rvalue.
+ if (Optional<Loc> L = V.getAs<Loc>())
+ V = Pred->getState()->getSVal(*L);
+ else
+ assert(V.isUnknown());
+
+ const Expr *CallExpr = Call.getOriginExpr();
+ evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
+
+ PostStmt PS(CallExpr, LCtx);
+ for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end();
+ I != E; ++I) {
+ ProgramStateRef State = (*I)->getState();
+ if (AlwaysReturnsLValue)
+ State = State->BindExpr(CallExpr, LCtx, ThisVal);
+ else
+ State = bindReturnValue(Call, LCtx, State);
+ Bldr.generateNode(PS, State, *I);
+ }
+}
+
+
+/// Returns a region representing the first element of a (possibly
+/// multi-dimensional) array.
+///
+/// On return, \p Ty will be set to the base type of the array.
+///
+/// If the type is not an array type at all, the original value is returned.
+static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
+ QualType &Ty) {
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ ASTContext &Ctx = SVB.getContext();
+
+ while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
+ Ty = AT->getElementType();
+ LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue);
}
- Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V));
+ return LValue;
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
@@ -57,6 +124,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
const MemRegion *Target = 0;
+ // FIXME: Handle arrays, which run the same constructor for every element.
+ // For now, we just run the first constructor (which should still invalidate
+ // the entire array).
+
switch (CE->getConstructionKind()) {
case CXXConstructExpr::CK_Complete: {
// See if we're constructing an existing region by looking at the next
@@ -66,29 +137,21 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
CFGElement Next = (*B)[currStmtIdx+1];
// Is this a constructor for a local variable?
- if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) {
+ 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();
- if (const ArrayType *AT = getContext().getAsArrayType(Ty)) {
- // FIXME: Handle arrays, which run the same constructor for
- // every element. This workaround will just run the first
- // constructor (which should still invalidate the entire array).
- SVal Base = State->getLValue(Var, LCtx);
- Target = State->getLValue(AT->getElementType(),
- getSValBuilder().makeZeroArrayIndex(),
- Base).getAsRegion();
- } else {
- Target = State->getLValue(Var, LCtx).getAsRegion();
- }
+ LValue = makeZeroElementRegion(State, LValue, Ty);
+ Target = LValue.getAsRegion();
}
}
}
}
// Is this a constructor for a member?
- if (const CFGInitializer *InitElem = dyn_cast<CFGInitializer>(&Next)) {
+ if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) {
const CXXCtorInitializer *Init = InitElem->getInitializer();
assert(Init->isAnyMemberInitializer());
@@ -97,13 +160,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
LCtx->getCurrentStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
+ const ValueDecl *Field;
+ SVal FieldVal;
if (Init->isIndirectMemberInitializer()) {
- SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal);
- Target = Field.getAsRegion();
+ Field = Init->getIndirectMember();
+ FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal);
} else {
- SVal Field = State->getLValue(Init->getMember(), ThisVal);
- Target = Field.getAsRegion();
+ 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.
@@ -130,8 +199,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
Target = ThisVal.getAsRegion();
} else {
// Cast to the base type.
- QualType BaseTy = CE->getType();
- SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
+ bool IsVirtual =
+ (CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase);
+ SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(),
+ IsVirtual);
Target = BaseVal.getAsRegion();
}
break;
@@ -148,14 +219,26 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
*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);
+ ExplodedNodeSet DstEvaluated;
+ StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
+
+ bool IsArray = isa<ElementRegion>(Target);
+ if (CE->getConstructor()->isTrivial() &&
+ CE->getConstructor()->isCopyOrMoveConstructor() &&
+ !IsArray) {
+ // FIXME: Handle other kinds of trivial constructors as well.
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ performTrivialCopy(Bldr, *I, *Call);
+
+ } else {
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ defaultEvalCall(Bldr, *I, *Call);
+ }
ExplodedNodeSet DstPostCall;
- getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
+ getCheckerManager().runCheckersForPostCall(DstPostCall, DstEvaluated,
*Call, *this);
getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
}
@@ -172,11 +255,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
// FIXME: We need to run the same destructor on every element of the array.
// This workaround will just run the first destructor (which will still
// invalidate the entire array).
- if (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) {
- ObjectType = AT->getElementType();
- Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(),
- loc::MemRegionVal(Dest)).getAsRegion();
- }
+ SVal DestVal = loc::MemRegionVal(Dest);
+ DestVal = makeZeroElementRegion(State, DestVal, ObjectType);
+ Dest = DestVal.getAsRegion();
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
@@ -211,15 +292,35 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// Also, we need to decide how allocators actually work -- they're not
// really part of the CXXNewExpr because they happen BEFORE the
// CXXConstructExpr subexpression. See PR12014 for some discussion.
- StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
unsigned blockCount = currBldrCtx->blockCount();
const LocationContext *LCtx = Pred->getLocationContext();
- DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx,
- CNE->getType(),
- blockCount);
- ProgramStateRef State = Pred->getState();
+ DefinedOrUnknownSVal symVal = UnknownVal();
+ FunctionDecl *FD = CNE->getOperatorNew();
+
+ bool IsStandardGlobalOpNewFunction = false;
+ if (FD && !isa<CXXMethodDecl>(FD) && !FD->isVariadic()) {
+ if (FD->getNumParams() == 2) {
+ QualType T = FD->getParamDecl(1)->getType();
+ if (const IdentifierInfo *II = T.getBaseTypeIdentifier())
+ // NoThrow placement new behaves as a standard new.
+ IsStandardGlobalOpNewFunction = II->getName().equals("nothrow_t");
+ }
+ else
+ // Placement forms are considered non-standard.
+ IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1);
+ }
+ // We assume all standard global 'operator new' functions allocate memory in
+ // heap. We realize this is an approximation that might not correctly model
+ // a custom global allocator.
+ if (IsStandardGlobalOpNewFunction)
+ symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
+ else
+ symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(),
+ blockCount);
+
+ ProgramStateRef State = Pred->getState();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
@@ -228,12 +329,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// FIXME: Once we figure out how we want allocators to work,
// we should be using the usual pre-/(default-)eval-/post-call checks here.
State = Call->invalidateRegions(blockCount);
+ if (!State)
+ return;
// If we're compiling with exceptions enabled, and this allocation function
// is not declared as non-throwing, failures /must/ be signalled by
// exceptions, and thus the return value will never be NULL.
// C++11 [basic.stc.dynamic.allocation]p3.
- FunctionDecl *FD = CNE->getOperatorNew();
if (FD && getContext().getLangOpts().CXXExceptions) {
QualType Ty = FD->getType();
if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>())
@@ -241,10 +343,12 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
State = State->assume(symVal, true);
}
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
- const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
+ const MemRegion *NewReg = symVal.castAs<loc::MemRegionVal>().getRegion();
QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
const ElementRegion *EleReg =
getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
@@ -258,30 +362,32 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// CXXNewExpr, we need to make sure that the constructed object is not
// immediately invalidated here. (The placement call should happen before
// the constructor call anyway.)
+ SVal Result = symVal;
if (FD && FD->isReservedGlobalPlacementOperator()) {
// Non-array placement new should always return the placement location.
SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
- SVal Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
- CNE->getPlacementArg(0)->getType());
- State = State->BindExpr(CNE, LCtx, Result);
- } else {
- State = State->BindExpr(CNE, LCtx, symVal);
+ Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
+ CNE->getPlacementArg(0)->getType());
}
+ // Bind the address of the object, then check to see if we cached out.
+ State = State->BindExpr(CNE, LCtx, Result);
+ ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State);
+ if (!NewN)
+ return;
+
// If the type is not a record, we won't have a CXXConstructExpr as an
// initializer. Copy the value over.
if (const Expr *Init = CNE->getInitializer()) {
if (!isa<CXXConstructExpr>(Init)) {
- QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
- (void)ObjTy;
- assert(!ObjTy->isRecordType());
- SVal Location = State->getSVal(CNE, LCtx);
- if (isa<Loc>(Location))
- State = State->bindLoc(cast<Loc>(Location), State->getSVal(Init, LCtx));
+ assert(Bldr.getResults().size() == 1);
+ Bldr.takeNodes(NewN);
+
+ assert(!CNE->getType()->getPointeeCXXRecordDecl());
+ evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx),
+ /*FirstInit=*/IsStandardGlobalOpNewFunction);
}
}
-
- Bldr.generateNode(CNE, Pred, State);
}
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 3ead0817f71b..f01e4e764014 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -13,13 +13,13 @@
#define DEBUG_TYPE "ExprEngine"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -33,6 +33,9 @@ STATISTIC(NumOfDynamicDispatchPathSplits,
STATISTIC(NumInlinedCalls,
"The # of times we inlined a call");
+STATISTIC(NumReachedInlineCountMax,
+ "The # of times we reached inline count maximum");
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -64,6 +67,7 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
static std::pair<const Stmt*,
const CFGBlock*> getLastStmt(const ExplodedNode *Node) {
const Stmt *S = 0;
+ const CFGBlock *Blk = 0;
const StackFrameContext *SF =
Node->getLocation().getLocationContext()->getCurrentStackFrame();
@@ -73,10 +77,10 @@ static std::pair<const Stmt*,
const ProgramPoint &PP = Node->getLocation();
if (PP.getLocationContext()->getCurrentStackFrame() == SF) {
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
+ if (Optional<StmtPoint> SP = PP.getAs<StmtPoint>()) {
S = SP->getStmt();
break;
- } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
+ } else if (Optional<CallExitEnd> CEE = PP.getAs<CallExitEnd>()) {
S = CEE->getCalleeContext()->getCallSite();
if (S)
break;
@@ -84,15 +88,17 @@ static std::pair<const Stmt*,
// If there is no statement, this is an implicitly-generated call.
// We'll walk backwards over it and then continue the loop to find
// an actual statement.
- const CallEnter *CE;
+ Optional<CallEnter> CE;
do {
Node = Node->getFirstPred();
CE = Node->getLocationAs<CallEnter>();
} while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());
// Continue searching the graph.
+ } else if (Optional<BlockEdge> BE = PP.getAs<BlockEdge>()) {
+ Blk = BE->getSrc();
}
- } else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) {
+ } else if (Optional<CallEnter> CE = PP.getAs<CallEnter>()) {
// If we reached the CallEnter for this function, it has no statements.
if (CE->getCalleeContext() == SF)
break;
@@ -104,24 +110,6 @@ static std::pair<const Stmt*,
Node = *Node->pred_begin();
}
- const CFGBlock *Blk = 0;
- if (S) {
- // Now, get the enclosing basic block.
- while (Node) {
- const ProgramPoint &PP = Node->getLocation();
- if (isa<BlockEdge>(PP) &&
- (PP.getLocationContext()->getCurrentStackFrame() == SF)) {
- BlockEdge &EPP = cast<BlockEdge>(PP);
- Blk = EPP.getDst();
- break;
- }
- if (Node->pred_empty())
- return std::pair<const Stmt*, const CFGBlock*>(S, (CFGBlock*)0);
-
- Node = *Node->pred_begin();
- }
- }
-
return std::pair<const Stmt*, const CFGBlock*>(S, Blk);
}
@@ -133,7 +121,7 @@ static std::pair<const Stmt*,
static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
StoreManager &StoreMgr) {
// For now, the only adjustments we handle apply only to locations.
- if (!isa<Loc>(V))
+ if (!V.getAs<Loc>())
return V;
// If the types already match, don't do any unnecessary work.
@@ -168,27 +156,25 @@ static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- NodeBuilder Bldr(Pred, Dst, BC);
-
// 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);
if (!Blk || !LastSt) {
+ Dst.Add(Pred);
return;
}
-
- // If the last statement is return, everything it references should stay live.
- if (isa<ReturnStmt>(LastSt))
- return;
- // Here, we call the Symbol Reaper with 0 stack context telling it to clean up
- // everything on the stack. We use LastStmt as a diagnostic statement, with
- // which the PreStmtPurgeDead point will be associated.
- currBldrCtx = &BC;
- removeDead(Pred, Dst, 0, 0, LastSt,
+ // Here, we destroy the current location context. We use the current
+ // function's entire body as a diagnostic statement, with which the program
+ // point will be associated. However, we only want to use LastStmt as a
+ // reference for what to clean up if it's a ReturnStmt; otherwise, everything
+ // is dead.
+ SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt), LCtx,
+ LCtx->getAnalysisDeclContext()->getBody(),
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
- currBldrCtx = 0;
}
static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
@@ -201,6 +187,23 @@ static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
}
+/// Returns true if the CXXConstructExpr \p E was intended to construct a
+/// prvalue for the region in \p V.
+///
+/// Note that we can't just test for rvalue vs. glvalue because
+/// CXXConstructExprs embedded in DeclStmts and initializers are considered
+/// rvalues by the AST, and the analyzer would like to treat them as lvalues.
+static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) {
+ if (E->isGLValue())
+ return false;
+
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR)
+ return false;
+
+ return isa<CXXTempObjectRegion>(MR);
+}
+
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points:
@@ -261,13 +264,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
SVal ThisV = state->getSVal(This);
- // If the constructed object is a prvalue, get its bindings.
- // Note that we have to be careful here because constructors embedded
- // in DeclStmts are not marked as lvalues.
- if (!CCE->isGLValue())
- if (const MemRegion *MR = ThisV.getAsRegion())
- if (isa<CXXTempObjectRegion>(MR))
- ThisV = state->getSVal(cast<Loc>(ThisV));
+ // If the constructed object is a temporary prvalue, get its bindings.
+ if (isTemporaryPRValue(CCE, ThisV))
+ ThisV = state->getSVal(ThisV.castAs<Loc>());
state = state->BindExpr(CCE, callerCtx, ThisV);
}
@@ -290,11 +289,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
currBldrCtx = &Ctx;
- // Here, we call the Symbol Reaper with 0 statement and caller location
+ // Here, we call the Symbol Reaper with 0 statement and callee location
// context, telling it to clean up everything in the callee's context
- // (and it's children). We use LastStmt as a diagnostic statement, which
- // which the PreStmtPurge Dead point will be associated.
- removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt,
+ // (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,
+ calleeCtx->getAnalysisDeclContext()->getBody(),
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
currBldrCtx = 0;
} else {
@@ -394,63 +394,6 @@ static bool IsInStdNamespace(const FunctionDecl *FD) {
return ND->getName() == "std";
}
-// Determine if we should inline the call.
-bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
- AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
- const CFG *CalleeCFG = CalleeADC->getCFG();
-
- // It is possible that the CFG cannot be constructed.
- // Be safe, and check if the CalleeCFG is valid.
- if (!CalleeCFG)
- return false;
-
- bool IsRecursive = false;
- unsigned StackDepth = 0;
- examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
- if ((StackDepth >= AMgr.options.InlineMaxStackDepth) &&
- ((CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize())
- || IsRecursive))
- return false;
-
- if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D))
- return false;
-
- if (CalleeCFG->getNumBlockIDs() > AMgr.options.InlineMaxFunctionSize)
- return false;
-
- // Do not inline variadic calls (for now).
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
- if (BD->isVariadic())
- return false;
- }
- else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isVariadic())
- return false;
- }
-
- if (getContext().getLangOpts().CPlusPlus) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // Conditionally allow the inlining of template functions.
- if (!getAnalysisManager().options.mayInlineTemplateFunctions())
- if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
- return false;
-
- // Conditionally allow the inlining of C++ standard library functions.
- if (!getAnalysisManager().options.mayInlineCXXStandardLibrary())
- if (getContext().getSourceManager().isInSystemHeader(FD->getLocation()))
- if (IsInStdNamespace(FD))
- return false;
- }
- }
-
- // It is possible that the live variables analysis cannot be
- // run. If so, bail out.
- if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
- return false;
-
- return true;
-}
-
// The GDM component containing the dynamic dispatch bifurcation info. When
// the exact type of the receiver is not known, we want to explore both paths -
// one on which we do inline it and the other one on which we don't. This is
@@ -474,107 +417,16 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
const LocationContext *CurLC = Pred->getLocationContext();
const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
- const LocationContext *ParentOfCallee = 0;
-
- AnalyzerOptions &Opts = getAnalysisManager().options;
-
- // FIXME: Refactor this check into a hypothetical CallEvent::canInline.
- switch (Call.getKind()) {
- case CE_Function:
- break;
- case CE_CXXMember:
- case CE_CXXMemberOperator:
- if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
- return false;
- break;
- case CE_CXXConstructor: {
- if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
- return false;
-
- const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
-
- // FIXME: We don't handle constructors or destructors for arrays properly.
- const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion();
- if (Target && isa<ElementRegion>(Target))
- return false;
-
- // FIXME: This is a hack. We don't use the correct region for a new
- // expression, so if we inline the constructor its result will just be
- // thrown away. This short-term hack is tracked in <rdar://problem/12180598>
- // and the longer-term possible fix is discussed in PR12014.
- const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
- if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr))
- if (isa<CXXNewExpr>(Parent))
- return false;
-
- // Inlining constructors requires including initializers in the CFG.
- const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers");
- (void)ADC;
-
- // If the destructor is trivial, it's always safe to inline the constructor.
- if (Ctor.getDecl()->getParent()->hasTrivialDestructor())
- break;
-
- // For other types, only inline constructors if destructor inlining is
- // also enabled.
- if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
- return false;
-
- // FIXME: This is a hack. We don't handle temporary destructors
- // right now, so we shouldn't inline their constructors.
- if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
- if (!Target || !isa<DeclRegion>(Target))
- return false;
-
- break;
- }
- case CE_CXXDestructor: {
- if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
- return false;
-
- // Inlining destructors requires building the CFG correctly.
- const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
- (void)ADC;
-
- const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
-
- // FIXME: We don't handle constructors or destructors for arrays properly.
- const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion();
- if (Target && isa<ElementRegion>(Target))
- return false;
-
- break;
- }
- case CE_CXXAllocator:
- // Do not inline allocators until we model deallocators.
- // This is unfortunate, but basically necessary for smart pointers and such.
- return false;
- case CE_Block: {
+ const LocationContext *ParentOfCallee = CallerSFC;
+ if (Call.getKind() == CE_Block) {
const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
assert(BR && "If we have the block definition we should have its region");
AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
cast<BlockDecl>(D),
BR);
- break;
- }
- case CE_ObjCMessage:
- if (!Opts.mayInlineObjCMethod())
- return false;
- if (!(getAnalysisManager().options.IPAMode == DynamicDispatch ||
- getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate))
- return false;
- break;
}
-
- if (!shouldInlineDecl(D, Pred))
- return false;
- if (!ParentOfCallee)
- ParentOfCallee = CallerSFC;
-
// This may be NULL, but that's fine.
const Expr *CallE = Call.getOriginExpr();
@@ -585,6 +437,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
currBldrCtx->getBlock(),
currStmtIdx);
+
CallEnter Loc(CallE, CalleeSFC, CurLC);
// Construct a new state which contains the mapping from actual to
@@ -613,11 +466,11 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
static ProgramStateRef getInlineFailedState(ProgramStateRef State,
const Stmt *CallE) {
- void *ReplayState = State->get<ReplayWithoutInlining>();
+ const void *ReplayState = State->get<ReplayWithoutInlining>();
if (!ReplayState)
return 0;
- assert(ReplayState == (const void*)CallE && "Backtracked to the wrong call.");
+ assert(ReplayState == CallE && "Backtracked to the wrong call.");
(void)CallE;
return State->remove<ReplayWithoutInlining>();
@@ -696,7 +549,13 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
}
}
} else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){
- return State->BindExpr(E, LCtx, C->getCXXThisVal());
+ SVal ThisV = C->getCXXThisVal();
+
+ // If the constructed object is a temporary prvalue, get its bindings.
+ if (isTemporaryPRValue(cast<CXXConstructExpr>(E), ThisV))
+ ThisV = State->getSVal(ThisV.castAs<Loc>());
+
+ return State->BindExpr(E, LCtx, ThisV);
}
// Conjure a symbol if the return value is unknown.
@@ -710,7 +569,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// Conservatively evaluate call by invalidating regions and binding
// a conjured return value.
void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
- ExplodedNode *Pred, ProgramStateRef State) {
+ ExplodedNode *Pred,
+ ProgramStateRef State) {
State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
State = bindReturnValue(Call, Pred->getLocationContext(), State);
@@ -718,38 +578,332 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
Bldr.generateNode(Call.getProgramPoint(), State, Pred);
}
+enum CallInlinePolicy {
+ CIP_Allowed,
+ CIP_DisallowedOnce,
+ CIP_DisallowedAlways
+};
+
+static CallInlinePolicy mayInlineCallKind(const CallEvent &Call,
+ const ExplodedNode *Pred,
+ AnalyzerOptions &Opts) {
+ const LocationContext *CurLC = Pred->getLocationContext();
+ const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
+ switch (Call.getKind()) {
+ case CE_Function:
+ case CE_Block:
+ break;
+ case CE_CXXMember:
+ case CE_CXXMemberOperator:
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
+ return CIP_DisallowedAlways;
+ break;
+ case CE_CXXConstructor: {
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
+ return CIP_DisallowedAlways;
+
+ const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
+
+ // FIXME: We don't handle constructors or destructors for arrays properly.
+ // Even once we do, we still need to be careful about implicitly-generated
+ // initializers for array fields in default move/copy constructors.
+ const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion();
+ if (Target && isa<ElementRegion>(Target))
+ return CIP_DisallowedOnce;
+
+ // FIXME: This is a hack. We don't use the correct region for a new
+ // expression, so if we inline the constructor its result will just be
+ // thrown away. This short-term hack is tracked in <rdar://problem/12180598>
+ // and the longer-term possible fix is discussed in PR12014.
+ const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
+ if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr))
+ if (isa<CXXNewExpr>(Parent))
+ return CIP_DisallowedOnce;
+
+ // Inlining constructors requires including initializers in the CFG.
+ const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
+ assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers");
+ (void)ADC;
+
+ // If the destructor is trivial, it's always safe to inline the constructor.
+ if (Ctor.getDecl()->getParent()->hasTrivialDestructor())
+ break;
+
+ // For other types, only inline constructors if destructor inlining is
+ // also enabled.
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
+ return CIP_DisallowedAlways;
+
+ // FIXME: This is a hack. We don't handle temporary destructors
+ // right now, so we shouldn't inline their constructors.
+ if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ if (!Target || !isa<DeclRegion>(Target))
+ return CIP_DisallowedOnce;
+
+ break;
+ }
+ case CE_CXXDestructor: {
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
+ return CIP_DisallowedAlways;
+
+ // Inlining destructors requires building the CFG correctly.
+ const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
+ assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
+ (void)ADC;
+
+ const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
+
+ // FIXME: We don't handle constructors or destructors for arrays properly.
+ const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion();
+ if (Target && isa<ElementRegion>(Target))
+ return CIP_DisallowedOnce;
+
+ break;
+ }
+ case CE_CXXAllocator:
+ // Do not inline allocators until we model deallocators.
+ // This is unfortunate, but basically necessary for smart pointers and such.
+ return CIP_DisallowedAlways;
+ case CE_ObjCMessage:
+ if (!Opts.mayInlineObjCMethod())
+ return CIP_DisallowedAlways;
+ if (!(Opts.getIPAMode() == IPAK_DynamicDispatch ||
+ Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate))
+ return CIP_DisallowedAlways;
+ break;
+ }
+
+ return CIP_Allowed;
+}
+
+/// Returns true if the given C++ class is a container.
+///
+/// Our heuristic for this is whether it contains a method named 'begin()' or a
+/// nested type named 'iterator'.
+static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) {
+ // Don't record any path information.
+ CXXBasePaths Paths(false, false, false);
+
+ const IdentifierInfo &BeginII = Ctx.Idents.get("begin");
+ DeclarationName BeginName = Ctx.DeclarationNames.getIdentifier(&BeginII);
+ DeclContext::lookup_const_result BeginDecls = RD->lookup(BeginName);
+ if (!BeginDecls.empty())
+ return true;
+ if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember,
+ BeginName.getAsOpaquePtr(),
+ Paths))
+ return true;
+
+ const IdentifierInfo &IterII = Ctx.Idents.get("iterator");
+ DeclarationName IteratorName = Ctx.DeclarationNames.getIdentifier(&IterII);
+ DeclContext::lookup_const_result IterDecls = RD->lookup(IteratorName);
+ if (!IterDecls.empty())
+ return true;
+ if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember,
+ IteratorName.getAsOpaquePtr(),
+ Paths))
+ return true;
+
+ return false;
+}
+
+/// Returns true if the given function refers to a constructor or destructor of
+/// a C++ container.
+///
+/// We generally do a poor job modeling most containers right now, and would
+/// prefer not to inline their methods.
+static bool isContainerCtorOrDtor(const ASTContext &Ctx,
+ const FunctionDecl *FD) {
+ // Heuristic: a type is a container if it contains a "begin()" method
+ // or a type named "iterator".
+ if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)))
+ return false;
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent();
+ return isContainerClass(Ctx, RD);
+}
+
+/// Returns true if the function in \p CalleeADC may be inlined in general.
+///
+/// This checks static properties of the function, such as its signature and
+/// CFG, to determine whether the analyzer should ever consider inlining it,
+/// in any context.
+static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC,
+ AnalyzerOptions &Opts) {
+ // FIXME: Do not inline variadic calls.
+ if (Call.isVariadic())
+ return false;
+
+ // Check certain C++-related inlining policies.
+ ASTContext &Ctx = CalleeADC->getASTContext();
+ if (Ctx.getLangOpts().CPlusPlus) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) {
+ // Conditionally control the inlining of template functions.
+ if (!Opts.mayInlineTemplateFunctions())
+ if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ return false;
+
+ // Conditionally control the inlining of C++ standard library functions.
+ if (!Opts.mayInlineCXXStandardLibrary())
+ if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation()))
+ if (IsInStdNamespace(FD))
+ return false;
+
+ // Conditionally control the inlining of methods on objects that look
+ // like C++ containers.
+ if (!Opts.mayInlineCXXContainerCtorsAndDtors())
+ if (!Ctx.getSourceManager().isFromMainFile(FD->getLocation()))
+ if (isContainerCtorOrDtor(Ctx, FD))
+ return false;
+ }
+ }
+
+ // It is possible that the CFG cannot be constructed.
+ // Be safe, and check if the CalleeCFG is valid.
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+ if (!CalleeCFG)
+ return false;
+
+ // Do not inline large functions.
+ if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize())
+ return false;
+
+ // It is possible that the live variables analysis cannot be
+ // run. If so, bail out.
+ if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
+ return false;
+
+ return true;
+}
+
+bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
+ const ExplodedNode *Pred) {
+ if (!D)
+ return false;
+
+ AnalysisManager &AMgr = getAnalysisManager();
+ AnalyzerOptions &Opts = AMgr.options;
+ AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager();
+ AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D);
+
+ // The auto-synthesized bodies are essential to inline as they are
+ // usually small and commonly used. Note: we should do this check early on to
+ // ensure we always inline these calls.
+ if (CalleeADC->isBodyAutosynthesized())
+ return true;
+
+ if (!AMgr.shouldInlineCall())
+ return false;
+
+ // Check if this function has been marked as non-inlinable.
+ Optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
+ if (MayInline.hasValue()) {
+ if (!MayInline.getValue())
+ return false;
+
+ } else {
+ // We haven't actually checked the static properties of this function yet.
+ // Do that now, and record our decision in the function summaries.
+ if (mayInlineDecl(Call, CalleeADC, Opts)) {
+ Engine.FunctionSummaries->markMayInline(D);
+ } else {
+ Engine.FunctionSummaries->markShouldNotInline(D);
+ return false;
+ }
+ }
+
+ // Check if we should inline a call based on its kind.
+ // FIXME: this checks both static and dynamic properties of the call, which
+ // means we're redoing a bit of work that could be cached in the function
+ // summary.
+ CallInlinePolicy CIP = mayInlineCallKind(Call, Pred, Opts);
+ if (CIP != CIP_Allowed) {
+ if (CIP == CIP_DisallowedAlways) {
+ assert(!MayInline.hasValue() || MayInline.getValue());
+ Engine.FunctionSummaries->markShouldNotInline(D);
+ }
+ return false;
+ }
+
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+
+ // Do not inline if recursive or we've reached max stack frame count.
+ bool IsRecursive = false;
+ unsigned StackDepth = 0;
+ examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
+ if ((StackDepth >= Opts.InlineMaxStackDepth) &&
+ ((CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize())
+ || IsRecursive))
+ return false;
+
+ // Do not inline large functions too many times.
+ if ((Engine.FunctionSummaries->getNumTimesInlined(D) >
+ Opts.getMaxTimesInlineLarge()) &&
+ CalleeCFG->getNumBlockIDs() > 13) {
+ NumReachedInlineCountMax++;
+ return false;
+ }
+
+ if (HowToInline == Inline_Minimal &&
+ (CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize()
+ || IsRecursive))
+ return false;
+
+ Engine.FunctionSummaries->bumpNumTimesInlined(D);
+
+ return true;
+}
+
+static bool isTrivialObjectAssignment(const CallEvent &Call) {
+ const CXXInstanceCall *ICall = dyn_cast<CXXInstanceCall>(&Call);
+ if (!ICall)
+ return false;
+
+ const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(ICall->getDecl());
+ if (!MD)
+ return false;
+ if (!(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()))
+ return false;
+
+ return MD->isTrivial();
+}
+
void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &CallTemplate) {
// Make sure we have the most recent state attached to the call.
ProgramStateRef State = Pred->getState();
CallEventRef<> Call = CallTemplate.cloneWithState(State);
- if (!getAnalysisManager().shouldInlineCall()) {
- conservativeEvalCall(*Call, Bldr, Pred, State);
+ // Special-case trivial assignment operators.
+ if (isTrivialObjectAssignment(*Call)) {
+ performTrivialCopy(Bldr, Pred, *Call);
return;
}
+
// Try to inline the call.
// The origin expression here is just used as a kind of checksum;
// this should still be safe even for CallEvents that don't come from exprs.
const Expr *E = Call->getOriginExpr();
- ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
+ ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
if (InlinedFailedState) {
// If we already tried once and failed, make sure we don't retry later.
State = InlinedFailedState;
} else {
RuntimeDefinition RD = Call->getRuntimeDefinition();
const Decl *D = RD.getDecl();
- if (D) {
+ if (shouldInlineCall(*Call, D, Pred)) {
if (RD.mayHaveOtherDefinitions()) {
+ AnalyzerOptions &Options = getAnalysisManager().options;
+
// Explore with and without inlining the call.
- if (getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate) {
+ if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) {
BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred);
return;
}
// Don't inline if we're not in any dynamic dispatch mode.
- if (getAnalysisManager().options.IPAMode != DynamicDispatch) {
+ if (Options.getIPAMode() != IPAK_DynamicDispatch) {
conservativeEvalCall(*Call, Bldr, Pred, State);
return;
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 51dda19b5315..d276d9244614 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -103,8 +103,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
// Handle the case where the container has no elements.
SVal FalseV = svalBuilder.makeTruthVal(0);
ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
-
- if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
+
+ if (Optional<loc::MemRegionVal> MV = elementV.getAs<loc::MemRegionVal>())
if (const TypedValueRegion *R =
dyn_cast<TypedValueRegion>(MV->getRegion())) {
// FIXME: The proper thing to do is to really iterate over the
@@ -161,8 +161,9 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
-
+ DefinedOrUnknownSVal receiverVal =
+ recVal.castAs<DefinedOrUnknownSVal>();
+
ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = State->assume(receiverVal);
@@ -179,13 +180,13 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
if (ObjCNoRet.isImplicitNoReturn(ME)) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- Bldr.generateSink(currStmt, Pred, State);
+ Bldr.generateSink(ME, Pred, State);
continue;
}
// Generate a transition to non-Nil state.
if (notNilState != State) {
- Pred = Bldr.generateNode(currStmt, Pred, notNilState);
+ Pred = Bldr.generateNode(ME, Pred, notNilState);
assert(Pred && "Should have cached out already!");
}
}
@@ -195,7 +196,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
if (ObjCNoRet.isImplicitNoReturn(ME)) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- Bldr.generateSink(currStmt, Pred, Pred->getState());
+ Bldr.generateSink(ME, Pred, Pred->getState());
continue;
}
}
diff --git a/lib/StaticAnalyzer/Core/FunctionSummary.cpp b/lib/StaticAnalyzer/Core/FunctionSummary.cpp
index c227aac2b4c7..c21735b8b882 100644
--- a/lib/StaticAnalyzer/Core/FunctionSummary.cpp
+++ b/lib/StaticAnalyzer/Core/FunctionSummary.cpp
@@ -1,4 +1,4 @@
-//== FunctionSummary.h - Stores summaries of functions. ------------*- C++ -*-//
+//== FunctionSummary.cpp - Stores summaries of functions. ----------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a summary of a function gathered/used by static analyzes.
+// This file defines a summary of a function gathered/used by static analysis.
//
//===----------------------------------------------------------------------===//
@@ -15,16 +15,10 @@
using namespace clang;
using namespace ento;
-FunctionSummariesTy::~FunctionSummariesTy() {
- for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
- delete(I->second);
- }
-}
-
unsigned FunctionSummariesTy::getTotalNumBasicBlocks() {
unsigned Total = 0;
for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
- Total += I->second->TotalBasicBlocks;
+ Total += I->second.TotalBasicBlocks;
}
return Total;
}
@@ -32,7 +26,7 @@ unsigned FunctionSummariesTy::getTotalNumBasicBlocks() {
unsigned FunctionSummariesTy::getTotalNumVisitedBasicBlocks() {
unsigned Total = 0;
for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
- Total += I->second->VisitedBasicBlocks.count();
+ Total += I->second.VisitedBasicBlocks.count();
}
return Total;
}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index fd875f66d2db..73426da2b4df 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Rewrite/Core/HTMLRewrite.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -76,7 +76,8 @@ HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
FilePrefix.appendComponent("report");
}
-void ento::createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string& prefix,
const Preprocessor &PP) {
C.push_back(new HTMLDiagnostics(prefix, PP));
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index fab10cfd3d04..b3a1e65b19a5 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -14,13 +14,14 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -194,6 +195,10 @@ DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const
}
DefinedOrUnknownSVal FieldRegion::getExtent(SValBuilder &svalBuilder) const {
+ // Force callers to deal with bitfields explicitly.
+ if (getDecl()->isBitField())
+ return UnknownVal();
+
DefinedOrUnknownSVal Extent = DeclRegion::getExtent(svalBuilder);
// A zero-length array at the end of a struct often stands for dynamically-
@@ -233,7 +238,7 @@ QualType ObjCIvarRegion::getValueType() const {
}
QualType CXXBaseObjectRegion::getValueType() const {
- return QualType(decl->getTypeForDecl(), 0);
+ return QualType(getDecl()->getTypeForDecl(), 0);
}
//===----------------------------------------------------------------------===//
@@ -272,10 +277,11 @@ void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const Expr *Ex, unsigned cnt,
- const MemRegion *) {
+ const MemRegion *superRegion) {
ID.AddInteger((unsigned) AllocaRegionKind);
ID.AddPointer(Ex);
ID.AddInteger(cnt);
+ ID.AddPointer(superRegion);
}
void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
@@ -400,14 +406,16 @@ void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
}
void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const CXXRecordDecl *decl,
- const MemRegion *sReg) {
- ID.AddPointer(decl);
- ID.AddPointer(sReg);
+ const CXXRecordDecl *RD,
+ bool IsVirtual,
+ const MemRegion *SReg) {
+ ID.AddPointer(RD);
+ ID.AddBoolean(IsVirtual);
+ ID.AddPointer(SReg);
}
void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, decl, superRegion);
+ ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
}
//===----------------------------------------------------------------------===//
@@ -470,7 +478,7 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
}
void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "base{" << superRegion << ',' << decl->getName() << '}';
+ os << "base{" << superRegion << ',' << getDecl()->getName() << '}';
}
void CXXThisRegion::dumpToStream(raw_ostream &os) const {
@@ -562,6 +570,14 @@ void VarRegion::printPretty(raw_ostream &os) const {
os << getDecl()->getName();
}
+bool ObjCIvarRegion::canPrintPretty() const {
+ return true;
+}
+
+void ObjCIvarRegion::printPretty(raw_ostream &os) const {
+ os << getDecl()->getName();
+}
+
bool FieldRegion::canPrintPretty() const {
return superRegion->canPrintPretty();
}
@@ -883,41 +899,50 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,
return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
}
-const CXXBaseObjectRegion *
-MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl,
- const MemRegion *superRegion) {
- // Check that the base class is actually a direct base of this region.
- if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(superRegion)) {
- if (const CXXRecordDecl *Class = TVR->getValueType()->getAsCXXRecordDecl()){
- if (Class->isVirtuallyDerivedFrom(decl)) {
- // Virtual base regions should not be layered, since the layout rules
- // are different.
- while (const CXXBaseObjectRegion *Base =
- dyn_cast<CXXBaseObjectRegion>(superRegion)) {
- superRegion = Base->getSuperRegion();
- }
- assert(superRegion && !isa<MemSpaceRegion>(superRegion));
+/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
+/// class of the type of \p Super.
+static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
+ const TypedValueRegion *Super,
+ bool IsVirtual) {
+ BaseClass = BaseClass->getCanonicalDecl();
- } else {
- // Non-virtual bases should always be direct bases.
-#ifndef NDEBUG
- bool FoundBase = false;
- for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
- E = Class->bases_end();
- I != E; ++I) {
- if (I->getType()->getAsCXXRecordDecl() == decl) {
- FoundBase = true;
- break;
- }
- }
+ const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
+ if (!Class)
+ return true;
+
+ 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)
+ return true;
+ }
+
+ return false;
+}
- assert(FoundBase && "Not a direct base class of this region");
-#endif
+const CXXBaseObjectRegion *
+MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
+ const MemRegion *Super,
+ bool IsVirtual) {
+ if (isa<TypedValueRegion>(Super)) {
+ assert(isValidBaseClass(RD, dyn_cast<TypedValueRegion>(Super), IsVirtual));
+ (void)isValidBaseClass;
+
+ if (IsVirtual) {
+ // Virtual base regions should not be layered, since the layout rules
+ // are different.
+ while (const CXXBaseObjectRegion *Base =
+ dyn_cast<CXXBaseObjectRegion>(Super)) {
+ Super = Base->getSuperRegion();
}
+ assert(Super && !isa<MemSpaceRegion>(Super));
}
}
- return getSubRegion<CXXBaseObjectRegion>(decl, superRegion);
+ return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
}
const CXXThisRegion*
@@ -1042,7 +1067,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
// FIXME: generalize to symbolic offsets.
SVal index = ER->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
+ if (Optional<nonloc::ConcreteInt> CI = index.getAs<nonloc::ConcreteInt>()) {
// Update the offset.
int64_t i = CI->getValue().getSExtValue();
@@ -1071,6 +1096,23 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
return RegionRawOffset(superR, offset);
}
+
+/// Returns true if \p Base is an immediate base class of \p Child
+static bool isImmediateBase(const CXXRecordDecl *Child,
+ const CXXRecordDecl *Base) {
+ // 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)
+ return true;
+ }
+
+ return false;
+}
+
RegionOffset MemRegion::getAsOffset() const {
const MemRegion *R = this;
const MemRegion *SymbolicOffsetBase = 0;
@@ -1078,16 +1120,37 @@ RegionOffset MemRegion::getAsOffset() const {
while (1) {
switch (R->getKind()) {
- default:
- return RegionOffset(R, RegionOffset::Symbolic);
+ case GenericMemSpaceRegionKind:
+ case StackLocalsSpaceRegionKind:
+ case StackArgumentsSpaceRegionKind:
+ case HeapSpaceRegionKind:
+ case UnknownSpaceRegionKind:
+ case StaticGlobalSpaceRegionKind:
+ case GlobalInternalSpaceRegionKind:
+ case GlobalSystemSpaceRegionKind:
+ case GlobalImmutableSpaceRegionKind:
+ // Stores can bind directly to a region space to set a default value.
+ assert(Offset == 0 && !SymbolicOffsetBase);
+ goto Finish;
+
+ case FunctionTextRegionKind:
+ case BlockTextRegionKind:
+ case BlockDataRegionKind:
+ // These will never have bindings, but may end up having values requested
+ // if the user does some strange casting.
+ if (Offset != 0)
+ SymbolicOffsetBase = R;
+ goto Finish;
case SymbolicRegionKind:
case AllocaRegionKind:
case CompoundLiteralRegionKind:
case CXXThisRegionKind:
case StringRegionKind:
+ case ObjCStringRegionKind:
case VarRegionKind:
case CXXTempObjectRegionKind:
+ // Usual base regions.
goto Finish;
case ObjCIvarRegionKind:
@@ -1103,6 +1166,7 @@ RegionOffset MemRegion::getAsOffset() const {
R = BOR->getSuperRegion();
QualType Ty;
+ bool RootIsSymbolic = false;
if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) {
Ty = TVR->getDesugaredValueType(getContext());
} else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
@@ -1110,6 +1174,7 @@ RegionOffset MemRegion::getAsOffset() const {
// Pretend the type of the symbol is the true dynamic type.
// (This will at least be self-consistent for the life of the symbol.)
Ty = SR->getSymbol()->getType()->getPointeeType();
+ RootIsSymbolic = true;
}
const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
@@ -1118,19 +1183,30 @@ RegionOffset MemRegion::getAsOffset() const {
SymbolicOffsetBase = R;
}
+ if (RootIsSymbolic) {
+ // Base layers on symbolic regions may not be type-correct.
+ // Double-check the inheritance here, and revert to a symbolic offset
+ // if it's invalid (e.g. due to a reinterpret_cast).
+ if (BOR->isVirtual()) {
+ if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ } else {
+ if (!isImmediateBase(Child, BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ }
+ }
+
// Don't bother calculating precise offsets if we already have a
// symbolic offset somewhere in the chain.
if (SymbolicOffsetBase)
continue;
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
-
CharUnits BaseOffset;
- const CXXRecordDecl *Base = BOR->getDecl();
- if (Child->isVirtuallyDerivedFrom(Base))
- BaseOffset = Layout.getVBaseClassOffset(Base);
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
+ if (BOR->isVirtual())
+ BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
else
- BaseOffset = Layout.getBaseClassOffset(Base);
+ BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
// The base offset is in chars, not in bits.
Offset += BaseOffset.getQuantity() * getContext().getCharWidth();
@@ -1148,7 +1224,8 @@ RegionOffset MemRegion::getAsOffset() const {
}
SVal Index = ER->getIndex();
- if (const nonloc::ConcreteInt *CI=dyn_cast<nonloc::ConcreteInt>(&Index)) {
+ if (Optional<nonloc::ConcreteInt> CI =
+ Index.getAs<nonloc::ConcreteInt>()) {
// Don't bother calculating precise offsets if we already have a
// symbolic offset somewhere in the chain.
if (SymbolicOffsetBase)
@@ -1207,6 +1284,29 @@ RegionOffset MemRegion::getAsOffset() const {
// BlockDataRegion
//===----------------------------------------------------------------------===//
+std::pair<const VarRegion *, const VarRegion *>
+BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
+ MemRegionManager &MemMgr = *getMemRegionManager();
+ const VarRegion *VR = 0;
+ const VarRegion *OriginalVR = 0;
+
+ if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {
+ VR = MemMgr.getVarRegion(VD, this);
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
+ else {
+ if (LC) {
+ VR = MemMgr.getVarRegion(VD, LC);
+ OriginalVR = VR;
+ }
+ else {
+ VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
+ }
+ return std::make_pair(VR, OriginalVR);
+}
+
void BlockDataRegion::LazyInitializeReferencedVars() {
if (ReferencedVars)
return;
@@ -1231,25 +1331,9 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
new (BVOriginal) VarVec(BC, E - I);
for ( ; I != E; ++I) {
- const VarDecl *VD = *I;
const VarRegion *VR = 0;
const VarRegion *OriginalVR = 0;
-
- if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {
- VR = MemMgr.getVarRegion(VD, this);
- OriginalVR = MemMgr.getVarRegion(VD, LC);
- }
- else {
- if (LC) {
- VR = MemMgr.getVarRegion(VD, LC);
- OriginalVR = VR;
- }
- else {
- VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
- OriginalVR = MemMgr.getVarRegion(VD, LC);
- }
- }
-
+ llvm::tie(VR, OriginalVR) = getCaptureRegions(*I);
assert(VR);
assert(OriginalVR);
BV->push_back(VR, BC);
@@ -1293,3 +1377,13 @@ BlockDataRegion::referenced_vars_end() const {
return BlockDataRegion::referenced_vars_iterator(Vec->end(),
VecOriginal->end());
}
+
+const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
+ for (referenced_vars_iterator I = referenced_vars_begin(),
+ E = referenced_vars_end();
+ I != E; ++I) {
+ if (I.getCapturedRegion() == R)
+ return I.getOriginalRegion();
+ }
+ return 0;
+}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 0f48d1e1c798..7c0fb14a5c82 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -12,16 +12,17 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -106,12 +107,16 @@ PathDiagnostic::~PathDiagnostic() {}
PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
StringRef bugtype, StringRef verboseDesc,
- StringRef shortDesc, StringRef category)
+ StringRef shortDesc, StringRef category,
+ PathDiagnosticLocation LocationToUnique,
+ const Decl *DeclToUnique)
: DeclWithIssue(declWithIssue),
BugType(StripTrailingDots(bugtype)),
VerboseDesc(StripTrailingDots(verboseDesc)),
ShortDesc(StripTrailingDots(shortDesc)),
Category(StripTrailingDots(category)),
+ UniqueingLoc(LocationToUnique),
+ UniqueingDecl(DeclToUnique),
path(pathImpl) {}
void PathDiagnosticConsumer::anchor() { }
@@ -125,7 +130,7 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() {
}
void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
- llvm::OwningPtr<PathDiagnostic> OwningD(D);
+ OwningPtr<PathDiagnostic> OwningD(D);
if (!D || D->path.empty())
return;
@@ -141,7 +146,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
// Verify that the entire path is from the same FileID.
FileID FID;
const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
- llvm::SmallVector<const PathPieces *, 5> WorkList;
+ SmallVector<const PathPieces *, 5> WorkList;
WorkList.push_back(&D->path);
while (!WorkList.empty()) {
@@ -208,9 +213,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
Diags.InsertNode(OwningD.take());
}
-static llvm::Optional<bool> comparePath(const PathPieces &X,
- const PathPieces &Y);
-static llvm::Optional<bool>
+static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
+static Optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece &X,
const PathDiagnosticControlFlowPiece &Y) {
FullSourceLoc XSL = X.getStartLocation().asLocation();
@@ -221,18 +225,16 @@ compareControlFlow(const PathDiagnosticControlFlowPiece &X,
FullSourceLoc YEL = Y.getEndLocation().asLocation();
if (XEL != YEL)
return XEL.isBeforeInTranslationUnitThan(YEL);
- return llvm::Optional<bool>();
+ return None;
}
-static llvm::Optional<bool>
-compareMacro(const PathDiagnosticMacroPiece &X,
- const PathDiagnosticMacroPiece &Y) {
+static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
+ const PathDiagnosticMacroPiece &Y) {
return comparePath(X.subPieces, Y.subPieces);
}
-static llvm::Optional<bool>
-compareCall(const PathDiagnosticCallPiece &X,
- const PathDiagnosticCallPiece &Y) {
+static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
+ const PathDiagnosticCallPiece &Y) {
FullSourceLoc X_CEL = X.callEnter.asLocation();
FullSourceLoc Y_CEL = Y.callEnter.asLocation();
if (X_CEL != Y_CEL)
@@ -248,8 +250,8 @@ compareCall(const PathDiagnosticCallPiece &X,
return comparePath(X.path, Y.path);
}
-static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
- const PathDiagnosticPiece &Y) {
+static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
+ const PathDiagnosticPiece &Y) {
if (X.getKind() != Y.getKind())
return X.getKind() < Y.getKind();
@@ -281,7 +283,7 @@ static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
cast<PathDiagnosticControlFlowPiece>(Y));
case clang::ento::PathDiagnosticPiece::Event:
- return llvm::Optional<bool>();
+ return None;
case clang::ento::PathDiagnosticPiece::Macro:
return compareMacro(cast<PathDiagnosticMacroPiece>(X),
cast<PathDiagnosticMacroPiece>(Y));
@@ -292,16 +294,15 @@ static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
llvm_unreachable("all cases handled");
}
-static llvm::Optional<bool> comparePath(const PathPieces &X,
- const PathPieces &Y) {
+static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
if (X.size() != Y.size())
return X.size() < Y.size();
for (unsigned i = 0, n = X.size(); i != n; ++i) {
- llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]);
+ Optional<bool> b = comparePiece(*X[i], *Y[i]);
if (b.hasValue())
return b.getValue();
}
- return llvm::Optional<bool>();
+ return None;
}
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
@@ -339,7 +340,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
if (*XI != *YI)
return (*XI) < (*YI);
}
- llvm::Optional<bool> b = comparePath(X.path, Y.path);
+ Optional<bool> b = comparePath(X.path, Y.path);
assert(b.hasValue());
return b.getValue();
}
@@ -475,18 +476,16 @@ getLocationForCaller(const StackFrameContext *SFC,
CFGElement Source = Block[SFC->getIndex()];
switch (Source.getKind()) {
- case CFGElement::Invalid:
- llvm_unreachable("Invalid CFGElement");
case CFGElement::Statement:
- return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
+ return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
SM, CallerCtx);
case CFGElement::Initializer: {
- const CFGInitializer &Init = cast<CFGInitializer>(Source);
+ const CFGInitializer &Init = Source.castAs<CFGInitializer>();
return PathDiagnosticLocation(Init.getInitializer()->getInit(),
SM, CallerCtx);
}
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
+ const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
SM, CallerCtx);
}
@@ -582,27 +581,27 @@ PathDiagnosticLocation
const SourceManager &SMng) {
const Stmt* S = 0;
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
const CFGBlock *BSrc = BE->getSrc();
S = BSrc->getTerminatorCondition();
- }
- else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+ } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
S = SP->getStmt();
- }
- else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
+ if (P.getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
+ } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
+ return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
+ SMng);
+ } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
return PathDiagnosticLocation(PIE->getLocation(), SMng);
- }
- else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
return getLocationForCaller(CE->getCalleeContext(),
CE->getLocationContext(),
SMng);
- }
- else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) {
+ } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
return getLocationForCaller(CEE->getCalleeContext(),
CEE->getLocationContext(),
SMng);
- }
- else {
+ } else {
llvm_unreachable("Unexpected ProgramPoint");
}
@@ -619,12 +618,16 @@ PathDiagnosticLocation
while (NI) {
ProgramPoint P = NI->getLocation();
- if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
+ if (Optional<StmtPoint> PS = P.getAs<StmtPoint>()) {
S = PS->getStmt();
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
+ if (P.getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SM,
+ NI->getLocationContext());
+ break;
+ } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
S = BE->getSrc()->getTerminator();
- if (S)
break;
+ }
NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
}
@@ -777,48 +780,129 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
}
+static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
+ StringRef Prefix = StringRef()) {
+ if (!D->getIdentifier())
+ return;
+ Out << Prefix << '\'' << *D << '\'';
+}
+
+static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
+ bool ExtendedDescription,
+ StringRef Prefix = StringRef()) {
+ if (!D)
+ return false;
+
+ if (isa<BlockDecl>(D)) {
+ if (ExtendedDescription)
+ Out << Prefix << "anonymous block";
+ return ExtendedDescription;
+ }
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ Out << Prefix;
+ if (ExtendedDescription && !MD->isUserProvided()) {
+ if (MD->isExplicitlyDefaulted())
+ Out << "defaulted ";
+ else
+ Out << "implicit ";
+ }
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (CD->isDefaultConstructor())
+ Out << "default ";
+ else if (CD->isCopyConstructor())
+ Out << "copy ";
+ else if (CD->isMoveConstructor())
+ Out << "move ";
+
+ Out << "constructor";
+ describeClass(Out, MD->getParent(), " for ");
+
+ } else if (isa<CXXDestructorDecl>(MD)) {
+ if (!MD->isUserProvided()) {
+ Out << "destructor";
+ describeClass(Out, MD->getParent(), " for ");
+ } else {
+ // Use ~Foo for explicitly-written destructors.
+ Out << "'" << *MD << "'";
+ }
+
+ } else if (MD->isCopyAssignmentOperator()) {
+ Out << "copy assignment operator";
+ describeClass(Out, MD->getParent(), " for ");
+
+ } else if (MD->isMoveAssignmentOperator()) {
+ Out << "move assignment operator";
+ describeClass(Out, MD->getParent(), " for ");
+
+ } else {
+ if (MD->getParent()->getIdentifier())
+ Out << "'" << *MD->getParent() << "::" << *MD << "'";
+ else
+ Out << "'" << *MD << "'";
+ }
+
+ return true;
+ }
+
+ Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
+ return true;
+}
+
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterEvent() const {
if (!Callee)
return 0;
+
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
- if (isa<BlockDecl>(Callee))
- Out << "Calling anonymous block";
- else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
- Out << "Calling '" << *ND << "'";
- StringRef msg = Out.str();
- if (msg.empty())
- return 0;
- return new PathDiagnosticEventPiece(callEnter, msg);
+
+ Out << "Calling ";
+ describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
+
+ assert(callEnter.asLocation().isValid());
+ return new PathDiagnosticEventPiece(callEnter, Out.str());
}
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
+ if (!callEnterWithin.asLocation().isValid())
+ return 0;
+ if (Callee->isImplicit())
+ return 0;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
+ if (MD->isDefaulted())
+ return 0;
+
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
- if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
- Out << "Entered call from '" << *ND << "'";
- else
- Out << "Entered call";
- StringRef msg = Out.str();
- if (msg.empty())
- return 0;
- return new PathDiagnosticEventPiece(callEnterWithin, msg);
+
+ Out << "Entered call";
+ describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
+
+ return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
}
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallExitEvent() const {
if (NoExit)
return 0;
+
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
- if (!CallStackMessage.empty())
+
+ if (!CallStackMessage.empty()) {
Out << CallStackMessage;
- else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
- Out << "Returning from '" << *ND << "'";
- else
- Out << "Returning to caller";
+ } else {
+ bool DidDescribe = describeCodeDecl(Out, Callee,
+ /*ExtendedDescription=*/false,
+ "Returning from ");
+ if (!DidDescribe)
+ Out << "Returning to caller";
+ }
+
+ assert(callReturn.asLocation().isValid());
return new PathDiagnosticEventPiece(callReturn, Out.str());
}
@@ -910,11 +994,10 @@ StackHintGenerator::~StackHintGenerator() {}
std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
ProgramPoint P = N->getLocation();
- const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
- assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
+ CallExitEnd CExit = P.castAs<CallExitEnd>();
// FIXME: Use CallEvent to abstract this over all calls.
- const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
+ const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
if (!CE)
return "";
@@ -937,7 +1020,7 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
}
// Check if the parameter is a pointer to the symbol.
- if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
+ if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
SVal PSV = State->getSVal(Reg->getRegion());
SymbolRef AS = PSV.getAsLocSymbol();
if (AS == Sym) {
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 17ef4cf571e8..7dcc088d18a6 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -11,16 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Casting.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#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;
@@ -33,7 +34,9 @@ namespace {
const LangOptions &LangOpts;
const bool SupportsCrossFileDiagnostics;
public:
- PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
+ PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& prefix,
+ const LangOptions &LangOpts,
bool supportsMultipleFiles);
virtual ~PlistDiagnostics() {}
@@ -54,22 +57,28 @@ namespace {
};
} // end anonymous namespace
-PlistDiagnostics::PlistDiagnostics(const std::string& output,
+PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& output,
const LangOptions &LO,
bool supportsMultipleFiles)
- : OutputFile(output), LangOpts(LO),
+ : OutputFile(output),
+ LangOpts(LO),
SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
-void ento::createPlistDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string& s,
const Preprocessor &PP) {
- C.push_back(new PlistDiagnostics(s, PP.getLangOpts(), false));
+ C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
+ PP.getLangOpts(), false));
}
-void ento::createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string &s,
const Preprocessor &PP) {
- C.push_back(new PlistDiagnostics(s, PP.getLangOpts(), true));
+ C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
+ PP.getLangOpts(), true));
}
static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V,
@@ -360,7 +369,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
const PathDiagnostic *D = *DI;
- llvm::SmallVector<const PathPieces *, 5> WorkList;
+ SmallVector<const PathPieces *, 5> WorkList;
WorkList.push_back(&D->path);
while (!WorkList.empty()) {
@@ -486,12 +495,32 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the bug hash for issue unique-ing. Currently, it's just an
// offset from the beginning of the function.
if (const Stmt *Body = DeclWithIssue->getBody()) {
- FullSourceLoc Loc(SM->getExpansionLoc(D->getLocation().asLocation()),
+
+ // If the bug uniqueing location exists, use it for the hash.
+ // For example, this ensures that two leaks reported on the same line
+ // will have different issue_hashes and that the hash will identify
+ // the leak location even after code is added between the allocation
+ // site and the end of scope (leak report location).
+ PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
+ if (UPDLoc.isValid()) {
+ FullSourceLoc UL(SM->getExpansionLoc(UPDLoc.asLocation()),
+ *SM);
+ FullSourceLoc UFunL(SM->getExpansionLoc(
+ D->getUniqueingDecl()->getBody()->getLocStart()), *SM);
+ o << " <key>issue_hash</key><string>"
+ << UL.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
+ << "</string>\n";
+
+ // Otherwise, use the location on which the bug is reported.
+ } else {
+ FullSourceLoc L(SM->getExpansionLoc(D->getLocation().asLocation()),
*SM);
- FullSourceLoc FunLoc(SM->getExpansionLoc(Body->getLocStart()), *SM);
- o << " <key>issue_hash</key><integer>"
- << Loc.getExpansionLineNumber() - FunLoc.getExpansionLineNumber()
- << "</integer>\n";
+ FullSourceLoc FunL(SM->getExpansionLoc(Body->getLocStart()), *SM);
+ o << " <key>issue_hash</key><string>"
+ << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
+ << "</string>\n";
+ }
+
}
}
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index b49a11e64214..bff2242925e5 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h"
#include "llvm/Support/raw_ostream.h"
@@ -132,7 +132,7 @@ ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const
ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
ProgramStateManager &Mgr = getStateManager();
- const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion();
+ const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
ProgramStateRef new_state = makeWithStore(newStore);
return Mgr.getOwningEngine() ?
@@ -140,46 +140,108 @@ ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
new_state;
}
+typedef ArrayRef<const MemRegion *> RegionList;
+typedef ArrayRef<SVal> ValueList;
+
ProgramStateRef
-ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions,
+ProgramState::invalidateRegions(RegionList Regions,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols *IS,
- const CallEvent *Call) const {
+ bool CausedByPointerEscape,
+ InvalidatedSymbols *IS,
+ const CallEvent *Call,
+ RegionList ConstRegions) const {
+ SmallVector<SVal, 8> Values;
+ for (RegionList::const_iterator I = Regions.begin(),
+ End = Regions.end(); I != End; ++I)
+ Values.push_back(loc::MemRegionVal(*I));
+
+ SmallVector<SVal, 8> ConstValues;
+ for (RegionList::const_iterator I = ConstRegions.begin(),
+ End = ConstRegions.end(); I != End; ++I)
+ ConstValues.push_back(loc::MemRegionVal(*I));
+
if (!IS) {
- StoreManager::InvalidatedSymbols invalidated;
- return invalidateRegionsImpl(Regions, E, Count, LCtx,
- invalidated, Call);
+ InvalidatedSymbols invalidated;
+ return invalidateRegionsImpl(Values, E, Count, LCtx,
+ CausedByPointerEscape,
+ invalidated, Call, ConstValues);
}
- return invalidateRegionsImpl(Regions, E, Count, LCtx, *IS, Call);
+ return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
+ *IS, Call, ConstValues);
}
-ProgramStateRef
-ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+ProgramStateRef
+ProgramState::invalidateRegions(ValueList Values,
+ const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
+ bool CausedByPointerEscape,
+ InvalidatedSymbols *IS,
+ const CallEvent *Call,
+ ValueList ConstValues) const {
+ if (!IS) {
+ InvalidatedSymbols invalidated;
+ return invalidateRegionsImpl(Values, E, Count, LCtx,
+ CausedByPointerEscape,
+ invalidated, Call, ConstValues);
+ }
+ return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
+ *IS, Call, ConstValues);
+}
+
+ProgramStateRef
+ProgramState::invalidateRegionsImpl(ValueList Values,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols &IS,
- const CallEvent *Call) const {
+ bool CausedByPointerEscape,
+ InvalidatedSymbols &IS,
+ const CallEvent *Call,
+ ValueList ConstValues) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
-
- if (Eng && Eng->wantsRegionChangeUpdate(this)) {
+ InvalidatedSymbols ConstIS;
+
+ if (Eng) {
+ StoreManager::InvalidatedRegions TopLevelInvalidated;
+ StoreManager::InvalidatedRegions TopLevelConstInvalidated;
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &newStore
- = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
- Call, &Invalidated);
+ = Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
+ E, Count, LCtx, Call,
+ IS, ConstIS,
+ &TopLevelInvalidated,
+ &TopLevelConstInvalidated,
+ &Invalidated);
+
ProgramStateRef newState = makeWithStore(newStore);
- return Eng->processRegionChanges(newState, &IS, Regions, Invalidated, Call);
+
+ if (CausedByPointerEscape) {
+ newState = Eng->notifyCheckersOfPointerEscape(newState, &IS,
+ TopLevelInvalidated,
+ Invalidated, Call);
+ if (!ConstValues.empty()) {
+ StoreManager::InvalidatedRegions Empty;
+ newState = Eng->notifyCheckersOfPointerEscape(newState, &ConstIS,
+ TopLevelConstInvalidated,
+ Empty, Call,
+ true);
+ }
+ }
+
+ return Eng->processRegionChanges(newState, &IS,
+ TopLevelInvalidated, Invalidated,
+ Call);
}
const StoreRef &newStore =
- Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
- Call, NULL);
+ Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
+ E, Count, LCtx, Call,
+ IS, ConstIS, NULL, NULL, NULL);
return makeWithStore(newStore);
}
ProgramStateRef ProgramState::killBinding(Loc LV) const {
- assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
+ assert(!LV.getAs<loc::MemRegionVal>() && "Use invalidateRegion instead.");
Store OldStore = getStore();
const StoreRef &newStore =
@@ -243,7 +305,7 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
// not unsigned.
const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int);
- if (isa<Loc>(V))
+ if (V.getAs<Loc>())
return loc::ConcreteInt(NewV);
else
return nonloc::ConcreteInt(NewV);
@@ -268,23 +330,6 @@ ProgramStateRef ProgramState::BindExpr(const Stmt *S,
return getStateManager().getPersistentState(NewSt);
}
-ProgramStateRef
-ProgramState::bindExprAndLocation(const Stmt *S, const LocationContext *LCtx,
- SVal location,
- SVal V) const {
- Environment NewEnv =
- getStateManager().EnvMgr.bindExprAndLocation(Env,
- EnvironmentEntry(S, LCtx),
- location, V);
-
- if (NewEnv == Env)
- return this;
-
- ProgramState NewSt = *this;
- NewSt.Env = NewEnv;
- return getStateManager().getPersistentState(NewSt);
-}
-
ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
bool Assumption,
@@ -308,28 +353,41 @@ ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
// Adjust the index.
SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add,
- cast<NonLoc>(Idx), Min, indexTy);
+ Idx.castAs<NonLoc>(), Min, indexTy);
if (newIdx.isUnknownOrUndef())
return this;
// Adjust the upper bound.
SVal newBound =
- svalBuilder.evalBinOpNN(this, BO_Add, cast<NonLoc>(UpperBound),
+ svalBuilder.evalBinOpNN(this, BO_Add, UpperBound.castAs<NonLoc>(),
Min, indexTy);
if (newBound.isUnknownOrUndef())
return this;
// Build the actual comparison.
- SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT,
- cast<NonLoc>(newIdx), cast<NonLoc>(newBound),
- Ctx.IntTy);
+ SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT, newIdx.castAs<NonLoc>(),
+ newBound.castAs<NonLoc>(), Ctx.IntTy);
if (inBound.isUnknownOrUndef())
return this;
// Finally, let the constraint manager take care of it.
ConstraintManager &CM = SM.getConstraintManager();
- return CM.assume(this, cast<DefinedSVal>(inBound), Assumption);
+ return CM.assume(this, inBound.castAs<DefinedSVal>(), Assumption);
+}
+
+ConditionTruthVal ProgramState::isNull(SVal V) const {
+ if (V.isZeroConstant())
+ return true;
+
+ if (V.isConstant())
+ return false;
+
+ SymbolRef Sym = V.getAsSymbol();
+ if (!Sym)
+ return ConditionTruthVal();
+
+ return getStateManager().ConstraintMgr->isNull(this, Sym);
}
ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
@@ -516,13 +574,22 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
}
bool ScanReachableSymbols::scan(SVal val) {
- if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
+ if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())
return scan(X->getRegion());
- if (nonloc::LazyCompoundVal *X = dyn_cast<nonloc::LazyCompoundVal>(&val))
- return scan(X->getRegion());
+ if (Optional<nonloc::LazyCompoundVal> X =
+ val.getAs<nonloc::LazyCompoundVal>()) {
+ StoreManager &StoreMgr = state->getStateManager().getStoreManager();
+ // FIXME: We don't really want to use getBaseRegion() here because pointer
+ // arithmetic doesn't apply, but scanReachableSymbols only accepts base
+ // regions right now.
+ if (!StoreMgr.scanReachableSymbols(X->getStore(),
+ X->getRegion()->getBaseRegion(),
+ *this))
+ return false;
+ }
- if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
+ if (Optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
return scan(X->getLoc());
if (SymbolRef Sym = val.getAsSymbol())
@@ -531,7 +598,7 @@ bool ScanReachableSymbols::scan(SVal val) {
if (const SymExpr *Sym = val.getAsSymbolicExpression())
return scan(Sym);
- if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val))
+ if (Optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())
return scan(*X);
return true;
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 411094bc1d14..3606e099cec2 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -16,9 +16,9 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -153,8 +153,8 @@ private:
// The function returns false if the described range is entirely outside
// the range of values for the associated symbol.
APSIntType Type(getMinValue());
- APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower);
- APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper);
+ APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower, true);
+ APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper, true);
switch (LowerTest) {
case APSIntType::RTR_Below:
@@ -285,8 +285,8 @@ namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(ProgramStateRef state, SymbolRef sym);
public:
- RangeConstraintManager(SubEngine *subengine, BasicValueFactory &BVF)
- : SimpleConstraintManager(subengine, BVF) {}
+ RangeConstraintManager(SubEngine *subengine, SValBuilder &SVB)
+ : SimpleConstraintManager(subengine, SVB) {}
ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
@@ -328,7 +328,7 @@ private:
ConstraintManager *
ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
- return new RangeConstraintManager(Eng, StMgr.getBasicVals());
+ return new RangeConstraintManager(Eng, StMgr.getSValBuilder());
}
const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
@@ -419,7 +419,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- if (AdjustmentType.testInRange(Int) != APSIntType::RTR_Within)
+ if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
return St;
llvm::APSInt Lower = AdjustmentType.convert(Int) - Adjustment;
@@ -439,7 +439,7 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- if (AdjustmentType.testInRange(Int) != APSIntType::RTR_Within)
+ if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
return NULL;
// [Int-Adjustment, Int-Adjustment]
@@ -454,7 +454,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return NULL;
case APSIntType::RTR_Within:
@@ -483,7 +483,7 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return St;
case APSIntType::RTR_Within:
@@ -512,7 +512,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return St;
case APSIntType::RTR_Within:
@@ -541,7 +541,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return NULL;
case APSIntType::RTR_Within:
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index aed994df4110..0f4a6824a24a 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -14,14 +14,15 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/Optional.h"
@@ -29,7 +30,6 @@
using namespace clang;
using namespace ento;
-using llvm::Optional;
//===----------------------------------------------------------------------===//
// Representation of binding keys.
@@ -45,11 +45,15 @@ private:
llvm::PointerIntPair<const MemRegion *, 2> P;
uint64_t Data;
- explicit BindingKey(const MemRegion *r, const MemRegion *Base, Kind k)
+ /// Create a key for a binding to region \p r, which has a symbolic offset
+ /// from region \p Base.
+ explicit BindingKey(const SubRegion *r, const SubRegion *Base, Kind k)
: P(r, k | Symbolic), Data(reinterpret_cast<uintptr_t>(Base)) {
assert(r && Base && "Must have known regions.");
assert(getConcreteOffsetRegion() == Base && "Failed to store base region");
}
+
+ /// Create a key for a binding at \p offset from base region \p r.
explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
: P(r, k), Data(offset) {
assert(r && "Must have known regions.");
@@ -67,9 +71,9 @@ public:
return Data;
}
- const MemRegion *getConcreteOffsetRegion() const {
+ const SubRegion *getConcreteOffsetRegion() const {
assert(hasSymbolicOffset());
- return reinterpret_cast<const MemRegion *>(static_cast<uintptr_t>(Data));
+ return reinterpret_cast<const SubRegion *>(static_cast<uintptr_t>(Data));
}
const MemRegion *getBaseRegion() const {
@@ -105,7 +109,7 @@ public:
BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
const RegionOffset &RO = R->getAsOffset();
if (RO.hasSymbolicOffset())
- return BindingKey(R, RO.getRegion(), k);
+ return BindingKey(cast<SubRegion>(R), cast<SubRegion>(RO.getRegion()), k);
return BindingKey(RO.getRegion(), RO.getOffset(), k);
}
@@ -120,6 +124,11 @@ namespace llvm {
<< ')';
return os;
}
+
+ template <typename T> struct isPodLike;
+ template <> struct isPodLike<BindingKey> {
+ static const bool value = true;
+ };
} // end llvm namespace
void BindingKey::dump() const {
@@ -130,8 +139,156 @@ void BindingKey::dump() const {
// Actual Store type.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<BindingKey, SVal> ClusterBindings;
-typedef llvm::ImmutableMap<const MemRegion *, ClusterBindings> RegionBindings;
+typedef llvm::ImmutableMap<BindingKey, SVal> ClusterBindings;
+typedef llvm::ImmutableMapRef<BindingKey, SVal> ClusterBindingsRef;
+typedef std::pair<BindingKey, SVal> BindingPair;
+
+typedef llvm::ImmutableMap<const MemRegion *, ClusterBindings>
+ RegionBindings;
+
+namespace {
+class RegionBindingsRef : public llvm::ImmutableMapRef<const MemRegion *,
+ ClusterBindings> {
+ ClusterBindings::Factory &CBFactory;
+public:
+ typedef llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>
+ ParentTy;
+
+ RegionBindingsRef(ClusterBindings::Factory &CBFactory,
+ const RegionBindings::TreeTy *T,
+ RegionBindings::TreeTy::Factory *F)
+ : llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>(T, F),
+ CBFactory(CBFactory) {}
+
+ RegionBindingsRef(const ParentTy &P, ClusterBindings::Factory &CBFactory)
+ : llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>(P),
+ CBFactory(CBFactory) {}
+
+ RegionBindingsRef add(key_type_ref K, data_type_ref D) const {
+ return RegionBindingsRef(static_cast<const ParentTy*>(this)->add(K, D),
+ CBFactory);
+ }
+
+ RegionBindingsRef remove(key_type_ref K) const {
+ return RegionBindingsRef(static_cast<const ParentTy*>(this)->remove(K),
+ CBFactory);
+ }
+
+ RegionBindingsRef addBinding(BindingKey K, SVal V) const;
+
+ RegionBindingsRef addBinding(const MemRegion *R,
+ BindingKey::Kind k, SVal V) const;
+
+ RegionBindingsRef &operator=(const RegionBindingsRef &X) {
+ *static_cast<ParentTy*>(this) = X;
+ return *this;
+ }
+
+ const SVal *lookup(BindingKey K) const;
+ const SVal *lookup(const MemRegion *R, BindingKey::Kind k) const;
+ const ClusterBindings *lookup(const MemRegion *R) const {
+ return static_cast<const ParentTy*>(this)->lookup(R);
+ }
+
+ RegionBindingsRef removeBinding(BindingKey K);
+
+ RegionBindingsRef removeBinding(const MemRegion *R,
+ BindingKey::Kind k);
+
+ RegionBindingsRef removeBinding(const MemRegion *R) {
+ return removeBinding(R, BindingKey::Direct).
+ removeBinding(R, BindingKey::Default);
+ }
+
+ Optional<SVal> getDirectBinding(const MemRegion *R) const;
+
+ /// getDefaultBinding - Returns an SVal* representing an optional default
+ /// binding associated with a region and its subregions.
+ Optional<SVal> getDefaultBinding(const MemRegion *R) const;
+
+ /// Return the internal tree as a Store.
+ Store asStore() const {
+ return asImmutableMap().getRootWithoutRetain();
+ }
+
+ void dump(raw_ostream &OS, const char *nl) const {
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ const ClusterBindings &Cluster = I.getData();
+ for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
+ CI != CE; ++CI) {
+ OS << ' ' << CI.getKey() << " : " << CI.getData() << nl;
+ }
+ OS << nl;
+ }
+ }
+
+ LLVM_ATTRIBUTE_USED void dump() const {
+ dump(llvm::errs(), "\n");
+ }
+};
+} // end anonymous namespace
+
+typedef const RegionBindingsRef& RegionBindingsConstRef;
+
+Optional<SVal> RegionBindingsRef::getDirectBinding(const MemRegion *R) const {
+ return Optional<SVal>::create(lookup(R, BindingKey::Direct));
+}
+
+Optional<SVal> RegionBindingsRef::getDefaultBinding(const MemRegion *R) const {
+ if (R->isBoundable())
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R))
+ if (TR->getValueType()->isUnionType())
+ return UnknownVal();
+
+ return Optional<SVal>::create(lookup(R, BindingKey::Default));
+}
+
+RegionBindingsRef RegionBindingsRef::addBinding(BindingKey K, SVal V) const {
+ const MemRegion *Base = K.getBaseRegion();
+
+ const ClusterBindings *ExistingCluster = lookup(Base);
+ ClusterBindings Cluster = (ExistingCluster ? *ExistingCluster
+ : CBFactory.getEmptyMap());
+
+ ClusterBindings NewCluster = CBFactory.add(Cluster, K, V);
+ return add(Base, NewCluster);
+}
+
+
+RegionBindingsRef RegionBindingsRef::addBinding(const MemRegion *R,
+ BindingKey::Kind k,
+ SVal V) const {
+ return addBinding(BindingKey::Make(R, k), V);
+}
+
+const SVal *RegionBindingsRef::lookup(BindingKey K) const {
+ const ClusterBindings *Cluster = lookup(K.getBaseRegion());
+ if (!Cluster)
+ return 0;
+ return Cluster->lookup(K);
+}
+
+const SVal *RegionBindingsRef::lookup(const MemRegion *R,
+ BindingKey::Kind k) const {
+ return lookup(BindingKey::Make(R, k));
+}
+
+RegionBindingsRef RegionBindingsRef::removeBinding(BindingKey K) {
+ const MemRegion *Base = K.getBaseRegion();
+ const ClusterBindings *Cluster = lookup(Base);
+ if (!Cluster)
+ return *this;
+
+ ClusterBindings NewCluster = CBFactory.remove(*Cluster, K);
+ if (NewCluster.isEmpty())
+ return remove(Base);
+ return add(Base, NewCluster);
+}
+
+RegionBindingsRef RegionBindingsRef::removeBinding(const MemRegion *R,
+ BindingKey::Kind k){
+ return removeBinding(BindingKey::Make(R, k));
+}
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -161,26 +318,38 @@ public:
//===----------------------------------------------------------------------===//
namespace {
+class invalidateRegionsWorker;
class RegionStoreManager : public StoreManager {
+public:
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
- ClusterBindings::Factory CBFactory;
+ mutable ClusterBindings::Factory CBFactory;
+
+ typedef std::vector<SVal> SValListTy;
+private:
+ typedef llvm::DenseMap<const LazyCompoundValData *,
+ SValListTy> LazyBindingsMapTy;
+ LazyBindingsMapTy LazyBindingsMap;
+
+ /// \brief A helper used to populate the work list with the given set of
+ /// regions.
+ void populateWorkList(invalidateRegionsWorker &W,
+ ArrayRef<SVal> Values,
+ bool IsArrayOfConstRegions,
+ InvalidatedRegions *TopLevelRegions);
public:
RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f)
: StoreManager(mgr), Features(f),
RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()) {}
- Optional<SVal> getDirectBinding(RegionBindings B, const MemRegion *R);
- /// getDefaultBinding - Returns an SVal* representing an optional default
- /// binding associated with a region and its subregions.
- Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
/// setImplicitDefaultValue - Set the default binding for the provided
/// MemRegion to the value implicitly defined for compound literals when
/// the value is not specified.
- StoreRef setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
+ RegionBindingsRef setImplicitDefaultValue(RegionBindingsConstRef B,
+ const MemRegion *R, QualType T);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
/// type. 'Array' represents the lvalue of the array being decayed
@@ -197,57 +366,47 @@ public:
//===-------------------------------------------------------------------===//
// Binding values to regions.
//===-------------------------------------------------------------------===//
- RegionBindings invalidateGlobalRegion(MemRegion::Kind K,
- const Expr *Ex,
- unsigned Count,
- const LocationContext *LCtx,
- RegionBindings B,
- InvalidatedRegions *Invalidated);
-
- StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions,
+ RegionBindingsRef invalidateGlobalRegion(MemRegion::Kind K,
+ const Expr *Ex,
+ unsigned Count,
+ const LocationContext *LCtx,
+ RegionBindingsRef B,
+ InvalidatedRegions *Invalidated);
+
+ StoreRef invalidateRegions(Store store,
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- InvalidatedSymbols &IS,
const CallEvent *Call,
- InvalidatedRegions *Invalidated);
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *Invalidated,
+ InvalidatedRegions *InvalidatedTopLevel,
+ InvalidatedRegions *InvalidatedTopLevelConst);
bool scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks);
-public: // Made public for helper classes.
-
- RegionBindings removeSubRegionBindings(RegionBindings B, const SubRegion *R);
-
- RegionBindings addBinding(RegionBindings B, BindingKey K, SVal V);
-
- RegionBindings addBinding(RegionBindings B, const MemRegion *R,
- BindingKey::Kind k, SVal V);
-
- const SVal *lookup(RegionBindings B, BindingKey K);
- const SVal *lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
+ RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B,
+ const SubRegion *R);
- RegionBindings removeBinding(RegionBindings B, BindingKey K);
- RegionBindings removeBinding(RegionBindings B, const MemRegion *R,
- BindingKey::Kind k);
+public: // Part of public interface to class.
- RegionBindings removeBinding(RegionBindings B, const MemRegion *R) {
- return removeBinding(removeBinding(B, R, BindingKey::Direct), R,
- BindingKey::Default);
+ virtual StoreRef Bind(Store store, Loc LV, SVal V) {
+ return StoreRef(bind(getRegionBindings(store), LV, V).asStore(), *this);
}
- RegionBindings removeCluster(RegionBindings B, const MemRegion *R);
-
-public: // Part of public interface to class.
-
- StoreRef Bind(Store store, Loc LV, SVal V);
+ 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) {
- RegionBindings B = GetRegionBindings(store);
- assert(!lookup(B, R, BindingKey::Default));
- assert(!lookup(B, R, BindingKey::Direct));
- return StoreRef(addBinding(B, R, BindingKey::Default, V)
- .getRootWithoutRetain(), *this);
+ RegionBindingsRef B = getRegionBindings(store);
+ assert(!B.lookup(R, BindingKey::Default));
+ assert(!B.lookup(R, BindingKey::Direct));
+ return StoreRef(B.addBinding(R, BindingKey::Default, V)
+ .asImmutableMap()
+ .getRootWithoutRetain(), *this);
}
/// \brief Create a new store that binds a value to a compound literal.
@@ -265,31 +424,37 @@ public: // Part of public interface to class.
const LocationContext *LC, SVal V);
/// BindStruct - Bind a compound value to a structure.
- StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V);
+ RegionBindingsRef bindStruct(RegionBindingsConstRef B,
+ const TypedValueRegion* R, SVal V);
/// BindVector - Bind a compound value to a vector.
- StoreRef BindVector(Store store, const TypedValueRegion* R, SVal V);
+ RegionBindingsRef bindVector(RegionBindingsConstRef B,
+ const TypedValueRegion* R, SVal V);
- StoreRef BindArray(Store store, const TypedValueRegion* R, SVal V);
+ RegionBindingsRef bindArray(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal V);
/// Clears out all bindings in the given region and assigns a new value
/// as a Default binding.
- StoreRef BindAggregate(Store store, const TypedRegion *R, SVal DefaultVal);
+ RegionBindingsRef bindAggregate(RegionBindingsConstRef B,
+ const TypedRegion *R,
+ SVal DefaultVal);
/// \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.
- StoreRef killBinding(Store ST, Loc L);
+ virtual StoreRef killBinding(Store ST, Loc L);
void incrementReferenceCount(Store store) {
- GetRegionBindings(store).manualRetain();
+ 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) {
- GetRegionBindings(store).manualRelease();
+ getRegionBindings(store).manualRelease();
}
bool includedInBindings(Store store, const MemRegion *region) const;
@@ -307,45 +472,64 @@ public: // Part of public interface to class.
/// return undefined
/// else
/// return symbolic
- SVal getBinding(Store store, Loc L, QualType T = QualType());
+ virtual SVal getBinding(Store S, Loc L, QualType T) {
+ return getBinding(getRegionBindings(S), L, T);
+ }
- SVal getBindingForElement(Store store, const ElementRegion *R);
+ SVal getBinding(RegionBindingsConstRef B, Loc L, QualType T = QualType());
- SVal getBindingForField(Store store, const FieldRegion *R);
+ SVal getBindingForElement(RegionBindingsConstRef B, const ElementRegion *R);
- SVal getBindingForObjCIvar(Store store, const ObjCIvarRegion *R);
+ SVal getBindingForField(RegionBindingsConstRef B, const FieldRegion *R);
- SVal getBindingForVar(Store store, const VarRegion *R);
+ SVal getBindingForObjCIvar(RegionBindingsConstRef B, const ObjCIvarRegion *R);
+
+ SVal getBindingForVar(RegionBindingsConstRef B, const VarRegion *R);
SVal getBindingForLazySymbol(const TypedValueRegion *R);
- SVal getBindingForFieldOrElementCommon(Store store, const TypedValueRegion *R,
- QualType Ty, const MemRegion *superR);
+ SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
+ const TypedValueRegion *R,
+ QualType Ty,
+ const MemRegion *superR);
- SVal getLazyBinding(const MemRegion *lazyBindingRegion,
- Store lazyBindingStore);
+ SVal getLazyBinding(const SubRegion *LazyBindingRegion,
+ RegionBindingsRef LazyBinding);
/// Get bindings for the values in a struct and return a CompoundVal, used
/// when doing struct copy:
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal getBindingForStruct(Store store, const TypedValueRegion* R);
-
- SVal getBindingForArray(Store store, const TypedValueRegion* R);
+ SVal getBindingForStruct(RegionBindingsConstRef B, const TypedValueRegion *R);
+ SVal getBindingForArray(RegionBindingsConstRef B, const TypedValueRegion *R);
+ NonLoc createLazyBinding(RegionBindingsConstRef B, const TypedValueRegion *R);
/// Used to lazily generate derived symbols for bindings that are defined
- /// implicitly by default bindings in a super region.
- Optional<SVal> getBindingForDerivedDefaultValue(RegionBindings B,
+ /// implicitly by default bindings in a super region.
+ ///
+ /// Note that callers may need to specially handle LazyCompoundVals, which
+ /// are returned as is in case the caller needs to treat them differently.
+ Optional<SVal> getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
const MemRegion *superR,
const TypedValueRegion *R,
QualType Ty);
- /// Get the state and region whose binding this region R corresponds to.
- std::pair<Store, const MemRegion*>
- GetLazyBinding(RegionBindings B, const MemRegion *R,
- const MemRegion *originalRegion,
- bool includeSuffix = false);
+ /// Get the state and region whose binding this region \p R corresponds to.
+ ///
+ /// If there is no lazy binding for \p R, the returned value will have a null
+ /// \c second. Note that a null pointer can represents a valid Store.
+ std::pair<Store, const SubRegion *>
+ findLazyBinding(RegionBindingsConstRef B, const SubRegion *R,
+ const SubRegion *originalRegion);
+
+ /// Returns the cached set of interesting SVals contained within a lazy
+ /// binding.
+ ///
+ /// The precise value of "interesting" is determined for the purposes of
+ /// RegionStore's internal analysis. It must always contain all regions and
+ /// symbols, but may omit constants and other kinds of SVal.
+ const SValListTy &getInterestingValues(nonloc::LazyCompoundVal LCV);
//===------------------------------------------------------------------===//
// State pruning.
@@ -368,16 +552,18 @@ public: // Part of public interface to class.
// Utility methods.
//===------------------------------------------------------------------===//
- static inline RegionBindings GetRegionBindings(Store store) {
- return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+ RegionBindingsRef getRegionBindings(Store store) const {
+ return RegionBindingsRef(CBFactory,
+ static_cast<const RegionBindings::TreeTy*>(store),
+ RBFactory.getTreeFactory());
}
void print(Store store, raw_ostream &Out, const char* nl,
const char *sep);
void iterBindings(Store store, BindingsHandler& f) {
- RegionBindings B = GetRegionBindings(store);
- for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ RegionBindingsRef B = getRegionBindings(store);
+ for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const ClusterBindings &Cluster = I.getData();
for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
CI != CE; ++CI) {
@@ -422,7 +608,8 @@ template <typename DERIVED>
class ClusterAnalysis {
protected:
typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
- typedef SmallVector<const MemRegion *, 10> WorkList;
+ typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement;
+ typedef SmallVector<WorkListElement, 10> WorkList;
llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
@@ -432,7 +619,7 @@ protected:
ASTContext &Ctx;
SValBuilder &svalBuilder;
- RegionBindings B;
+ RegionBindingsRef B;
const bool includeGlobals;
@@ -442,12 +629,12 @@ protected:
public:
ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr,
- RegionBindings b, const bool includeGlobals)
+ RegionBindingsRef b, const bool includeGlobals)
: RM(rm), Ctx(StateMgr.getContext()),
svalBuilder(StateMgr.getSValBuilder()),
B(b), includeGlobals(includeGlobals) {}
- RegionBindings getRegionBindings() const { return B; }
+ RegionBindingsRef getRegionBindings() const { return B; }
bool isVisited(const MemRegion *R) {
return Visited.count(getCluster(R));
@@ -455,7 +642,8 @@ public:
void GenerateClusters() {
// Scan the entire set of bindings and record the region clusters.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+ for (RegionBindingsRef::iterator RI = B.begin(), RE = B.end();
+ RI != RE; ++RI){
const MemRegion *Base = RI.getKey();
const ClusterBindings &Cluster = RI.getData();
@@ -468,35 +656,35 @@ public:
}
}
- bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) {
+ bool AddToWorkList(WorkListElement E, const ClusterBindings *C) {
if (C && !Visited.insert(C))
return false;
- WL.push_back(R);
+ WL.push_back(E);
return true;
}
- bool AddToWorkList(const MemRegion *R) {
- const MemRegion *baseR = R->getBaseRegion();
- return AddToWorkList(baseR, getCluster(baseR));
+ bool AddToWorkList(const MemRegion *R, bool Flag = false) {
+ const MemRegion *BaseR = R->getBaseRegion();
+ return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR));
}
void RunWorkList() {
while (!WL.empty()) {
- const MemRegion *baseR = WL.pop_back_val();
+ WorkListElement E = WL.pop_back_val();
+ const MemRegion *BaseR = E.getPointer();
- // First visit the cluster.
- if (const ClusterBindings *Cluster = getCluster(baseR))
- static_cast<DERIVED*>(this)->VisitCluster(baseR, *Cluster);
-
- // Next, visit the base region.
- static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR),
+ E.getInt());
}
}
-public:
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitBaseRegion(const MemRegion *baseR) {}
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C) {}
+
+ void VisitCluster(const MemRegion *BaseR, const ClusterBindings *C,
+ bool Flag) {
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, C);
+ }
};
}
@@ -507,7 +695,7 @@ public:
bool RegionStoreManager::scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks) {
assert(R == R->getBaseRegion() && "Should only be called for base regions");
- RegionBindings B = GetRegionBindings(S);
+ RegionBindingsRef B = getRegionBindings(S);
const ClusterBindings *Cluster = B.lookup(R);
if (!Cluster)
@@ -562,98 +750,141 @@ static bool isCompatibleWithFields(BindingKey K, const FieldVector &Fields) {
Fields.begin() - Delta);
}
-RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
- const SubRegion *R) {
- BindingKey SRKey = BindingKey::Make(R, BindingKey::Default);
- const MemRegion *ClusterHead = SRKey.getBaseRegion();
- if (R == ClusterHead) {
- // We can remove an entire cluster's bindings all in one go.
- return RBFactory.remove(B, R);
- }
-
+/// Collects all bindings in \p Cluster that may refer to bindings within
+/// \p Top.
+///
+/// Each binding is a pair whose \c first is the key (a BindingKey) and whose
+/// \c second is the value (an SVal).
+///
+/// The \p IncludeAllDefaultBindings parameter specifies whether to include
+/// default bindings that may extend beyond \p Top itself, e.g. if \p Top is
+/// an aggregate within a larger aggregate with a default binding.
+static void
+collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
+ SValBuilder &SVB, const ClusterBindings &Cluster,
+ const SubRegion *Top, BindingKey TopKey,
+ bool IncludeAllDefaultBindings) {
FieldVector FieldsInSymbolicSubregions;
- bool HasSymbolicOffset = SRKey.hasSymbolicOffset();
- if (HasSymbolicOffset) {
- getSymbolicOffsetFields(SRKey, FieldsInSymbolicSubregions);
- R = cast<SubRegion>(SRKey.getConcreteOffsetRegion());
- SRKey = BindingKey::Make(R, BindingKey::Default);
+ if (TopKey.hasSymbolicOffset()) {
+ getSymbolicOffsetFields(TopKey, FieldsInSymbolicSubregions);
+ Top = cast<SubRegion>(TopKey.getConcreteOffsetRegion());
+ TopKey = BindingKey::Make(Top, BindingKey::Default);
}
- // This assumes the region being invalidated is char-aligned. This isn't
- // true for bitfields, but since bitfields have no subregions they shouldn't
- // be using this function anyway.
+ // Find the length (in bits) of the region being invalidated.
uint64_t Length = UINT64_MAX;
-
- SVal Extent = R->getExtent(svalBuilder);
- if (nonloc::ConcreteInt *ExtentCI = dyn_cast<nonloc::ConcreteInt>(&Extent)) {
+ SVal Extent = Top->getExtent(SVB);
+ if (Optional<nonloc::ConcreteInt> ExtentCI =
+ Extent.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt &ExtentInt = ExtentCI->getValue();
assert(ExtentInt.isNonNegative() || ExtentInt.isUnsigned());
// Extents are in bytes but region offsets are in bits. Be careful!
- Length = ExtentInt.getLimitedValue() * Ctx.getCharWidth();
+ Length = ExtentInt.getLimitedValue() * SVB.getContext().getCharWidth();
+ } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(Top)) {
+ if (FR->getDecl()->isBitField())
+ Length = FR->getDecl()->getBitWidthValue(SVB.getContext());
}
- const ClusterBindings *Cluster = B.lookup(ClusterHead);
- if (!Cluster)
- return B;
-
- ClusterBindings Result = *Cluster;
-
- // It is safe to iterate over the bindings as they are being changed
- // because they are in an ImmutableMap.
- for (ClusterBindings::iterator I = Cluster->begin(), E = Cluster->end();
+ for (ClusterBindings::iterator I = Cluster.begin(), E = Cluster.end();
I != E; ++I) {
BindingKey NextKey = I.getKey();
- if (NextKey.getRegion() == SRKey.getRegion()) {
+ if (NextKey.getRegion() == TopKey.getRegion()) {
// FIXME: This doesn't catch the case where we're really invalidating a
// region with a symbolic offset. Example:
// R: points[i].y
// Next: points[0].x
- if (NextKey.getOffset() > SRKey.getOffset() &&
- NextKey.getOffset() - SRKey.getOffset() < Length) {
+ if (NextKey.getOffset() > TopKey.getOffset() &&
+ NextKey.getOffset() - TopKey.getOffset() < Length) {
// Case 1: The next binding is inside the region we're invalidating.
- // Remove it.
- Result = CBFactory.remove(Result, NextKey);
+ // Include it.
+ Bindings.push_back(*I);
- } else if (NextKey.getOffset() == SRKey.getOffset()) {
+ } else if (NextKey.getOffset() == TopKey.getOffset()) {
// Case 2: The next binding is at the same offset as the region we're
// invalidating. In this case, we need to leave default bindings alone,
// since they may be providing a default value for a regions beyond what
// we're invalidating.
// FIXME: This is probably incorrect; consider invalidating an outer
// struct whose first field is bound to a LazyCompoundVal.
- if (NextKey.isDirect())
- Result = CBFactory.remove(Result, NextKey);
+ if (IncludeAllDefaultBindings || NextKey.isDirect())
+ Bindings.push_back(*I);
}
-
+
} else if (NextKey.hasSymbolicOffset()) {
const MemRegion *Base = NextKey.getConcreteOffsetRegion();
- if (R->isSubRegionOf(Base)) {
+ if (Top->isSubRegionOf(Base)) {
// Case 3: The next key is symbolic and we just changed something within
// its concrete region. We don't know if the binding is still valid, so
- // we'll be conservative and remove it.
- if (NextKey.isDirect())
+ // we'll be conservative and include it.
+ if (IncludeAllDefaultBindings || NextKey.isDirect())
if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
- Result = CBFactory.remove(Result, NextKey);
+ Bindings.push_back(*I);
} else if (const SubRegion *BaseSR = dyn_cast<SubRegion>(Base)) {
// Case 4: The next key is symbolic, but we changed a known
- // super-region. In this case the binding is certainly no longer valid.
- if (R == Base || BaseSR->isSubRegionOf(R))
+ // super-region. In this case the binding is certainly included.
+ if (Top == Base || BaseSR->isSubRegionOf(Top))
if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
- Result = CBFactory.remove(Result, NextKey);
+ Bindings.push_back(*I);
}
}
}
+}
+
+static void
+collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
+ SValBuilder &SVB, const ClusterBindings &Cluster,
+ const SubRegion *Top, bool IncludeAllDefaultBindings) {
+ collectSubRegionBindings(Bindings, SVB, Cluster, Top,
+ BindingKey::Make(Top, BindingKey::Default),
+ IncludeAllDefaultBindings);
+}
+
+RegionBindingsRef
+RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B,
+ const SubRegion *Top) {
+ BindingKey TopKey = BindingKey::Make(Top, BindingKey::Default);
+ const MemRegion *ClusterHead = TopKey.getBaseRegion();
+
+ if (Top == ClusterHead) {
+ // We can remove an entire cluster's bindings all in one go.
+ return B.remove(Top);
+ }
+
+ const ClusterBindings *Cluster = B.lookup(ClusterHead);
+ if (!Cluster) {
+ // If we're invalidating a region with a symbolic offset, we need to make
+ // sure we don't treat the base region as uninitialized anymore.
+ if (TopKey.hasSymbolicOffset()) {
+ const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
+ return B.addBinding(Concrete, BindingKey::Default, UnknownVal());
+ }
+ return B;
+ }
+
+ SmallVector<BindingPair, 32> Bindings;
+ collectSubRegionBindings(Bindings, svalBuilder, *Cluster, Top, TopKey,
+ /*IncludeAllDefaultBindings=*/false);
+
+ ClusterBindingsRef Result(*Cluster, CBFactory);
+ for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(),
+ E = Bindings.end();
+ I != E; ++I)
+ Result = Result.remove(I->first);
// If we're invalidating a region with a symbolic offset, we need to make sure
// we don't treat the base region as uninitialized anymore.
- // FIXME: This isn't very precise; see the example in the loop.
- if (HasSymbolicOffset)
- Result = CBFactory.add(Result, SRKey, UnknownVal());
+ // FIXME: This isn't very precise; see the example in
+ // collectSubRegionBindings.
+ if (TopKey.hasSymbolicOffset()) {
+ const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
+ Result = Result.add(BindingKey::Make(Concrete, BindingKey::Default),
+ UnknownVal());
+ }
if (Result.isEmpty())
- return RBFactory.remove(B, ClusterHead);
- return RBFactory.add(B, ClusterHead, Result);
+ return B.remove(ClusterHead);
+ return B.add(ClusterHead, Result.asImmutableMap());
}
namespace {
@@ -662,24 +893,26 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
const Expr *Ex;
unsigned Count;
const LocationContext *LCtx;
- StoreManager::InvalidatedSymbols &IS;
+ InvalidatedSymbols &IS;
+ InvalidatedSymbols &ConstIS;
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
ProgramStateManager &stateMgr,
- RegionBindings b,
+ RegionBindingsRef b,
const Expr *ex, unsigned count,
const LocationContext *lctx,
- StoreManager::InvalidatedSymbols &is,
+ InvalidatedSymbols &is,
+ InvalidatedSymbols &inConstIS,
StoreManager::InvalidatedRegions *r,
bool includeGlobals)
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
- Ex(ex), Count(count), LCtx(lctx), IS(is), Regions(r) {}
+ Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitBaseRegion(const MemRegion *baseR);
-
-private:
+ /// \param IsConst Specifies if the region we are invalidating is constant.
+ /// If it is, we invalidate all subregions, but not the base region itself.
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C,
+ bool IsConst);
void VisitBinding(SVal V);
};
}
@@ -695,43 +928,30 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
}
// Is it a LazyCompoundVal? All references get invalidated as well.
- if (const nonloc::LazyCompoundVal *LCS =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
- const MemRegion *LazyR = LCS->getRegion();
- RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+ const RegionStoreManager::SValListTy &Vals = RM.getInterestingValues(*LCS);
- // FIXME: This should not have to walk all bindings in the old store.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
- const ClusterBindings &Cluster = RI.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- BindingKey K = CI.getKey();
- if (const SubRegion *BaseR = dyn_cast<SubRegion>(K.getRegion())) {
- if (BaseR == LazyR)
- VisitBinding(CI.getData());
- else if (K.hasSymbolicOffset() && BaseR->isSubRegionOf(LazyR))
- VisitBinding(CI.getData());
- }
- }
- }
+ for (RegionStoreManager::SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end();
+ I != E; ++I)
+ VisitBinding(*I);
return;
}
}
-void invalidateRegionsWorker::VisitCluster(const MemRegion *BaseR,
- const ClusterBindings &C) {
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
- VisitBinding(I.getData());
-
- B = RM.removeCluster(B, BaseR);
-}
+void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
+ const ClusterBindings *C,
+ bool IsConst) {
+ if (C) {
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
+ VisitBinding(I.getData());
-void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
- // Symbolic region? Mark that symbol touched by the invalidation.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
- IS.insert(SR->getSymbol());
+ if (!IsConst)
+ B = B.remove(baseR);
+ }
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
@@ -739,7 +959,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
for (BlockDataRegion::referenced_vars_iterator
BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
BI != BE; ++BI) {
- const VarRegion *VR = *BI;
+ const VarRegion *VR = BI.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) {
AddToWorkList(VR);
@@ -750,9 +970,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// invalidate that region. This is because a block may capture
// a pointer value, but the thing pointed by that pointer may
// get invalidated.
- Store store = B.getRootWithoutRetain();
- SVal V = RM.getBinding(store, loc::MemRegionVal(VR));
- if (const Loc *L = dyn_cast<Loc>(&V)) {
+ SVal V = RM.getBinding(B, loc::MemRegionVal(VR));
+ if (Optional<Loc> L = V.getAs<Loc>()) {
if (const MemRegion *LR = L->getAsRegion())
AddToWorkList(LR);
}
@@ -761,6 +980,20 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
return;
}
+ // Symbolic region?
+ SymbolRef RegionSym = 0;
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ RegionSym = SR->getSymbol();
+
+ if (IsConst) {
+ // Mark that symbol touched by the invalidation.
+ ConstIS.insert(RegionSym);
+ return;
+ }
+
+ // Mark that symbol touched by the invalidation.
+ IS.insert(RegionSym);
+
// Otherwise, we have a normal data region. Record that we touched the region.
if (Regions)
Regions->push_back(baseR);
@@ -770,7 +1003,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V =
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
- B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -786,7 +1019,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
Ctx.IntTy, Count);
- B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -795,7 +1028,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
DefinedOrUnknownSVal V =
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
AT->getElementType(), Count);
- B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -804,7 +1037,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// If the region is a global and we are invalidating all globals,
// just erase the entry. This causes all globals to be lazily
// symbolicated from the same base symbol.
- B = RM.removeBinding(B, baseR);
+ B = B.removeBinding(baseR);
return;
}
@@ -812,15 +1045,16 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
T,Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = RM.addBinding(B, baseR, BindingKey::Direct, V);
+ B = B.addBinding(baseR, BindingKey::Direct, V);
}
-RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
- const Expr *Ex,
- unsigned Count,
- const LocationContext *LCtx,
- RegionBindings B,
- InvalidatedRegions *Invalidated) {
+RegionBindingsRef
+RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
+ const Expr *Ex,
+ unsigned Count,
+ const LocationContext *LCtx,
+ RegionBindingsRef B,
+ InvalidatedRegions *Invalidated) {
// Bind the globals memory space to a new symbol that we will use to derive
// the bindings for all globals.
const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K);
@@ -828,8 +1062,8 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
/* type does not matter */ Ctx.IntTy,
Count);
- B = removeBinding(B, GS);
- B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
+ B = B.removeBinding(GS)
+ .addBinding(BindingKey::Make(GS, BindingKey::Default), V);
// Even if there are no bindings in the global scope, we still need to
// record that we touched it.
@@ -839,47 +1073,82 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
return B;
}
-StoreRef RegionStoreManager::invalidateRegions(Store store,
- ArrayRef<const MemRegion *> Regions,
- const Expr *Ex, unsigned Count,
- const LocationContext *LCtx,
- InvalidatedSymbols &IS,
- const CallEvent *Call,
- InvalidatedRegions *Invalidated) {
- invalidateRegionsWorker W(*this, StateMgr,
- RegionStoreManager::GetRegionBindings(store),
- Ex, Count, LCtx, IS, Invalidated, false);
+void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
+ ArrayRef<SVal> Values,
+ bool IsArrayOfConstRegions,
+ InvalidatedRegions *TopLevelRegions) {
+ for (ArrayRef<SVal>::iterator I = Values.begin(),
+ E = Values.end(); I != E; ++I) {
+ SVal V = *I;
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+
+ const SValListTy &Vals = getInterestingValues(*LCS);
+
+ for (SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end(); I != E; ++I) {
+ // Note: the last argument is false here because these are
+ // non-top-level regions.
+ if (const MemRegion *R = (*I).getAsRegion())
+ W.AddToWorkList(R, /*IsConst=*/ false);
+ }
+ continue;
+ }
+
+ if (const MemRegion *R = V.getAsRegion()) {
+ if (TopLevelRegions)
+ TopLevelRegions->push_back(R);
+ W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions);
+ continue;
+ }
+ }
+}
+
+StoreRef
+RegionStoreManager::invalidateRegions(Store store,
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
+ const Expr *Ex, unsigned Count,
+ const LocationContext *LCtx,
+ const CallEvent *Call,
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *TopLevelRegions,
+ InvalidatedRegions *TopLevelConstRegions,
+ InvalidatedRegions *Invalidated) {
+ RegionBindingsRef B = RegionStoreManager::getRegionBindings(store);
+ invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS,
+ Invalidated, false);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
// Add the regions to the worklist.
- for (ArrayRef<const MemRegion *>::iterator
- I = Regions.begin(), E = Regions.end(); I != E; ++I)
- W.AddToWorkList(*I);
+ populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false,
+ TopLevelRegions);
+ populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true,
+ TopLevelConstRegions);
W.RunWorkList();
// Return the new bindings.
- RegionBindings B = W.getRegionBindings();
+ B = W.getRegionBindings();
- // For all globals which are not static nor immutable: determine which global
- // regions should be invalidated and invalidate them.
+ // For calls, determine which global regions should be invalidated and
+ // invalidate them. (Note that function-static and immutable globals are never
+ // invalidated by this.)
// TODO: This could possibly be more precise with modules.
- //
- // System calls invalidate only system globals.
- if (Call && Call->isInSystemHeader()) {
+ if (Call) {
B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
- // Internal calls might invalidate both system and internal globals.
- } else {
- B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
- Ex, Count, LCtx, B, Invalidated);
- B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
- Ex, Count, LCtx, B, Invalidated);
+
+ if (!Call->isInSystemHeader()) {
+ B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
+ Ex, Count, LCtx, B, Invalidated);
+ }
}
- return StoreRef(B.getRootWithoutRetain(), *this);
+ return StoreRef(B.asStore(), *this);
}
//===----------------------------------------------------------------------===//
@@ -923,10 +1192,10 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state,
/// the array). This is called by ExprEngine when evaluating casts
/// from arrays to pointers.
SVal RegionStoreManager::ArrayToPointer(Loc Array) {
- if (!isa<loc::MemRegionVal>(Array))
+ if (!Array.getAs<loc::MemRegionVal>())
return UnknownVal();
- const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion();
+ const MemRegion* R = Array.castAs<loc::MemRegionVal>().getRegion();
const TypedValueRegion* ArrayR = dyn_cast<TypedValueRegion>(R);
if (!ArrayR)
@@ -945,31 +1214,9 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
// Loading values from regions.
//===----------------------------------------------------------------------===//
-Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
- const MemRegion *R) {
-
- if (const SVal *V = lookup(B, R, BindingKey::Direct))
- return *V;
-
- return Optional<SVal>();
-}
-
-Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
- const MemRegion *R) {
- if (R->isBoundable())
- if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R))
- if (TR->getValueType()->isUnionType())
- return UnknownVal();
-
- if (const SVal *V = lookup(B, R, BindingKey::Default))
- return *V;
-
- return Optional<SVal>();
-}
-
-SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
- assert(!isa<UnknownVal>(L) && "location unknown");
- assert(!isa<UndefinedVal>(L) && "location undefined");
+SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T) {
+ assert(!L.getAs<UnknownVal>() && "location unknown");
+ assert(!L.getAs<UndefinedVal>() && "location undefined");
// For access to concrete addresses, return UnknownVal. Checks
// for null dereferences (and similar errors) are done by checkers, not
@@ -977,14 +1224,14 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// FIXME: We can consider lazily symbolicating such memory, but we really
// should defer this when we can reason easily about symbolicating arrays
// of bytes.
- if (isa<loc::ConcreteInt>(L)) {
+ if (L.getAs<loc::ConcreteInt>()) {
return UnknownVal();
}
- if (!isa<loc::MemRegionVal>(L)) {
+ if (!L.getAs<loc::MemRegionVal>()) {
return UnknownVal();
}
- const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
+ const MemRegion *MR = L.castAs<loc::MemRegionVal>().getRegion();
if (isa<AllocaRegion>(MR) ||
isa<SymbolicRegion>(MR) ||
@@ -1005,6 +1252,11 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
const TypedValueRegion *R = cast<TypedValueRegion>(MR);
QualType RTy = R->getValueType();
+ // FIXME: we do not yet model the parts of a complex type, so treat the
+ // whole thing as "unknown".
+ if (RTy->isAnyComplexType())
+ return UnknownVal();
+
// FIXME: We should eventually handle funny addressing. e.g.:
//
// int x = ...;
@@ -1013,9 +1265,8 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// char c = *q; // returns the first byte of 'x'.
//
// Such funny addressing will occur due to layering of regions.
-
if (RTy->isStructureOrClassType())
- return getBindingForStruct(store, R);
+ return getBindingForStruct(B, R);
// FIXME: Handle unions.
if (RTy->isUnionType())
@@ -1023,7 +1274,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
if (RTy->isArrayType()) {
if (RTy->isConstantArrayType())
- return getBindingForArray(store, R);
+ return getBindingForArray(B, R);
else
return UnknownVal();
}
@@ -1033,7 +1284,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
return UnknownVal();
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return CastRetrievedVal(getBindingForField(store, FR), FR, T, false);
+ return CastRetrievedVal(getBindingForField(B, FR), FR, T, false);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
// FIXME: Here we actually perform an implicit conversion from the loaded
@@ -1041,7 +1292,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// more intelligently. For example, an 'element' can encompass multiple
// bound regions (e.g., several bound bytes), or could be a subset of
// a larger value.
- return CastRetrievedVal(getBindingForElement(store, ER), ER, T, false);
+ return CastRetrievedVal(getBindingForElement(B, ER), ER, T, false);
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
@@ -1051,7 +1302,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// reinterpretted, it is possible we stored a different value that could
// fit within the ivar. Either we need to cast these when storing them
// or reinterpret them lazily (as we do here).
- return CastRetrievedVal(getBindingForObjCIvar(store, IVR), IVR, T, false);
+ return CastRetrievedVal(getBindingForObjCIvar(B, IVR), IVR, T, false);
}
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -1061,11 +1312,10 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// variable is reinterpretted, it is possible we stored a different value
// that could fit within the variable. Either we need to cast these when
// storing them or reinterpret them lazily (as we do here).
- return CastRetrievedVal(getBindingForVar(store, VR), VR, T, false);
+ return CastRetrievedVal(getBindingForVar(B, VR), VR, T, false);
}
- RegionBindings B = GetRegionBindings(store);
- const SVal *V = lookup(B, R, BindingKey::Direct);
+ const SVal *V = B.lookup(R, BindingKey::Direct);
// Check if the region has a binding.
if (V)
@@ -1086,69 +1336,109 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
return svalBuilder.getRegionValueSymbolVal(R);
}
-std::pair<Store, const MemRegion *>
-RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
- const MemRegion *originalRegion,
- bool includeSuffix) {
-
+static QualType getUnderlyingType(const SubRegion *R) {
+ QualType RegionTy;
+ if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R))
+ RegionTy = TVR->getValueType();
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ RegionTy = SR->getSymbol()->getType();
+
+ return RegionTy;
+}
+
+/// Checks to see if store \p B has a lazy binding for region \p R.
+///
+/// If \p AllowSubregionBindings is \c false, a lazy binding will be rejected
+/// if there are additional bindings within \p R.
+///
+/// Note that unlike RegionStoreManager::findLazyBinding, this will not search
+/// for lazy bindings for super-regions of \p R.
+static Optional<nonloc::LazyCompoundVal>
+getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B,
+ const SubRegion *R, bool AllowSubregionBindings) {
+ Optional<SVal> V = B.getDefaultBinding(R);
+ if (!V)
+ return None;
+
+ Optional<nonloc::LazyCompoundVal> LCV = V->getAs<nonloc::LazyCompoundVal>();
+ if (!LCV)
+ return None;
+
+ // If the LCV is for a subregion, the types might not match, and we shouldn't
+ // reuse the binding.
+ QualType RegionTy = getUnderlyingType(R);
+ if (!RegionTy.isNull() &&
+ !RegionTy->isVoidPointerType()) {
+ QualType SourceRegionTy = LCV->getRegion()->getValueType();
+ if (!SVB.getContext().hasSameUnqualifiedType(RegionTy, SourceRegionTy))
+ return None;
+ }
+
+ if (!AllowSubregionBindings) {
+ // If there are any other bindings within this region, we shouldn't reuse
+ // the top-level binding.
+ SmallVector<BindingPair, 16> Bindings;
+ collectSubRegionBindings(Bindings, SVB, *B.lookup(R->getBaseRegion()), R,
+ /*IncludeAllDefaultBindings=*/true);
+ if (Bindings.size() > 1)
+ return None;
+ }
+
+ return *LCV;
+}
+
+
+std::pair<Store, const SubRegion *>
+RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
+ const SubRegion *R,
+ const SubRegion *originalRegion) {
if (originalRegion != R) {
- if (Optional<SVal> OV = getDefaultBinding(B, R)) {
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
- return std::make_pair(V->getStore(), V->getRegion());
- }
+ if (Optional<nonloc::LazyCompoundVal> V =
+ getExistingLazyBinding(svalBuilder, B, R, true))
+ return std::make_pair(V->getStore(), V->getRegion());
}
-
+
+ typedef std::pair<Store, const SubRegion *> StoreRegionPair;
+ StoreRegionPair Result = StoreRegionPair();
+
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, ER->getSuperRegion(), originalRegion);
-
- if (X.second)
- return std::make_pair(X.first,
- MRMgr.getElementRegionWithSuper(ER, X.second));
- }
- else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, FR->getSuperRegion(), originalRegion);
-
- if (X.second) {
- if (includeSuffix)
- return std::make_pair(X.first,
- MRMgr.getFieldRegionWithSuper(FR, X.second));
- return X;
- }
-
- }
- // C++ base object region is another kind of region that we should blast
- // through to look for lazy compound value. It is like a field region.
- else if (const CXXBaseObjectRegion *baseReg =
- dyn_cast<CXXBaseObjectRegion>(R)) {
- const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, baseReg->getSuperRegion(), originalRegion);
+ Result = findLazyBinding(B, cast<SubRegion>(ER->getSuperRegion()),
+ originalRegion);
+
+ if (Result.second)
+ Result.second = MRMgr.getElementRegionWithSuper(ER, Result.second);
+
+ } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+ Result = findLazyBinding(B, cast<SubRegion>(FR->getSuperRegion()),
+ originalRegion);
+
+ if (Result.second)
+ Result.second = MRMgr.getFieldRegionWithSuper(FR, Result.second);
+
+ } else if (const CXXBaseObjectRegion *BaseReg =
+ dyn_cast<CXXBaseObjectRegion>(R)) {
+ // C++ base object region is another kind of region that we should blast
+ // through to look for lazy compound value. It is like a field region.
+ Result = findLazyBinding(B, cast<SubRegion>(BaseReg->getSuperRegion()),
+ originalRegion);
- if (X.second) {
- if (includeSuffix)
- return std::make_pair(X.first,
- MRMgr.getCXXBaseObjectRegionWithSuper(baseReg,
- X.second));
- return X;
- }
+ if (Result.second)
+ Result.second = MRMgr.getCXXBaseObjectRegionWithSuper(BaseReg,
+ Result.second);
}
- // The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
- // possible for a valid lazy binding.
- return std::make_pair((Store) 0, (const MemRegion *) 0);
+ return Result;
}
-SVal RegionStoreManager::getBindingForElement(Store store,
+SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
const ElementRegion* R) {
// We do not currently model bindings of the CompoundLiteralregion.
if (isa<CompoundLiteralRegion>(R->getBaseRegion()))
return UnknownVal();
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1163,7 +1453,7 @@ SVal RegionStoreManager::getBindingForElement(Store store,
const StringLiteral *Str = StrR->getStringLiteral();
SVal Idx = R->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
+ if (Optional<nonloc::ConcreteInt> CI = Idx.getAs<nonloc::ConcreteInt>()) {
int64_t i = CI->getValue().getSExtValue();
// Abort on string underrun. This can be possible by arbitrary
// clients of getBindingForElement().
@@ -1202,7 +1492,7 @@ SVal RegionStoreManager::getBindingForElement(Store store,
QualType elemT = R->getElementType();
if (elemT->isScalarType()) {
if (Ctx.getTypeSizeInChars(baseT) >= Ctx.getTypeSizeInChars(elemT)) {
- if (const Optional<SVal> &V = getDirectBinding(B, superR)) {
+ if (const Optional<SVal> &V = B.getDirectBinding(superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1216,29 +1506,27 @@ SVal RegionStoreManager::getBindingForElement(Store store,
}
}
}
- return getBindingForFieldOrElementCommon(store, R, R->getElementType(),
- superR);
+ return getBindingForFieldOrElementCommon(B, R, R->getElementType(),superR);
}
-SVal RegionStoreManager::getBindingForField(Store store,
- const FieldRegion* R) {
+SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
+ const FieldRegion* R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
QualType Ty = R->getValueType();
- return getBindingForFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
+ return getBindingForFieldOrElementCommon(B, R, Ty, R->getSuperRegion());
}
Optional<SVal>
-RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindings B,
+RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
const MemRegion *superR,
const TypedValueRegion *R,
QualType Ty) {
- if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
+ if (const Optional<SVal> &D = B.getDefaultBinding(superR)) {
const SVal &val = D.getValue();
if (SymbolRef parentSym = val.getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1249,53 +1537,95 @@ RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindings B,
if (val.isUnknownOrUndef())
return val;
- // Lazy bindings are handled later.
- if (isa<nonloc::LazyCompoundVal>(val))
- return Optional<SVal>();
+ // Lazy bindings are usually handled through getExistingLazyBinding().
+ // We should unify these two code paths at some point.
+ if (val.getAs<nonloc::LazyCompoundVal>())
+ return val;
llvm_unreachable("Unknown default value");
}
- return Optional<SVal>();
+ return None;
}
-SVal RegionStoreManager::getLazyBinding(const MemRegion *lazyBindingRegion,
- Store lazyBindingStore) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
- return getBindingForElement(lazyBindingStore, ER);
-
- return getBindingForField(lazyBindingStore,
- cast<FieldRegion>(lazyBindingRegion));
+SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
+ RegionBindingsRef LazyBinding) {
+ SVal Result;
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(LazyBindingRegion))
+ Result = getBindingForElement(LazyBinding, ER);
+ else
+ Result = getBindingForField(LazyBinding,
+ cast<FieldRegion>(LazyBindingRegion));
+
+ // FIXME: This is a hack to deal with RegionStore's inability to distinguish a
+ // default value for /part/ of an aggregate from a default value for the
+ // /entire/ aggregate. The most common case of this is when struct Outer
+ // has as its first member a struct Inner, which is copied in from a stack
+ // variable. In this case, even if the Outer's default value is symbolic, 0,
+ // or unknown, it gets overridden by the Inner's default value of undefined.
+ //
+ // This is a general problem -- if the Inner is zero-initialized, the Outer
+ // will now look zero-initialized. The proper way to solve this is with a
+ // new version of RegionStore that tracks the extent of a binding as well
+ // as the offset.
+ //
+ // This hack only takes care of the undefined case because that can very
+ // quickly result in a warning.
+ if (Result.isUndef())
+ Result = UnknownVal();
+
+ return Result;
}
-SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
+SVal
+RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const TypedValueRegion *R,
QualType Ty,
const MemRegion *superR) {
// At this point we have already checked in either getBindingForElement or
// getBindingForField if 'R' has a direct binding.
- RegionBindings B = GetRegionBindings(store);
// Lazy binding?
Store lazyBindingStore = NULL;
- const MemRegion *lazyBindingRegion = NULL;
- llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R, R,
- true);
-
+ const SubRegion *lazyBindingRegion = NULL;
+ llvm::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R);
if (lazyBindingRegion)
- return getLazyBinding(lazyBindingRegion, lazyBindingStore);
+ return getLazyBinding(lazyBindingRegion,
+ getRegionBindings(lazyBindingStore));
// Record whether or not we see a symbolic index. That can completely
// be out of scope of our lookup.
bool hasSymbolicIndex = false;
- while (superR) {
- if (const Optional<SVal> &D =
- getBindingForDerivedDefaultValue(B, superR, R, Ty))
+ // FIXME: This is a hack to deal with RegionStore's inability to distinguish a
+ // default value for /part/ of an aggregate from a default value for the
+ // /entire/ aggregate. The most common case of this is when struct Outer
+ // has as its first member a struct Inner, which is copied in from a stack
+ // variable. In this case, even if the Outer's default value is symbolic, 0,
+ // or unknown, it gets overridden by the Inner's default value of undefined.
+ //
+ // This is a general problem -- if the Inner is zero-initialized, the Outer
+ // will now look zero-initialized. The proper way to solve this is with a
+ // new version of RegionStore that tracks the extent of a binding as well
+ // as the offset.
+ //
+ // This hack only takes care of the undefined case because that can very
+ // quickly result in a warning.
+ bool hasPartialLazyBinding = false;
+
+ const SubRegion *Base = dyn_cast<SubRegion>(superR);
+ while (Base) {
+ if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) {
+ if (D->getAs<nonloc::LazyCompoundVal>()) {
+ hasPartialLazyBinding = true;
+ break;
+ }
+
return *D;
+ }
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(superR)) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(Base)) {
NonLoc index = ER->getIndex();
if (!index.isConstant())
hasSymbolicIndex = true;
@@ -1303,11 +1633,7 @@ SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
// If our super region is a field or element itself, walk up the region
// hierarchy to see if there is a default value installed in an ancestor.
- if (const SubRegion *SR = dyn_cast<SubRegion>(superR)) {
- superR = SR->getSuperRegion();
- continue;
- }
- break;
+ Base = dyn_cast<SubRegion>(Base->getSuperRegion());
}
if (R->hasStackNonParametersStorage()) {
@@ -1327,27 +1653,25 @@ SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
// a symbolic offset.
if (hasSymbolicIndex)
return UnknownVal();
-
- return UndefinedVal();
+
+ if (!hasPartialLazyBinding)
+ return UndefinedVal();
}
// All other values are symbolic.
return svalBuilder.getRegionValueSymbolVal(R);
}
-SVal RegionStoreManager::getBindingForObjCIvar(Store store,
+SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B,
const ObjCIvarRegion* R) {
-
- // Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
-
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ // Check if the region has a binding.
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
const MemRegion *superR = R->getSuperRegion();
// Check if the super region has a default binding.
- if (const Optional<SVal> &V = getDefaultBinding(B, superR)) {
+ if (const Optional<SVal> &V = B.getDefaultBinding(superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1358,51 +1682,64 @@ SVal RegionStoreManager::getBindingForObjCIvar(Store store,
return getBindingForLazySymbol(R);
}
-SVal RegionStoreManager::getBindingForVar(Store store, const VarRegion *R) {
+static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) {
+ ASTContext &Ctx = SVB.getContext();
+ if (!VD->getType().isConstQualified())
+ return None;
- // Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
+ const Expr *Init = VD->getInit();
+ if (!Init)
+ return None;
+
+ llvm::APSInt Result;
+ if (!Init->isGLValue() && Init->EvaluateAsInt(Result, Ctx))
+ return SVB.makeIntVal(Result);
+
+ if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+ return SVB.makeNull();
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ // FIXME: Handle other possible constant expressions.
+ return None;
+}
+
+SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
+ const VarRegion *R) {
+
+ // Check if the region has a binding.
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
- QualType T = VD->getType();
const MemSpaceRegion *MS = R->getMemorySpace();
- if (isa<UnknownSpaceRegion>(MS) ||
- isa<StackArgumentsSpaceRegion>(MS))
+ // Arguments are always symbolic.
+ if (isa<StackArgumentsSpaceRegion>(MS))
+ return svalBuilder.getRegionValueSymbolVal(R);
+
+ // Is 'VD' declared constant? If so, retrieve the constant value.
+ if (Optional<SVal> V = getConstValue(svalBuilder, VD))
+ return *V;
+
+ // This must come after the check for constants because closure-captured
+ // constant variables may appear in UnknownSpaceRegion.
+ if (isa<UnknownSpaceRegion>(MS))
return svalBuilder.getRegionValueSymbolVal(R);
if (isa<GlobalsSpaceRegion>(MS)) {
- if (isa<NonStaticGlobalSpaceRegion>(MS)) {
- // Is 'VD' declared constant? If so, retrieve the constant value.
- QualType CT = Ctx.getCanonicalType(T);
- if (CT.isConstQualified()) {
- const Expr *Init = VD->getInit();
- // Do the null check first, as we want to call 'IgnoreParenCasts'.
- if (Init)
- if (const IntegerLiteral *IL =
- dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
- const nonloc::ConcreteInt &V = svalBuilder.makeIntVal(IL);
- return svalBuilder.evalCast(V, Init->getType(), IL->getType());
- }
- }
+ QualType T = VD->getType();
- if (const Optional<SVal> &V
- = getBindingForDerivedDefaultValue(B, MS, R, CT))
- return V.getValue();
+ // Function-scoped static variables are default-initialized to 0; if they
+ // have an initializer, it would have been processed by now.
+ if (isa<StaticGlobalSpaceRegion>(MS))
+ return svalBuilder.makeZeroVal(T);
- return svalBuilder.getRegionValueSymbolVal(R);
+ if (Optional<SVal> V = getBindingForDerivedDefaultValue(B, MS, R, T)) {
+ assert(!V->getAs<nonloc::LazyCompoundVal>());
+ return V.getValue();
}
- if (T->isIntegerType())
- return svalBuilder.makeIntVal(0, T);
- if (T->isPointerType())
- return svalBuilder.makeNull();
-
- return UnknownVal();
+ return svalBuilder.getRegionValueSymbolVal(R);
}
return UndefinedVal();
@@ -1413,55 +1750,77 @@ SVal RegionStoreManager::getBindingForLazySymbol(const TypedValueRegion *R) {
return svalBuilder.getRegionValueSymbolVal(R);
}
-static bool mayHaveLazyBinding(QualType Ty) {
- return Ty->isArrayType() || Ty->isStructureOrClassType();
+const RegionStoreManager::SValListTy &
+RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
+ // First, check the cache.
+ LazyBindingsMapTy::iterator I = LazyBindingsMap.find(LCV.getCVData());
+ if (I != LazyBindingsMap.end())
+ return I->second;
+
+ // If we don't have a list of values cached, start constructing it.
+ SValListTy List;
+
+ const SubRegion *LazyR = LCV.getRegion();
+ RegionBindingsRef B = getRegionBindings(LCV.getStore());
+
+ // If this region had /no/ bindings at the time, there are no interesting
+ // values to return.
+ const ClusterBindings *Cluster = B.lookup(LazyR->getBaseRegion());
+ if (!Cluster)
+ return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List));
+
+ SmallVector<BindingPair, 32> Bindings;
+ collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR,
+ /*IncludeAllDefaultBindings=*/true);
+ for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(),
+ E = Bindings.end();
+ I != E; ++I) {
+ SVal V = I->second;
+ if (V.isUnknownOrUndef() || V.isConstant())
+ continue;
+
+ if (Optional<nonloc::LazyCompoundVal> InnerLCV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+ const SValListTy &InnerList = getInterestingValues(*InnerLCV);
+ List.insert(List.end(), InnerList.begin(), InnerList.end());
+ continue;
+ }
+
+ List.push_back(V);
+ }
+
+ return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List));
+}
+
+NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
+ if (Optional<nonloc::LazyCompoundVal> V =
+ getExistingLazyBinding(svalBuilder, B, R, false))
+ return *V;
+
+ return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
}
-SVal RegionStoreManager::getBindingForStruct(Store store,
- const TypedValueRegion* R) {
+SVal RegionStoreManager::getBindingForStruct(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
const RecordDecl *RD = R->getValueType()->castAs<RecordType>()->getDecl();
if (RD->field_empty())
return UnknownVal();
- // If we already have a lazy binding, don't create a new one,
- // unless the first field might have a lazy binding of its own.
- // (Right now we can't tell the difference.)
- QualType FirstFieldType = RD->field_begin()->getType();
- if (!mayHaveLazyBinding(FirstFieldType)) {
- RegionBindings B = GetRegionBindings(store);
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
- return *V;
- }
- }
-
- return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
+ return createLazyBinding(B, R);
}
-SVal RegionStoreManager::getBindingForArray(Store store,
- const TypedValueRegion * R) {
- const ConstantArrayType *Ty = Ctx.getAsConstantArrayType(R->getValueType());
- assert(Ty && "Only constant array types can have compound bindings.");
+SVal RegionStoreManager::getBindingForArray(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
+ assert(Ctx.getAsConstantArrayType(R->getValueType()) &&
+ "Only constant array types can have compound bindings.");
- // If we already have a lazy binding, don't create a new one,
- // unless the first element might have a lazy binding of its own.
- // (Right now we can't tell the difference.)
- if (!mayHaveLazyBinding(Ty->getElementType())) {
- RegionBindings B = GetRegionBindings(store);
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
- return *V;
- }
- }
-
- return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
+ return createLazyBinding(B, R);
}
bool RegionStoreManager::includedInBindings(Store store,
const MemRegion *region) const {
- RegionBindings B = GetRegionBindings(store);
+ RegionBindingsRef B = getRegionBindings(store);
region = region->getBaseRegion();
// Quick path: if the base is the head of a cluster, the region is live.
@@ -1469,7 +1828,7 @@ bool RegionStoreManager::includedInBindings(Store store,
return true;
// Slow path: if the region is the VALUE of any binding, it is live.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
+ for (RegionBindingsRef::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
const ClusterBindings &Cluster = RI.getData();
for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
CI != CE; ++CI) {
@@ -1488,31 +1847,33 @@ bool RegionStoreManager::includedInBindings(Store store,
//===----------------------------------------------------------------------===//
StoreRef RegionStoreManager::killBinding(Store ST, Loc L) {
- if (isa<loc::MemRegionVal>(L))
- if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
- return StoreRef(removeBinding(GetRegionBindings(ST),
- R).getRootWithoutRetain(),
+ if (Optional<loc::MemRegionVal> LV = L.getAs<loc::MemRegionVal>())
+ if (const MemRegion* R = LV->getRegion())
+ return StoreRef(getRegionBindings(ST).removeBinding(R)
+ .asImmutableMap()
+ .getRootWithoutRetain(),
*this);
return StoreRef(ST, *this);
}
-StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
- if (isa<loc::ConcreteInt>(L))
- return StoreRef(store, *this);
+RegionBindingsRef
+RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
+ if (L.getAs<loc::ConcreteInt>())
+ return B;
// If we get here, the location should be a region.
- const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+ const MemRegion *R = L.castAs<loc::MemRegionVal>().getRegion();
// Check if the region is a struct region.
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
QualType Ty = TR->getValueType();
if (Ty->isArrayType())
- return BindArray(store, TR, V);
+ return bindArray(B, TR, V);
if (Ty->isStructureOrClassType())
- return BindStruct(store, TR, V);
+ return bindStruct(B, TR, V);
if (Ty->isVectorType())
- return BindVector(store, TR, V);
+ return bindVector(B, TR, V);
}
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
@@ -1526,12 +1887,8 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
}
// Clear out bindings that may overlap with this binding.
-
- // Perform the binding.
- RegionBindings B = GetRegionBindings(store);
- B = removeSubRegionBindings(B, cast<SubRegion>(R));
- BindingKey Key = BindingKey::Make(R, BindingKey::Direct);
- return StoreRef(addBinding(B, Key, V).getRootWithoutRetain(), *this);
+ RegionBindingsRef NewB = removeSubRegionBindings(B, cast<SubRegion>(R));
+ return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V);
}
// FIXME: this method should be merged into Bind().
@@ -1542,10 +1899,10 @@ StoreRef RegionStoreManager::bindCompoundLiteral(Store ST,
return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V);
}
-StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
- const MemRegion *R,
- QualType T) {
- RegionBindings B = GetRegionBindings(store);
+RegionBindingsRef
+RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B,
+ const MemRegion *R,
+ QualType T) {
SVal V;
if (Loc::isLocType(T))
@@ -1566,12 +1923,13 @@ StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
V = UnknownVal();
}
- return StoreRef(addBinding(B, R, BindingKey::Default,
- V).getRootWithoutRetain(), *this);
+ return B.addBinding(R, BindingKey::Default, V);
}
-StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
- SVal Init) {
+RegionBindingsRef
+RegionStoreManager::bindArray(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal Init) {
const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
QualType ElementTy = AT->getElementType();
@@ -1581,30 +1939,31 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
Size = CAT->getSize().getZExtValue();
// Check if the init expr is a string literal.
- if (loc::MemRegionVal *MRV = dyn_cast<loc::MemRegionVal>(&Init)) {
+ if (Optional<loc::MemRegionVal> MRV = Init.getAs<loc::MemRegionVal>()) {
const StringRegion *S = cast<StringRegion>(MRV->getRegion());
// Treat the string as a lazy compound value.
- nonloc::LazyCompoundVal LCV =
- cast<nonloc::LazyCompoundVal>(svalBuilder.
- makeLazyCompoundVal(StoreRef(store, *this), S));
- return BindAggregate(store, R, LCV);
+ StoreRef store(B.asStore(), *this);
+ nonloc::LazyCompoundVal LCV = svalBuilder.makeLazyCompoundVal(store, S)
+ .castAs<nonloc::LazyCompoundVal>();
+ return bindAggregate(B, R, LCV);
}
// Handle lazy compound values.
- if (isa<nonloc::LazyCompoundVal>(Init))
- return BindAggregate(store, R, Init);
+ if (Init.getAs<nonloc::LazyCompoundVal>())
+ return bindAggregate(B, R, Init);
// Remaining case: explicit compound values.
if (Init.isUnknown())
- return setImplicitDefaultValue(store, R, ElementTy);
+ return setImplicitDefaultValue(B, R, ElementTy);
- nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
+ const nonloc::CompoundVal& CV = Init.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
- StoreRef newStore(store, *this);
+ RegionBindingsRef NewB(B);
+
for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
@@ -1614,44 +1973,45 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, Ctx);
if (ElementTy->isStructureOrClassType())
- newStore = BindStruct(newStore.getStore(), ER, *VI);
+ NewB = bindStruct(NewB, ER, *VI);
else if (ElementTy->isArrayType())
- newStore = BindArray(newStore.getStore(), ER, *VI);
+ NewB = bindArray(NewB, ER, *VI);
else
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(ER), *VI);
+ NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the
// array default value.
if (Size.hasValue() && i < Size.getValue())
- newStore = setImplicitDefaultValue(newStore.getStore(), R, ElementTy);
+ NewB = setImplicitDefaultValue(NewB, R, ElementTy);
- return newStore;
+ return NewB;
}
-StoreRef RegionStoreManager::BindVector(Store store, const TypedValueRegion* R,
- SVal V) {
+RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal V) {
QualType T = R->getValueType();
assert(T->isVectorType());
const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
// Handle lazy compound values and symbolic values.
- if (isa<nonloc::LazyCompoundVal>(V) || isa<nonloc::SymbolVal>(V))
- return BindAggregate(store, R, V);
+ if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
+ return bindAggregate(B, R, V);
// We may get non-CompoundVal accidentally due to imprecise cast logic or
// that we are binding symbolic struct value. Kill the field values, and if
// the value is symbolic go and bind it as a "default" binding.
- if (!isa<nonloc::CompoundVal>(V)) {
- return BindAggregate(store, R, UnknownVal());
+ if (!V.getAs<nonloc::CompoundVal>()) {
+ return bindAggregate(B, R, UnknownVal());
}
QualType ElemType = VT->getElementType();
- nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
+ nonloc::CompoundVal CV = V.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
unsigned index = 0, numElements = VT->getNumElements();
- StoreRef newStore(store, *this);
-
+ RegionBindingsRef NewB(B);
+
for ( ; index != numElements ; ++index) {
if (VI == VE)
break;
@@ -1660,20 +2020,20 @@ StoreRef RegionStoreManager::BindVector(Store store, const TypedValueRegion* R,
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
if (ElemType->isArrayType())
- newStore = BindArray(newStore.getStore(), ER, *VI);
+ NewB = bindArray(NewB, ER, *VI);
else if (ElemType->isStructureOrClassType())
- newStore = BindStruct(newStore.getStore(), ER, *VI);
+ NewB = bindStruct(NewB, ER, *VI);
else
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(ER), *VI);
+ NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI);
}
- return newStore;
+ return NewB;
}
-StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
- SVal V) {
-
+RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal V) {
if (!Features.supportsFields())
- return StoreRef(store, *this);
+ return B;
QualType T = R->getValueType();
assert(T->isStructureOrClassType());
@@ -1682,24 +2042,24 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
RecordDecl *RD = RT->getDecl();
if (!RD->isCompleteDefinition())
- return StoreRef(store, *this);
+ return B;
// Handle lazy compound values and symbolic values.
- if (isa<nonloc::LazyCompoundVal>(V) || isa<nonloc::SymbolVal>(V))
- return BindAggregate(store, R, V);
+ if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
+ return bindAggregate(B, R, V);
// We may get non-CompoundVal accidentally due to imprecise cast logic or
// that we are binding symbolic struct value. Kill the field values, and if
// the value is symbolic go and bind it as a "default" binding.
- if (V.isUnknown() || !isa<nonloc::CompoundVal>(V))
- return BindAggregate(store, R, UnknownVal());
+ if (V.isUnknown() || !V.getAs<nonloc::CompoundVal>())
+ return bindAggregate(B, R, UnknownVal());
- nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
+ const nonloc::CompoundVal& CV = V.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RecordDecl::field_iterator FI, FE;
- StoreRef newStore(store, *this);
-
+ RegionBindingsRef NewB(B);
+
for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) {
if (VI == VE)
@@ -1713,95 +2073,30 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
if (FTy->isArrayType())
- newStore = BindArray(newStore.getStore(), FR, *VI);
+ NewB = bindArray(NewB, FR, *VI);
else if (FTy->isStructureOrClassType())
- newStore = BindStruct(newStore.getStore(), FR, *VI);
+ NewB = bindStruct(NewB, FR, *VI);
else
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(FR), *VI);
+ NewB = bind(NewB, svalBuilder.makeLoc(FR), *VI);
++VI;
}
// There may be fewer values in the initialize list than the fields of struct.
if (FI != FE) {
- RegionBindings B = GetRegionBindings(newStore.getStore());
- B = addBinding(B, R, BindingKey::Default, svalBuilder.makeIntVal(0, false));
- newStore = StoreRef(B.getRootWithoutRetain(), *this);
+ NewB = NewB.addBinding(R, BindingKey::Default,
+ svalBuilder.makeIntVal(0, false));
}
- return newStore;
+ return NewB;
}
-StoreRef RegionStoreManager::BindAggregate(Store store, const TypedRegion *R,
- SVal Val) {
+RegionBindingsRef
+RegionStoreManager::bindAggregate(RegionBindingsConstRef B,
+ const TypedRegion *R,
+ SVal Val) {
// Remove the old bindings, using 'R' as the root of all regions
// we will invalidate. Then add the new binding.
- RegionBindings B = GetRegionBindings(store);
-
- B = removeSubRegionBindings(B, R);
- B = addBinding(B, R, BindingKey::Default, Val);
-
- return StoreRef(B.getRootWithoutRetain(), *this);
-}
-
-//===----------------------------------------------------------------------===//
-// "Raw" retrievals and bindings.
-//===----------------------------------------------------------------------===//
-
-
-RegionBindings RegionStoreManager::addBinding(RegionBindings B, BindingKey K,
- SVal V) {
- const MemRegion *Base = K.getBaseRegion();
-
- const ClusterBindings *ExistingCluster = B.lookup(Base);
- ClusterBindings Cluster = (ExistingCluster ? *ExistingCluster
- : CBFactory.getEmptyMap());
-
- ClusterBindings NewCluster = CBFactory.add(Cluster, K, V);
- return RBFactory.add(B, Base, NewCluster);
-}
-
-RegionBindings RegionStoreManager::addBinding(RegionBindings B,
- const MemRegion *R,
- BindingKey::Kind k, SVal V) {
- return addBinding(B, BindingKey::Make(R, k), V);
-}
-
-const SVal *RegionStoreManager::lookup(RegionBindings B, BindingKey K) {
- const ClusterBindings *Cluster = B.lookup(K.getBaseRegion());
- if (!Cluster)
- return 0;
-
- return Cluster->lookup(K);
-}
-
-const SVal *RegionStoreManager::lookup(RegionBindings B,
- const MemRegion *R,
- BindingKey::Kind k) {
- return lookup(B, BindingKey::Make(R, k));
-}
-
-RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
- BindingKey K) {
- const MemRegion *Base = K.getBaseRegion();
- const ClusterBindings *Cluster = B.lookup(Base);
- if (!Cluster)
- return B;
-
- ClusterBindings NewCluster = CBFactory.remove(*Cluster, K);
- if (NewCluster.isEmpty())
- return RBFactory.remove(B, Base);
- return RBFactory.add(B, Base, NewCluster);
-}
-
-RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
- const MemRegion *R,
- BindingKey::Kind k){
- return removeBinding(B, BindingKey::Make(R, k));
-}
-
-RegionBindings RegionStoreManager::removeCluster(RegionBindings B,
- const MemRegion *Base) {
- return RBFactory.remove(B, Base);
+ return removeSubRegionBindings(B, R).addBinding(R, BindingKey::Default, Val);
}
//===----------------------------------------------------------------------===//
@@ -1818,7 +2113,7 @@ class removeDeadBindingsWorker :
public:
removeDeadBindingsWorker(RegionStoreManager &rm,
ProgramStateManager &stateMgr,
- RegionBindings b, SymbolReaper &symReaper,
+ RegionBindingsRef b, SymbolReaper &symReaper,
const StackFrameContext *LCtx)
: ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b,
/* includeGlobals = */ false),
@@ -1826,7 +2121,8 @@ public:
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
+ using ClusterAnalysis<removeDeadBindingsWorker>::VisitCluster;
bool UpdatePostponed();
void VisitBinding(SVal V);
@@ -1869,38 +2165,30 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
}
void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
- const ClusterBindings &C) {
+ const ClusterBindings *C) {
+ if (!C)
+ return;
+
// Mark the symbol for any SymbolicRegion with live bindings as live itself.
// This means we should continue to track that symbol.
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
VisitBinding(I.getData());
}
void removeDeadBindingsWorker::VisitBinding(SVal V) {
// Is it a LazyCompoundVal? All referenced regions are live as well.
- if (const nonloc::LazyCompoundVal *LCS =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
- const MemRegion *LazyR = LCS->getRegion();
- RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+ const RegionStoreManager::SValListTy &Vals = RM.getInterestingValues(*LCS);
- // FIXME: This should not have to walk all bindings in the old store.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
- const ClusterBindings &Cluster = RI.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- BindingKey K = CI.getKey();
- if (const SubRegion *BaseR = dyn_cast<SubRegion>(K.getRegion())) {
- if (BaseR == LazyR)
- VisitBinding(CI.getData());
- else if (K.hasSymbolicOffset() && BaseR->isSubRegionOf(LazyR))
- VisitBinding(CI.getData());
- }
- }
- }
+ for (RegionStoreManager::SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end();
+ I != E; ++I)
+ VisitBinding(*I);
return;
}
@@ -1946,7 +2234,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
StoreRef RegionStoreManager::removeDeadBindings(Store store,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper) {
- RegionBindings B = GetRegionBindings(store);
+ RegionBindingsRef B = getRegionBindings(store);
removeDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx);
W.GenerateClusters();
@@ -1961,7 +2249,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
- for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion *Base = I.getKey();
// If the cluster has been visited, we know the region has been marked.
@@ -1969,7 +2257,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
continue;
// Remove the dead entry.
- B = removeCluster(B, Base);
+ B = B.remove(Base);
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(Base))
SymReaper.maybeDead(SymR->getSymbol());
@@ -1985,7 +2273,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
}
}
- return StoreRef(B.getRootWithoutRetain(), *this);
+ return StoreRef(B.asStore(), *this);
}
//===----------------------------------------------------------------------===//
@@ -1994,17 +2282,9 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
void RegionStoreManager::print(Store store, raw_ostream &OS,
const char* nl, const char *sep) {
- RegionBindings B = GetRegionBindings(store);
+ RegionBindingsRef B = getRegionBindings(store);
OS << "Store (direct and default bindings), "
- << (void*) B.getRootWithoutRetain()
+ << B.asStore()
<< " :" << nl;
-
- for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const ClusterBindings &Cluster = I.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- OS << ' ' << CI.getKey() << " : " << CI.getData() << nl;
- }
- OS << nl;
- }
+ B.dump(OS, nl);
}
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index b87169a4b335..c72e7808010e 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -12,13 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
using namespace clang;
using namespace ento;
@@ -78,13 +78,13 @@ SVal SValBuilder::convertToArrayIndex(SVal val) {
return val;
// Common case: we have an appropriately sized integer.
- if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&val)) {
+ if (Optional<nonloc::ConcreteInt> CI = val.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt& I = CI->getValue();
if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
return val;
}
- return evalCastFromNonLoc(cast<NonLoc>(val), ArrayIndexTy);
+ return evalCastFromNonLoc(val.castAs<NonLoc>(), ArrayIndexTy);
}
nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr *boolean){
@@ -237,11 +237,11 @@ SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
return makeNonLoc(symLHS, Op, symRHS, ResultTy);
if (symLHS && symLHS->computeComplexity() < MaxComp)
- if (const nonloc::ConcreteInt *rInt = dyn_cast<nonloc::ConcreteInt>(&RHS))
+ if (Optional<nonloc::ConcreteInt> rInt = RHS.getAs<nonloc::ConcreteInt>())
return makeNonLoc(symLHS, Op, rInt->getValue(), ResultTy);
if (symRHS && symRHS->computeComplexity() < MaxComp)
- if (const nonloc::ConcreteInt *lInt = dyn_cast<nonloc::ConcreteInt>(&LHS))
+ if (Optional<nonloc::ConcreteInt> lInt = LHS.getAs<nonloc::ConcreteInt>())
return makeNonLoc(lInt->getValue(), Op, symRHS, ResultTy);
return UnknownVal();
@@ -257,41 +257,42 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
if (lhs.isUnknown() || rhs.isUnknown())
return UnknownVal();
- if (isa<Loc>(lhs)) {
- if (isa<Loc>(rhs))
- return evalBinOpLL(state, op, cast<Loc>(lhs), cast<Loc>(rhs), type);
+ if (Optional<Loc> LV = lhs.getAs<Loc>()) {
+ if (Optional<Loc> RV = rhs.getAs<Loc>())
+ return evalBinOpLL(state, op, *LV, *RV, type);
- return evalBinOpLN(state, op, cast<Loc>(lhs), cast<NonLoc>(rhs), type);
+ return evalBinOpLN(state, op, *LV, rhs.castAs<NonLoc>(), type);
}
- if (isa<Loc>(rhs)) {
+ if (Optional<Loc> RV = rhs.getAs<Loc>()) {
// Support pointer arithmetic where the addend is on the left
// and the pointer on the right.
assert(op == BO_Add);
// Commute the operands.
- return evalBinOpLN(state, op, cast<Loc>(rhs), cast<NonLoc>(lhs), type);
+ return evalBinOpLN(state, op, *RV, lhs.castAs<NonLoc>(), type);
}
- return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type);
+ return evalBinOpNN(state, op, lhs.castAs<NonLoc>(), rhs.castAs<NonLoc>(),
+ type);
}
DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state,
DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs) {
- return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs,
- Context.IntTy));
+ return evalBinOp(state, BO_EQ, lhs, rhs, Context.IntTy)
+ .castAs<DefinedOrUnknownSVal>();
}
/// Recursively check if the pointer types are equal modulo const, volatile,
-/// and restrict qualifiers. Assumes the input types are canonical.
-/// TODO: This is based off of code in SemaCast; can we reuse it.
-static bool haveSimilarTypes(ASTContext &Context, QualType T1,
- QualType T2) {
- while (Context.UnwrapSimilarPointerTypes(T1, T2)) {
+/// and restrict qualifiers. Also, assume that all types are similar to 'void'.
+/// Assumes the input types are canonical.
+static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy,
+ QualType FromTy) {
+ while (Context.UnwrapSimilarPointerTypes(ToTy, FromTy)) {
Qualifiers Quals1, Quals2;
- T1 = Context.getUnqualifiedArrayType(T1, Quals1);
- T2 = Context.getUnqualifiedArrayType(T2, Quals2);
+ ToTy = Context.getUnqualifiedArrayType(ToTy, Quals1);
+ FromTy = Context.getUnqualifiedArrayType(FromTy, Quals2);
// Make sure that non cvr-qualifiers the other qualifiers (e.g., address
// spaces) are identical.
@@ -301,7 +302,12 @@ static bool haveSimilarTypes(ASTContext &Context, QualType T1,
return false;
}
- if (T1 != T2)
+ // If we are casting to void, the 'From' value can be used to represent the
+ // 'To' value.
+ if (ToTy->isVoidType())
+ return true;
+
+ if (ToTy != FromTy)
return false;
return true;
@@ -314,19 +320,19 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
if (val.isUnknownOrUndef() || castTy == originalTy)
return val;
- // For const casts, just propagate the value.
+ // For const casts, casts to void, just propagate the value.
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
- if (haveSimilarTypes(Context, Context.getPointerType(castTy),
- Context.getPointerType(originalTy)))
+ if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy),
+ Context.getPointerType(originalTy)))
return val;
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::isLocType(originalTy))
- return evalCastFromLoc(cast<Loc>(val), castTy);
+ return evalCastFromLoc(val.castAs<Loc>(), castTy);
// Check for casts from integers to pointers.
if (Loc::isLocType(castTy) && originalTy->isIntegerType()) {
- if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) {
if (const MemRegion *R = LV->getLoc().getAsRegion()) {
StoreManager &storeMgr = StateMgr.getStoreManager();
R = storeMgr.castRegion(R, castTy);
@@ -346,7 +352,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// Check for casts from array type to another type.
if (originalTy->isArrayType()) {
// We will always decay to a pointer.
- val = StateMgr.ArrayToPointer(cast<Loc>(val));
+ val = StateMgr.ArrayToPointer(val.castAs<Loc>());
// Are we casting from an array to a pointer? If so just pass on
// the decayed value.
@@ -361,7 +367,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// need the original decayed type.
// QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
// QualType pointerTy = C.getPointerType(elemTy);
- return evalCastFromLoc(cast<Loc>(val), castTy);
+ return evalCastFromLoc(val.castAs<Loc>(), castTy);
}
// Check for casts from a region to a specific type.
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index e34ab6a2be91..38e216f28c06 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
using llvm::APSInt;
@@ -29,13 +30,13 @@ using llvm::APSInt;
//===----------------------------------------------------------------------===//
bool SVal::hasConjuredSymbol() const {
- if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
+ if (Optional<nonloc::SymbolVal> SV = getAs<nonloc::SymbolVal>()) {
SymbolRef sym = SV->getSymbol();
if (isa<SymbolConjured>(sym))
return true;
}
- if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
+ if (Optional<loc::MemRegionVal> RV = getAs<loc::MemRegionVal>()) {
const MemRegion *R = RV->getRegion();
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
SymbolRef sym = SR->getSymbol();
@@ -48,7 +49,7 @@ bool SVal::hasConjuredSymbol() const {
}
const FunctionDecl *SVal::getAsFunctionDecl() const {
- if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
+ if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
@@ -65,10 +66,10 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
/// region. If that is the case, gets the underlining region.
SymbolRef SVal::getAsLocSymbol() const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
- if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
+ if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
return X->getLoc().getAsLocSymbol();
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
+ if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion *R = X->stripCasts();
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
@@ -78,7 +79,7 @@ SymbolRef SVal::getAsLocSymbol() const {
/// Get the symbol in the SVal or its base region.
SymbolRef SVal::getLocSymbolInBase() const {
- const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);
+ Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
if (!X)
return 0;
@@ -101,7 +102,7 @@ SymbolRef SVal::getLocSymbolInBase() const {
/// Otherwise return 0.
SymbolRef SVal::getAsSymbol() const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
- if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+ if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
return X->getSymbol();
return getAsLocSymbol();
@@ -110,7 +111,7 @@ SymbolRef SVal::getAsSymbol() const {
/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
/// return that expression. Otherwise return NULL.
const SymExpr *SVal::getAsSymbolicExpression() const {
- if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+ if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
return X->getSymbol();
return getAsSymbol();
@@ -124,12 +125,11 @@ const SymExpr* SVal::getAsSymExpr() const {
}
const MemRegion *SVal::getAsRegion() const {
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
+ if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
return X->getRegion();
- if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
+ if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
return X->getLoc().getAsRegion();
- }
return 0;
}
@@ -143,7 +143,7 @@ const void *nonloc::LazyCompoundVal::getStore() const {
return static_cast<const LazyCompoundValData*>(Data)->getStore();
}
-const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
+const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
return static_cast<const LazyCompoundValData*>(Data)->getRegion();
}
@@ -164,16 +164,15 @@ nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
//===----------------------------------------------------------------------===//
bool SVal::isConstant() const {
- return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
+ return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
}
bool SVal::isConstant(int I) const {
- if (isa<loc::ConcreteInt>(*this))
- return cast<loc::ConcreteInt>(*this).getValue() == I;
- else if (isa<nonloc::ConcreteInt>(*this))
- return cast<nonloc::ConcreteInt>(*this).getValue() == I;
- else
- return false;
+ if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
+ return LV->getValue() == I;
+ if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
+ return NV->getValue() == I;
+ return false;
}
bool SVal::isZeroConstant() const {
@@ -215,13 +214,12 @@ SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
BinaryOperator::Opcode Op,
const loc::ConcreteInt& R) const {
- assert (Op == BO_Add || Op == BO_Sub ||
- (Op >= BO_LT && Op <= BO_NE));
+ assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub);
- const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
+ const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
if (X)
- return loc::ConcreteInt(*X);
+ return nonloc::ConcreteInt(*X);
else
return UndefinedVal();
}
@@ -238,10 +236,10 @@ void SVal::dumpToStream(raw_ostream &os) const {
os << "Unknown";
break;
case NonLocKind:
- cast<NonLoc>(this)->dumpToStream(os);
+ castAs<NonLoc>().dumpToStream(os);
break;
case LocKind:
- cast<Loc>(this)->dumpToStream(os);
+ castAs<Loc>().dumpToStream(os);
break;
case UndefinedKind:
os << "Undefined";
@@ -252,7 +250,7 @@ void SVal::dumpToStream(raw_ostream &os) const {
void NonLoc::dumpToStream(raw_ostream &os) const {
switch (getSubKind()) {
case nonloc::ConcreteIntKind: {
- const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
+ const nonloc::ConcreteInt& C = castAs<nonloc::ConcreteInt>();
if (C.getValue().isUnsigned())
os << C.getValue().getZExtValue();
else
@@ -262,16 +260,16 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
break;
}
case nonloc::SymbolValKind: {
- os << cast<nonloc::SymbolVal>(this)->getSymbol();
+ os << castAs<nonloc::SymbolVal>().getSymbol();
break;
}
case nonloc::LocAsIntegerKind: {
- const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
+ const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
break;
}
case nonloc::CompoundValKind: {
- const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
+ const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
os << "compoundVal{";
bool first = true;
for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
@@ -287,7 +285,7 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
break;
}
case nonloc::LazyCompoundValKind: {
- const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
+ const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>();
os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
<< ',' << C.getRegion()
<< '}';
@@ -302,13 +300,13 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
void Loc::dumpToStream(raw_ostream &os) const {
switch (getSubKind()) {
case loc::ConcreteIntKind:
- os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
+ os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
break;
case loc::GotoLabelKind:
- os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName();
+ os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
break;
case loc::MemRegionKind:
- os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
+ os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
break;
default:
llvm_unreachable("Pretty-printing not implemented for this Loc.");
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 4236ee470af4..9b759df48f28 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -24,7 +24,7 @@ namespace ento {
SimpleConstraintManager::~SimpleConstraintManager() {}
bool SimpleConstraintManager::canReasonAbout(SVal X) const {
- nonloc::SymbolVal *SymVal = dyn_cast<nonloc::SymbolVal>(&X);
+ Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
if (SymVal && SymVal->isExpression()) {
const SymExpr *SE = SymVal->getSymbol();
@@ -49,6 +49,16 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
}
}
+ if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
+ if (BinaryOperator::isComparisonOp(SSE->getOpcode())) {
+ // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc.
+ if (Loc::isLocType(SSE->getLHS()->getType())) {
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ return true;
+ }
+ }
+ }
+
return false;
}
@@ -58,10 +68,9 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
DefinedSVal Cond,
bool Assumption) {
- if (isa<NonLoc>(Cond))
- return assume(state, cast<NonLoc>(Cond), Assumption);
- else
- return assume(state, cast<Loc>(Cond), Assumption);
+ if (Optional<NonLoc> NV = Cond.getAs<NonLoc>())
+ return assume(state, *NV, Assumption);
+ return assume(state, Cond.castAs<Loc>(), Assumption);
}
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond,
@@ -82,7 +91,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
case loc::MemRegionKind: {
// FIXME: Should this go into the storemanager?
- const MemRegion *R = cast<loc::MemRegionVal>(Cond).getRegion();
+ const MemRegion *R = Cond.castAs<loc::MemRegionVal>().getRegion();
const SubRegion *SubR = dyn_cast<SubRegion>(R);
while (SubR) {
@@ -104,7 +113,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
return Assumption ? state : NULL;
case loc::ConcreteIntKind: {
- bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
+ bool b = Cond.castAs<loc::ConcreteInt>().getValue() != 0;
bool isFeasible = b ? Assumption : !Assumption;
return isFeasible ? state : NULL;
}
@@ -120,21 +129,6 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
return state;
}
-static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
- // FIXME: This should probably be part of BinaryOperator, since this isn't
- // the only place it's used. (This code was copied from SimpleSValBuilder.cpp.)
- switch (op) {
- default:
- llvm_unreachable("Invalid opcode.");
- case BO_LT: return BO_GE;
- case BO_GT: return BO_LE;
- case BO_LE: return BO_GT;
- case BO_GE: return BO_LT;
- case BO_EQ: return BO_NE;
- case BO_NE: return BO_EQ;
- }
-}
-
ProgramStateRef
SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State,
@@ -165,14 +159,12 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
return assumeAuxForSymbol(state, sym, Assumption);
}
- BasicValueFactory &BasicVals = getBasicVals();
-
switch (Cond.getSubKind()) {
default:
llvm_unreachable("'Assume' not implemented for this NonLoc");
case nonloc::SymbolValKind: {
- nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
+ nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
SymbolRef sym = SV.getSymbol();
assert(sym);
@@ -181,36 +173,55 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
return assumeAuxForSymbol(state, sym, Assumption);
// Handle symbolic expression.
- } else {
+ } else if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym)) {
// We can only simplify expressions whose RHS is an integer.
- const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym);
- if (!SE)
- return assumeAuxForSymbol(state, sym, Assumption);
BinaryOperator::Opcode op = SE->getOpcode();
- // Implicitly compare non-comparison expressions to 0.
- if (!BinaryOperator::isComparisonOp(op)) {
- QualType T = SE->getType();
- const llvm::APSInt &zero = BasicVals.getValue(0, T);
- op = (Assumption ? BO_NE : BO_EQ);
- return assumeSymRel(state, SE, op, zero);
+ if (BinaryOperator::isComparisonOp(op)) {
+ if (!Assumption)
+ op = BinaryOperator::negateComparisonOp(op);
+
+ return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
}
- // From here on out, op is the real comparison we'll be testing.
- if (!Assumption)
- op = NegateComparison(op);
- return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
+ } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(sym)) {
+ // Translate "a != b" to "(b - a) != 0".
+ // We invert the order of the operands as a heuristic for how loop
+ // conditions are usually written ("begin != end") as compared to length
+ // calculations ("end - begin"). The more correct thing to do would be to
+ // canonicalize "a - b" and "b - a", which would allow us to treat
+ // "a != b" and "b != a" the same.
+ SymbolManager &SymMgr = getSymbolManager();
+ BinaryOperator::Opcode Op = SSE->getOpcode();
+ assert(BinaryOperator::isComparisonOp(Op));
+
+ // For now, we only support comparing pointers.
+ assert(Loc::isLocType(SSE->getLHS()->getType()));
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ QualType DiffTy = SymMgr.getContext().getPointerDiffType();
+ SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
+ SSE->getLHS(), DiffTy);
+
+ const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
+ Op = BinaryOperator::reverseComparisonOp(Op);
+ if (!Assumption)
+ Op = BinaryOperator::negateComparisonOp(Op);
+ return assumeSymRel(state, Subtraction, Op, Zero);
}
+
+ // If we get here, there's nothing else we can do but treat the symbol as
+ // opaque.
+ return assumeAuxForSymbol(state, sym, Assumption);
}
case nonloc::ConcreteIntKind: {
- bool b = cast<nonloc::ConcreteInt>(Cond).getValue() != 0;
+ bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
bool isFeasible = b ? Assumption : !Assumption;
return isFeasible ? state : NULL;
}
case nonloc::LocAsIntegerKind:
- return assumeAux(state, cast<nonloc::LocAsInteger>(Cond).getLoc(),
+ return assumeAux(state, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
Assumption);
} // end switch
}
@@ -258,10 +269,14 @@ ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state,
APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
+ // Prefer unsigned comparisons.
+ if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
+ ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
+ Adjustment.setIsSigned(false);
+
switch (op) {
default:
- // No logic yet for other operators. assume the constraint is feasible.
- return state;
+ llvm_unreachable("invalid operation not caught by assertion above");
case BO_EQ:
return assumeSymEQ(state, Sym, ConvertedInt, Adjustment);
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 01f0b4e4461f..10ddef1341c5 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -23,10 +23,10 @@ namespace ento {
class SimpleConstraintManager : public ConstraintManager {
SubEngine *SU;
- BasicValueFactory &BVF;
+ SValBuilder &SVB;
public:
- SimpleConstraintManager(SubEngine *subengine, BasicValueFactory &BV)
- : SU(subengine), BVF(BV) {}
+ SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB)
+ : SU(subengine), SVB(SB) {}
virtual ~SimpleConstraintManager();
//===------------------------------------------------------------------===//
@@ -81,7 +81,8 @@ protected:
// Internal implementation.
//===------------------------------------------------------------------===//
- BasicValueFactory &getBasicVals() const { return BVF; }
+ BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
+ SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
bool canReasonAbout(SVal X) const;
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index fbc6ba055105..5cc8926a4449 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
using namespace clang;
@@ -60,16 +60,16 @@ SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
//===----------------------------------------------------------------------===//
SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) {
- assert(isa<Loc>(&Val) || isa<NonLoc>(&Val));
- return isa<Loc>(Val) ? evalCastFromLoc(cast<Loc>(Val), CastTy)
- : evalCastFromNonLoc(cast<NonLoc>(Val), CastTy);
+ assert(Val.getAs<Loc>() || Val.getAs<NonLoc>());
+ return Val.getAs<Loc>() ? evalCastFromLoc(Val.castAs<Loc>(), CastTy)
+ : evalCastFromNonLoc(Val.castAs<NonLoc>(), CastTy);
}
SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
bool isLocType = Loc::isLocType(castTy);
- if (nonloc::LocAsInteger *LI = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) {
if (isLocType)
return LI->getLoc();
@@ -98,15 +98,21 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
}
// If value is a non integer constant, produce unknown.
- if (!isa<nonloc::ConcreteInt>(val))
+ if (!val.getAs<nonloc::ConcreteInt>())
return UnknownVal();
+ // Handle casts to a boolean type.
+ if (castTy->isBooleanType()) {
+ bool b = val.castAs<nonloc::ConcreteInt>().getValue().getBoolValue();
+ return makeTruthVal(b, castTy);
+ }
+
// Only handle casts from integers to integers - if val is an integer constant
// being cast to a non integer type, produce unknown.
if (!isLocType && !castTy->isIntegerType())
return UnknownVal();
- llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
+ llvm::APSInt i = val.castAs<nonloc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(castTy).apply(i);
if (isLocType)
@@ -134,10 +140,10 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
if (castTy->isIntegerType()) {
unsigned BitWidth = Context.getTypeSize(castTy);
- if (!isa<loc::ConcreteInt>(val))
+ if (!val.getAs<loc::ConcreteInt>())
return makeLocAsInteger(val, BitWidth);
- llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ llvm::APSInt i = val.castAs<loc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(castTy).apply(i);
return makeIntVal(i);
}
@@ -155,7 +161,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
SVal SimpleSValBuilder::evalMinus(NonLoc val) {
switch (val.getSubKind()) {
case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(val).evalMinus(*this);
+ return val.castAs<nonloc::ConcreteInt>().evalMinus(*this);
default:
return UnknownVal();
}
@@ -164,7 +170,7 @@ SVal SimpleSValBuilder::evalMinus(NonLoc val) {
SVal SimpleSValBuilder::evalComplement(NonLoc X) {
switch (X.getSubKind()) {
case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(X).evalComplement(*this);
+ return X.castAs<nonloc::ConcreteInt>().evalComplement(*this);
default:
return UnknownVal();
}
@@ -174,33 +180,6 @@ SVal SimpleSValBuilder::evalComplement(NonLoc X) {
// Transfer function for binary operators.
//===----------------------------------------------------------------------===//
-static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
- switch (op) {
- default:
- llvm_unreachable("Invalid opcode.");
- case BO_LT: return BO_GE;
- case BO_GT: return BO_LE;
- case BO_LE: return BO_GT;
- case BO_GE: return BO_LT;
- case BO_EQ: return BO_NE;
- case BO_NE: return BO_EQ;
- }
-}
-
-static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) {
- switch (op) {
- default:
- llvm_unreachable("Invalid opcode.");
- case BO_LT: return BO_GT;
- case BO_GT: return BO_LT;
- case BO_LE: return BO_GE;
- case BO_GE: return BO_LE;
- case BO_EQ:
- case BO_NE:
- return op;
- }
-}
-
SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
BinaryOperator::Opcode op,
const llvm::APSInt &RHS,
@@ -331,15 +310,15 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
default:
return makeSymExprValNN(state, op, lhs, rhs, resultTy);
case nonloc::LocAsIntegerKind: {
- Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
+ Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc();
switch (rhs.getSubKind()) {
case nonloc::LocAsIntegerKind:
return evalBinOpLL(state, op, lhsL,
- cast<nonloc::LocAsInteger>(rhs).getLoc(),
+ rhs.castAs<nonloc::LocAsInteger>().getLoc(),
resultTy);
case nonloc::ConcreteIntKind: {
// Transform the integer into a location and compare.
- llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
+ llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
}
@@ -356,7 +335,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
}
case nonloc::ConcreteIntKind: {
- llvm::APSInt LHSValue = cast<nonloc::ConcreteInt>(lhs).getValue();
+ llvm::APSInt LHSValue = lhs.castAs<nonloc::ConcreteInt>().getValue();
// If we're dealing with two known constants, just perform the operation.
if (const llvm::APSInt *KnownRHSValue = getKnownValue(state, rhs)) {
@@ -392,7 +371,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_GT:
case BO_LE:
case BO_GE:
- op = ReverseComparison(op);
+ op = BinaryOperator::reverseComparisonOp(op);
// FALL-THROUGH
case BO_EQ:
case BO_NE:
@@ -419,7 +398,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
case nonloc::SymbolValKind: {
// We only handle LHS as simple symbols or SymIntExprs.
- SymbolRef Sym = cast<nonloc::SymbolVal>(lhs).getSymbol();
+ SymbolRef Sym = lhs.castAs<nonloc::SymbolVal>().getSymbol();
// LHS is a symbolic expression.
if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(Sym)) {
@@ -460,7 +439,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_EQ:
case BO_NE:
// Negate the comparison and make a value.
- opc = NegateComparison(opc);
+ opc = BinaryOperator::negateComparisonOp(opc);
assert(symIntExpr->getType() == resultTy);
return makeNonLoc(symIntExpr->getLHS(), opc,
symIntExpr->getRHS(), resultTy);
@@ -502,22 +481,21 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// Otherwise, make a SymIntExpr out of the expression.
return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy);
}
+ }
-
- } else if (isa<SymbolData>(Sym)) {
- // Does the symbol simplify to a constant? If so, "fold" the constant
- // by setting 'lhs' to a ConcreteInt and try again.
- if (const llvm::APSInt *Constant = state->getConstraintManager()
- .getSymVal(state, Sym)) {
- lhs = nonloc::ConcreteInt(*Constant);
- continue;
- }
-
- // Is the RHS a constant?
- if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
- return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
+ // Does the symbolic expression simplify to a constant?
+ // If so, "fold" the constant by setting 'lhs' to a ConcreteInt
+ // and try again.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) {
+ lhs = nonloc::ConcreteInt(*Constant);
+ continue;
}
+ // Is the RHS a constant?
+ if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
+ return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
+
// Give up -- this is not a symbolic expression we can handle.
return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
}
@@ -595,25 +573,27 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
if (!BinaryOperator::isComparisonOp(op))
return UnknownVal();
- const llvm::APSInt &lVal = cast<loc::ConcreteInt>(lhs).getValue();
- return makeNonLoc(rSym, ReverseComparison(op), lVal, resultTy);
+ const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue();
+ op = BinaryOperator::reverseComparisonOp(op);
+ return makeNonLoc(rSym, op, lVal, resultTy);
}
// If both operands are constants, just perform the operation.
- if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
- SVal ResultVal = cast<loc::ConcreteInt>(lhs).evalBinOp(BasicVals, op,
- *rInt);
- if (Loc *Result = dyn_cast<Loc>(&ResultVal))
- return evalCastFromLoc(*Result, resultTy);
- else
- return UnknownVal();
+ if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
+ SVal ResultVal =
+ lhs.castAs<loc::ConcreteInt>().evalBinOp(BasicVals, op, *rInt);
+ if (Optional<NonLoc> Result = ResultVal.getAs<NonLoc>())
+ return evalCastFromNonLoc(*Result, resultTy);
+
+ assert(!ResultVal.getAs<Loc>() && "Loc-Loc ops should not produce Locs");
+ return UnknownVal();
}
// Special case comparisons against NULL.
// This must come after the test if the RHS is a symbol, which is used to
// build constraints. The address of any non-symbolic region is guaranteed
// to be non-NULL, as is any label.
- assert(isa<loc::MemRegionVal>(rhs) || isa<loc::GotoLabel>(rhs));
+ assert(rhs.getAs<loc::MemRegionVal>() || rhs.getAs<loc::GotoLabel>());
if (lhs.isZeroConstant()) {
switch (op) {
default:
@@ -634,7 +614,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
return UnknownVal();
}
case loc::MemRegionKind: {
- if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
+ if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
if (SymbolRef lSym = lhs.getAsLocSymbol())
@@ -676,11 +656,11 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// regions, though.
return UnknownVal();
- const MemSpaceRegion *LeftMS = LeftMR->getMemorySpace();
- const MemSpaceRegion *RightMS = RightMR->getMemorySpace();
- const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
const MemRegion *LeftBase = LeftMR->getBaseRegion();
const MemRegion *RightBase = RightMR->getBaseRegion();
+ const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
+ const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
+ const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
// If the two regions are from different known memory spaces they cannot be
// equal. Also, assume that no symbolic region (whose memory space is
@@ -732,21 +712,21 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// Get the left index and cast it to the correct type.
// If the index is unknown or undefined, bail out here.
SVal LeftIndexVal = LeftER->getIndex();
- NonLoc *LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
+ Optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>();
if (!LeftIndex)
return UnknownVal();
- LeftIndexVal = evalCastFromNonLoc(*LeftIndex, resultTy);
- LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
+ LeftIndexVal = evalCastFromNonLoc(*LeftIndex, ArrayIndexTy);
+ LeftIndex = LeftIndexVal.getAs<NonLoc>();
if (!LeftIndex)
return UnknownVal();
// Do the same for the right index.
SVal RightIndexVal = RightER->getIndex();
- NonLoc *RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
+ Optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>();
if (!RightIndex)
return UnknownVal();
- RightIndexVal = evalCastFromNonLoc(*RightIndex, resultTy);
- RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
+ RightIndexVal = evalCastFromNonLoc(*RightIndex, ArrayIndexTy);
+ RightIndex = RightIndexVal.getAs<NonLoc>();
if (!RightIndex)
return UnknownVal();
@@ -783,7 +763,6 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
}
// If we get here, we have no way of comparing the ElementRegions.
- return UnknownVal();
}
// See if both regions are fields of the same structure.
@@ -836,6 +815,13 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
llvm_unreachable("Fields not found in parent record's definition");
}
+ // At this point we're not going to get a good answer, but we can try
+ // conjuring an expression instead.
+ SymbolRef LHSSym = lhs.getAsLocSymbol();
+ SymbolRef RHSSym = rhs.getAsLocSymbol();
+ if (LHSSym && RHSSym)
+ return makeNonLoc(LHSSym, op, RHSSym, resultTy);
+
// If we get here, we have no way of comparing the regions.
return UnknownVal();
}
@@ -852,11 +838,12 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Special case: 'rhs' is an integer that has the same width as a pointer and
// we are using the integer location in a comparison. Normally this cannot be
- // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+ // triggered, but transfer functions like those for OSCompareAndSwapBarrier32
// can generate comparisons that trigger this code.
// FIXME: Are all locations guaranteed to have pointer width?
if (BinaryOperator::isComparisonOp(op)) {
- if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
+ if (Optional<nonloc::ConcreteInt> rhsInt =
+ rhs.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt *x = &rhsInt->getValue();
ASTContext &ctx = Context;
if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
@@ -873,8 +860,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values.
- if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
- if (loc::ConcreteInt *lhsInt = dyn_cast<loc::ConcreteInt>(&lhs)) {
+ if (Optional<nonloc::ConcreteInt> rhsInt = rhs.getAs<nonloc::ConcreteInt>()) {
+ if (Optional<loc::ConcreteInt> lhsInt = lhs.getAs<loc::ConcreteInt>()) {
const llvm::APSInt &leftI = lhsInt->getValue();
assert(leftI.isUnsigned());
llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);
@@ -904,7 +891,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Handle cases where 'lhs' is a region.
if (const MemRegion *region = lhs.getAsRegion()) {
- rhs = cast<NonLoc>(convertToArrayIndex(rhs));
+ rhs = convertToArrayIndex(rhs).castAs<NonLoc>();
SVal index = UnknownVal();
const MemRegion *superR = 0;
QualType elementType;
@@ -923,7 +910,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
elementType = resultTy->getPointeeType();
}
- if (NonLoc *indexV = dyn_cast<NonLoc>(&index)) {
+ if (Optional<NonLoc> indexV = index.getAs<NonLoc>()) {
return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV,
superR, getContext()));
}
@@ -936,10 +923,10 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
if (V.isUnknownOrUndef())
return NULL;
- if (loc::ConcreteInt* X = dyn_cast<loc::ConcreteInt>(&V))
+ if (Optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
return &X->getValue();
- if (nonloc::ConcreteInt* X = dyn_cast<nonloc::ConcreteInt>(&V))
+ if (Optional<nonloc::ConcreteInt> X = V.getAs<nonloc::ConcreteInt>())
return &X->getValue();
if (SymbolRef Sym = V.getAsSymbol())
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 939ae54dad74..a0c24fedcfca 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
using namespace clang;
using namespace ento;
@@ -223,13 +223,38 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
llvm_unreachable("unreachable");
}
+static bool regionMatchesCXXRecordType(SVal V, QualType Ty) {
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR)
+ return true;
+
+ const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
+ if (!TVR)
+ return true;
+
+ const CXXRecordDecl *RD = TVR->getValueType()->getAsCXXRecordDecl();
+ if (!RD)
+ return true;
+
+ const CXXRecordDecl *Expected = Ty->getPointeeCXXRecordDecl();
+ if (!Expected)
+ Expected = Ty->getAsCXXRecordDecl();
+
+ return Expected->getCanonicalDecl() == RD->getCanonicalDecl();
+}
+
SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
+ // Sanity check to avoid doing the wrong thing in the face of
+ // reinterpret_cast.
+ if (!regionMatchesCXXRecordType(Derived, Cast->getSubExpr()->getType()))
+ return UnknownVal();
+
// Walk through the cast path to create nested CXXBaseRegions.
SVal Result = Derived;
for (CastExpr::path_const_iterator I = Cast->path_begin(),
E = Cast->path_end();
I != E; ++I) {
- Result = evalDerivedToBase(Result, (*I)->getType());
+ Result = evalDerivedToBase(Result, (*I)->getType(), (*I)->isVirtual());
}
return Result;
}
@@ -239,13 +264,16 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) {
SVal Result = Derived;
for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
I != E; ++I) {
- Result = evalDerivedToBase(Result, I->Base->getType());
+ Result = evalDerivedToBase(Result, I->Base->getType(),
+ I->Base->isVirtual());
}
return Result;
}
-SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
- loc::MemRegionVal *DerivedRegVal = dyn_cast<loc::MemRegionVal>(&Derived);
+SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType,
+ bool IsVirtual) {
+ Optional<loc::MemRegionVal> DerivedRegVal =
+ Derived.getAs<loc::MemRegionVal>();
if (!DerivedRegVal)
return Derived;
@@ -255,7 +283,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
assert(BaseDecl && "not a C++ object?");
const MemRegion *BaseReg =
- MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion());
+ MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion(),
+ IsVirtual);
return loc::MemRegionVal(BaseReg);
}
@@ -264,7 +293,7 @@ SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType,
bool &Failed) {
Failed = false;
- loc::MemRegionVal *BaseRegVal = dyn_cast<loc::MemRegionVal>(&Base);
+ Optional<loc::MemRegionVal> BaseRegVal = Base.getAs<loc::MemRegionVal>();
if (!BaseRegVal)
return UnknownVal();
const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false);
@@ -348,12 +377,12 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
- Loc BaseL = cast<Loc>(Base);
+ Loc BaseL = Base.castAs<Loc>();
const MemRegion* BaseR = 0;
switch (BaseL.getSubKind()) {
case loc::MemRegionKind:
- BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+ BaseR = BaseL.castAs<loc::MemRegionVal>().getRegion();
break;
case loc::GotoLabelKind:
@@ -390,16 +419,16 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
// FIXME: For absolute pointer addresses, we just return that value back as
// well, although in reality we should return the offset added to that
// value.
- if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+ if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>())
return Base;
- const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
+ const MemRegion* BaseRegion = Base.castAs<loc::MemRegionVal>().getRegion();
// Pointer of any type can be cast and used as array base.
const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
// Convert the offset to the appropriate size and signedness.
- Offset = cast<NonLoc>(svalBuilder.convertToArrayIndex(Offset));
+ Offset = svalBuilder.convertToArrayIndex(Offset).castAs<NonLoc>();
if (!ElemR) {
//
@@ -417,15 +446,16 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
SVal BaseIdx = ElemR->getIndex();
- if (!isa<nonloc::ConcreteInt>(BaseIdx))
+ if (!BaseIdx.getAs<nonloc::ConcreteInt>())
return UnknownVal();
- const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
+ const llvm::APSInt &BaseIdxI =
+ BaseIdx.castAs<nonloc::ConcreteInt>().getValue();
// Only allow non-integer offsets if the base region has no offset itself.
// FIXME: This is a somewhat arbitrary restriction. We should be using
// SValBuilder here to add the two offsets without checking their types.
- if (!isa<nonloc::ConcreteInt>(Offset)) {
+ if (!Offset.getAs<nonloc::ConcreteInt>()) {
if (isa<ElementRegion>(BaseRegion->StripCasts()))
return UnknownVal();
@@ -434,7 +464,7 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
Ctx));
}
- const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
+ const llvm::APSInt& OffI = Offset.castAs<nonloc::ConcreteInt>().getValue();
assert(BaseIdxI.isSigned());
// Compute the new index.
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 0c5098b1e7d0..de2f5bc7b373 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -27,52 +27,33 @@ void SymExpr::dump() const {
dumpToStream(llvm::errs());
}
-static void print(raw_ostream &os, BinaryOperator::Opcode Op) {
- switch (Op) {
- default:
- llvm_unreachable("operator printing not implemented");
- case BO_Mul: os << '*' ; break;
- case BO_Div: os << '/' ; break;
- case BO_Rem: os << '%' ; break;
- case BO_Add: os << '+' ; break;
- case BO_Sub: os << '-' ; break;
- case BO_Shl: os << "<<" ; break;
- case BO_Shr: os << ">>" ; break;
- case BO_LT: os << "<" ; break;
- case BO_GT: os << '>' ; break;
- case BO_LE: os << "<=" ; break;
- case BO_GE: os << ">=" ; break;
- case BO_EQ: os << "==" ; break;
- case BO_NE: os << "!=" ; break;
- case BO_And: os << '&' ; break;
- case BO_Xor: os << '^' ; break;
- case BO_Or: os << '|' ; break;
- }
-}
-
void SymIntExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
- os << ") ";
- print(os, getOpcode());
- os << ' ' << getRHS().getZExtValue();
- if (getRHS().isUnsigned()) os << 'U';
+ os << ") "
+ << BinaryOperator::getOpcodeStr(getOpcode()) << ' '
+ << getRHS().getZExtValue();
+ if (getRHS().isUnsigned())
+ os << 'U';
}
void IntSymExpr::dumpToStream(raw_ostream &os) const {
- os << ' ' << getLHS().getZExtValue();
- if (getLHS().isUnsigned()) os << 'U';
- print(os, getOpcode());
- os << '(';
+ os << getLHS().getZExtValue();
+ if (getLHS().isUnsigned())
+ os << 'U';
+ os << ' '
+ << BinaryOperator::getOpcodeStr(getOpcode())
+ << " (";
getRHS()->dumpToStream(os);
- os << ") ";
+ os << ')';
}
void SymSymExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
- os << ") ";
- os << '(';
+ os << ") "
+ << BinaryOperator::getOpcodeStr(getOpcode())
+ << " (";
getRHS()->dumpToStream(os);
os << ')';
}
@@ -468,9 +449,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
switch (sym->getKind()) {
case SymExpr::RegionValueKind:
- // FIXME: We should be able to use isLiveRegion here (this behavior
- // predates isLiveRegion), but doing so causes test failures. Investigate.
- KnownLive = true;
+ KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
break;
case SymExpr::ConjuredKind:
KnownLive = false;
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index e09f4e365344..d5706d6dbbe8 100644
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -46,7 +46,8 @@ public:
} // end anonymous namespace
-void ento::createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string& out,
const Preprocessor &PP) {
C.push_back(new TextPathDiagnostics(out, PP.getDiagnostics()));
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 7dbac3cf93a0..d71e528848b0 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -20,31 +20,30 @@
#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"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/Timer.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"
-
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include <queue>
using namespace clang;
@@ -54,9 +53,11 @@ using llvm::SmallPtrSet;
static ExplodedNode::Auditor* CreateUbiViz();
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
-STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level).");
+STATISTIC(NumFunctionsAnalyzed,
+ "The # of functions and blocks analyzed (as top level "
+ "with inlining turned on).");
STATISTIC(NumBlocksInAnalyzedFunctions,
- "The # of basic blocks in the analyzed functions.");
+ "The # of basic blocks in the analyzed functions.");
STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
@@ -64,11 +65,13 @@ STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
// Special PathDiagnosticConsumers.
//===----------------------------------------------------------------------===//
-static void createPlistHTMLDiagnosticConsumer(PathDiagnosticConsumers &C,
+static void createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string &prefix,
const Preprocessor &PP) {
- createHTMLDiagnosticConsumer(C, llvm::sys::path::parent_path(prefix), PP);
- createPlistDiagnosticConsumer(C, prefix, PP);
+ createHTMLDiagnosticConsumer(AnalyzerOpts, C,
+ llvm::sys::path::parent_path(prefix), PP);
+ createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
}
namespace {
@@ -188,13 +191,14 @@ public:
switch (Opts->AnalysisDiagOpt) {
default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
- case PD_##NAME: CREATEFN(PathConsumers, OutDir, PP); break;
+ case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\
+ break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}
} else if (Opts->AnalysisDiagOpt == PD_TEXT) {
// Create the text client even without a specified output file since
// it just uses diagnostic notes.
- createTextPathDiagnosticConsumer(PathConsumers, "", PP);
+ createTextPathDiagnosticConsumer(*Opts.getPtr(), PathConsumers, "", PP);
}
// Create the analyzer component creators.
@@ -208,14 +212,15 @@ public:
switch (Opts->AnalysisConstraintsOpt) {
default:
- llvm_unreachable("Unknown store manager.");
+ llvm_unreachable("Unknown constraint manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateConstraintMgr = CREATEFN; break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}
}
- void DisplayFunction(const Decl *D, AnalysisMode Mode) {
+ void DisplayFunction(const Decl *D, AnalysisMode Mode,
+ ExprEngine::InliningModes IMode) {
if (!Opts->AnalyzerDisplayProgress)
return;
@@ -226,8 +231,18 @@ public:
if (Mode == AM_Syntax)
llvm::errs() << " (Syntax)";
- else if (Mode == AM_Path)
- llvm::errs() << " (Path)";
+ else if (Mode == AM_Path) {
+ llvm::errs() << " (Path, ";
+ switch (IMode) {
+ case ExprEngine::Inline_Minimal:
+ llvm::errs() << " Inline_Minimal";
+ break;
+ case ExprEngine::Inline_Regular:
+ llvm::errs() << " Inline_Regular";
+ break;
+ }
+ llvm::errs() << ")";
+ }
else
assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
@@ -268,6 +283,12 @@ public:
virtual void HandleTranslationUnit(ASTContext &C);
+ /// \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);
+
/// \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.
void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
@@ -279,10 +300,14 @@ public:
/// set of functions which should be considered analyzed after analyzing the
/// given root function.
void HandleCode(Decl *D, AnalysisMode Mode,
+ ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
SetOfConstDecls *VisitedCallees = 0);
- void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees);
+ void RunPathSensitiveChecks(Decl *D,
+ ExprEngine::InliningModes IMode,
+ SetOfConstDecls *VisitedCallees);
void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees);
/// Visitors for the RecursiveASTVisitor.
@@ -305,14 +330,25 @@ public:
// only determined when they are instantiated.
if (FD->isThisDeclarationADefinition() &&
!FD->isDependentContext()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
HandleCode(FD, RecVisitorMode);
}
return true;
}
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- if (MD->isThisDeclarationADefinition())
+ if (MD->isThisDeclarationADefinition()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
HandleCode(MD, RecVisitorMode);
+ }
+ return true;
+ }
+
+ bool VisitBlockDecl(BlockDecl *BD) {
+ if (BD->hasBody()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
+ HandleCode(BD, RecVisitorMode);
+ }
return true;
}
@@ -352,95 +388,90 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
}
}
-static bool shouldSkipFunction(CallGraphNode *N,
- SmallPtrSet<CallGraphNode*,24> Visited) {
- // We want to re-analyse the functions as top level in several cases:
+static bool shouldSkipFunction(const Decl *D,
+ SetOfConstDecls Visited,
+ SetOfConstDecls VisitedAsTopLevel) {
+ if (VisitedAsTopLevel.count(D))
+ return true;
+
+ // We want to re-analyse the functions as top level in the following cases:
// - The 'init' methods should be reanalyzed because
// ObjCNonNilReturnValueChecker assumes that '[super init]' never returns
- // 'nil' and unless we analyze the 'init' functions as top level, we will not
- // catch errors within defensive code.
+ // 'nil' and unless we analyze the 'init' functions as top level, we will
+ // not catch errors within defensive code.
// - We want to reanalyze all ObjC methods as top level to report Retain
// Count naming convention errors more aggressively.
- if (isa<ObjCMethodDecl>(N->getDecl()))
+ if (isa<ObjCMethodDecl>(D))
return false;
// Otherwise, if we visited the function before, do not reanalyze it.
- return Visited.count(N);
+ return Visited.count(D);
}
-void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
- // Otherwise, use the Callgraph to derive the order.
- // Build the Call Graph.
- CallGraph CG;
+ExprEngine::InliningModes
+AnalysisConsumer::getInliningModeForFunction(const Decl *D,
+ 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.
+ if (Visited.count(D)) {
+ assert(isa<ObjCMethodDecl>(D) &&
+ "We are only reanalyzing ObjCMethods.");
+ const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
+ if (ObjCM->getMethodFamily() != OMF_init)
+ return ExprEngine::Inline_Minimal;
+ }
- // Add all the top level declarations to the graph.
+ return ExprEngine::Inline_Regular;
+}
+
+void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
+ // Build the Call Graph by adding all the top level declarations to the graph.
// Note: CallGraph can trigger deserialization of more items from a pch
// (though HandleInterestingDecl); triggering additions to LocalTUDecls.
// We rely on random access to add the initially processed Decls to CG.
+ CallGraph CG;
for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
CG.addToCallGraph(LocalTUDecls[i]);
}
- // Find the top level nodes - children of root + the unreachable (parentless)
- // nodes.
- llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
- for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
- TE = CG.parentless_end(); TI != TE; ++TI) {
- TopLevelFunctions.push_back(*TI);
+ // Walk over all of the call graph nodes in topological order, so that we
+ // analyze parents before the children. Skip the functions inlined into
+ // the previously processed functions. Use external Visited set to identify
+ // inlined functions. The topological order allows the "do not reanalyze
+ // previously inlined function" performance heuristic to be triggered more
+ // often.
+ SetOfConstDecls Visited;
+ SetOfConstDecls VisitedAsTopLevel;
+ llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
+ for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
+ I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
NumFunctionTopLevel++;
- }
- CallGraphNode *Entry = CG.getRoot();
- for (CallGraphNode::iterator I = Entry->begin(),
- E = Entry->end(); I != E; ++I) {
- TopLevelFunctions.push_back(*I);
- NumFunctionTopLevel++;
- }
- // Make sure the nodes are sorted in order reverse of their definition in the
- // translation unit. This step is very important for performance. It ensures
- // that we analyze the root functions before the externally available
- // subroutines.
- std::deque<CallGraphNode*> BFSQueue;
- for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
- TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
- TI != TE; ++TI)
- BFSQueue.push_back(*TI);
-
- // BFS over all of the functions, while skipping the ones inlined into
- // the previously processed functions. Use external Visited set, which is
- // also modified when we inline a function.
- SmallPtrSet<CallGraphNode*,24> Visited;
- while(!BFSQueue.empty()) {
- CallGraphNode *N = BFSQueue.front();
- BFSQueue.pop_front();
-
- // Push the children into the queue.
- for (CallGraphNode::const_iterator CI = N->begin(),
- CE = N->end(); CI != CE; ++CI) {
- if (!shouldSkipFunction(*CI, Visited))
- BFSQueue.push_back(*CI);
- }
+ CallGraphNode *N = *I;
+ Decl *D = N->getDecl();
+
+ // Skip the abstract root node.
+ if (!D)
+ continue;
// Skip the functions which have been processed already or previously
// inlined.
- if (shouldSkipFunction(N, Visited))
+ if (shouldSkipFunction(D, Visited, VisitedAsTopLevel))
continue;
// Analyze the function.
SetOfConstDecls VisitedCallees;
- Decl *D = N->getDecl();
- assert(D);
- HandleCode(D, AM_Path,
+
+ HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
(Mgr->options.InliningMode == All ? 0 : &VisitedCallees));
// Add the visited callees to the global visited set.
for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
E = VisitedCallees.end(); I != E; ++I) {
- CallGraphNode *VN = CG.getNode(*I);
- if (VN)
- Visited.insert(VN);
+ Visited.insert(*I);
}
- Visited.insert(N);
+ VisitedAsTopLevel.insert(D);
}
}
@@ -503,16 +534,6 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
}
-static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
- if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
- WL.push_back(BD);
-
- for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
- I!=E; ++I)
- if (DeclContext *DC = dyn_cast<DeclContext>(*I))
- FindBlocks(DC, WL);
-}
-
static std::string getFunctionName(const Decl *D) {
if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
return ID->getSelector().getAsString();
@@ -548,40 +569,32 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
}
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees) {
+ if (!D->hasBody())
+ return;
Mode = getModeForDecl(D, Mode);
if (Mode == AM_None)
return;
- DisplayFunction(D, Mode);
+ DisplayFunction(D, Mode, IMode);
CFG *DeclCFG = Mgr->getCFG(D);
if (DeclCFG) {
unsigned CFGSize = DeclCFG->size();
MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
}
-
// Clear the AnalysisManager of old AnalysisDeclContexts.
Mgr->ClearContexts();
-
- // Dispatch on the actions.
- SmallVector<Decl*, 10> WL;
- WL.push_back(D);
-
- if (D->hasBody() && Opts->AnalyzeNestedBlocks)
- FindBlocks(cast<DeclContext>(D), WL);
-
BugReporter BR(*Mgr);
- for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
- WI != WE; ++WI)
- if ((*WI)->hasBody()) {
- if (Mode & AM_Syntax)
- checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
- RunPathSensitiveChecks(*WI, VisitedCallees);
- NumFunctionsAnalyzed++;
- }
- }
+
+ if (Mode & AM_Syntax)
+ checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
+ if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
+ RunPathSensitiveChecks(D, IMode, VisitedCallees);
+ if (IMode != ExprEngine::Inline_Minimal)
+ NumFunctionsAnalyzed++;
+ }
}
//===----------------------------------------------------------------------===//
@@ -589,6 +602,7 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
//===----------------------------------------------------------------------===//
void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees) {
// Construct the analysis engine. First check if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
@@ -599,7 +613,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
return;
- ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
+ ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
// Set the graph auditor.
OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -610,7 +624,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
// Execute the worklist algorithm.
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
- Mgr->options.MaxNodes);
+ Mgr->options.getMaxNodesPerTopLevelFunction());
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
@@ -625,20 +639,21 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
}
void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *Visited) {
switch (Mgr->getLangOpts().getGC()) {
case LangOptions::NonGC:
- ActionExprEngine(D, false, Visited);
+ ActionExprEngine(D, false, IMode, Visited);
break;
case LangOptions::GCOnly:
- ActionExprEngine(D, true, Visited);
+ ActionExprEngine(D, true, IMode, Visited);
break;
case LangOptions::HybridGC:
- ActionExprEngine(D, false, Visited);
- ActionExprEngine(D, true, Visited);
+ ActionExprEngine(D, false, IMode, Visited);
+ ActionExprEngine(D, true, IMode, Visited);
break;
}
}
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index e8daa65e410a..4fad5a8a7c59 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
-#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Basic/Diagnostic.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 "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/SmallVector.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index 85a18ec98ead..13971af9afad 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
#include "AnalysisConsumer.h"
+#include "clang/Frontend/CompilerInstance.h"
using namespace clang;
using namespace ento;
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 15091c7e901e..99aff9f4e973 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -38,8 +38,8 @@ const char *const CommonOptionsParser::HelpMessage =
"\tFor example, it can be a CMake build directory in which a file named\n"
"\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
"\tCMake option to get this output). When no build path is specified,\n"
- "\tclang-check will attempt to locate it automatically using all parent\n"
- "\tpaths of the first input file. See:\n"
+ "\ta search for compile_commands.json will be attempted through all\n"
+ "\tparent paths of the first input file . See:\n"
"\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
"\texample of setting up Clang Tooling on a source tree.\n"
"\n"
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 4149cda3787c..b5b99cb7c63e 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -12,13 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#include <sstream>
#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>
namespace clang {
namespace tooling {
@@ -72,7 +72,7 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
CompilationDatabase *
CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
std::string &ErrorMessage) {
- llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
+ SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
@@ -87,7 +87,7 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
CompilationDatabase *
CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
std::string &ErrorMessage) {
- llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
+ SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
ErrorMessage);
@@ -132,6 +132,11 @@ FixedCompilationDatabase::getAllFiles() const {
return std::vector<std::string>();
}
+std::vector<CompileCommand>
+FixedCompilationDatabase::getAllCompileCommands() const {
+ return std::vector<CompileCommand>();
+}
+
// This anchor is used to force the linker to link in the generated object file
// and thus register the JSONCompilationDatabasePlugin.
extern volatile int JSONAnchorSource;
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
index 8f25a8c2bcfb..5eb4bb9e49d6 100644
--- a/lib/Tooling/FileMatchTrie.cpp
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include <sstream>
#include "clang/Tooling/FileMatchTrie.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h"
+#include <sstream>
namespace clang {
namespace tooling {
@@ -172,7 +172,7 @@ void FileMatchTrie::insert(StringRef NewPath) {
}
StringRef FileMatchTrie::findEquivalent(StringRef FileName,
- llvm::raw_ostream &Error) const {
+ raw_ostream &Error) const {
if (llvm::sys::path::is_relative(FileName)) {
Error << "Cannot resolve relative paths";
return StringRef();
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index cf35a2566637..254b069952da 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/JSONCompilationDatabase.h"
-
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
@@ -50,7 +49,9 @@ class CommandLineArgumentParser {
bool parseStringInto(std::string &String) {
do {
if (*Position == '"') {
- if (!parseQuotedStringInto(String)) return false;
+ if (!parseDoubleQuotedStringInto(String)) return false;
+ } else if (*Position == '\'') {
+ if (!parseSingleQuotedStringInto(String)) return false;
} else {
if (!parseFreeStringInto(String)) return false;
}
@@ -58,7 +59,7 @@ class CommandLineArgumentParser {
return true;
}
- bool parseQuotedStringInto(std::string &String) {
+ bool parseDoubleQuotedStringInto(std::string &String) {
if (!next()) return false;
while (*Position != '"') {
if (!skipEscapeCharacter()) return false;
@@ -68,12 +69,21 @@ class CommandLineArgumentParser {
return next();
}
+ bool parseSingleQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '\'') {
+ String.push_back(*Position);
+ if (!next()) return false;
+ }
+ return next();
+ }
+
bool parseFreeStringInto(std::string &String) {
do {
if (!skipEscapeCharacter()) return false;
String.push_back(*Position);
if (!next()) return false;
- } while (*Position != ' ' && *Position != '"');
+ } while (*Position != ' ' && *Position != '"' && *Position != '\'');
return true;
}
@@ -112,9 +122,9 @@ std::vector<std::string> unescapeCommandLine(
class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
virtual CompilationDatabase *loadFromDirectory(
StringRef Directory, std::string &ErrorMessage) {
- llvm::SmallString<1024> JSONDatabasePath(Directory);
+ SmallString<1024> JSONDatabasePath(Directory);
llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
- llvm::OwningPtr<CompilationDatabase> Database(
+ OwningPtr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
if (!Database)
return NULL;
@@ -134,14 +144,14 @@ volatile int JSONAnchorSource = 0;
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
+ OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
llvm::error_code Result =
llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
if (Result != 0) {
ErrorMessage = "Error while opening JSON database: " + Result.message();
return NULL;
}
- llvm::OwningPtr<JSONCompilationDatabase> Database(
+ OwningPtr<JSONCompilationDatabase> Database(
new JSONCompilationDatabase(DatabaseBuffer.take()));
if (!Database->parse(ErrorMessage))
return NULL;
@@ -151,10 +161,10 @@ JSONCompilationDatabase::loadFromFile(StringRef FilePath,
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
+ OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
llvm::MemoryBuffer::getMemBuffer(DatabaseString));
- llvm::OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
+ OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
if (!Database->parse(ErrorMessage))
return NULL;
return Database.take();
@@ -162,32 +172,20 @@ JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
std::vector<CompileCommand>
JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
- llvm::SmallString<128> NativeFilePath;
+ 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);
- if (Match.empty()) {
- if (Error.empty())
- Error = "No match found.";
- llvm::outs() << Error << "\n";
+ if (Match.empty())
return std::vector<CompileCommand>();
- }
llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
CommandsRefI = IndexByFile.find(Match);
if (CommandsRefI == IndexByFile.end())
return std::vector<CompileCommand>();
- const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue();
std::vector<CompileCommand> Commands;
- for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
- llvm::SmallString<8> DirectoryStorage;
- llvm::SmallString<1024> CommandStorage;
- Commands.push_back(CompileCommand(
- // FIXME: Escape correctly:
- CommandsRef[I].first->getValue(DirectoryStorage),
- unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
- }
+ getCommands(CommandsRefI->getValue(), Commands);
return Commands;
}
@@ -206,6 +204,30 @@ JSONCompilationDatabase::getAllFiles() const {
return Result;
}
+std::vector<CompileCommand>
+JSONCompilationDatabase::getAllCompileCommands() const {
+ std::vector<CompileCommand> Commands;
+ for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
+ CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
+ getCommands(CommandsRefI->getValue(), Commands);
+ }
+ return Commands;
+}
+
+void JSONCompilationDatabase::getCommands(
+ ArrayRef<CompileCommandRef> CommandsRef,
+ std::vector<CompileCommand> &Commands) const {
+ for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
+ SmallString<8> DirectoryStorage;
+ SmallString<1024> CommandStorage;
+ Commands.push_back(CompileCommand(
+ // FIXME: Escape correctly:
+ CommandsRef[I].first->getValue(DirectoryStorage),
+ unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
+ }
+}
+
bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
llvm::yaml::document_iterator I = YAMLStream.begin();
if (I == YAMLStream.end()) {
@@ -217,8 +239,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
ErrorMessage = "Error while parsing YAML.";
return false;
}
- llvm::yaml::SequenceNode *Array =
- llvm::dyn_cast<llvm::yaml::SequenceNode>(Root);
+ llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
if (Array == NULL) {
ErrorMessage = "Expected array.";
return false;
@@ -226,8 +247,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
AE = Array->end();
AI != AE; ++AI) {
- llvm::yaml::MappingNode *Object =
- llvm::dyn_cast<llvm::yaml::MappingNode>(&*AI);
+ llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
if (Object == NULL) {
ErrorMessage = "Expected object.";
return false;
@@ -244,18 +264,18 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
return false;
}
llvm::yaml::ScalarNode *ValueString =
- llvm::dyn_cast<llvm::yaml::ScalarNode>(Value);
+ dyn_cast<llvm::yaml::ScalarNode>(Value);
if (ValueString == NULL) {
ErrorMessage = "Expected string as value.";
return false;
}
llvm::yaml::ScalarNode *KeyString =
- llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
+ dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
if (KeyString == NULL) {
ErrorMessage = "Expected strings as key.";
return false;
}
- llvm::SmallString<8> KeyStorage;
+ SmallString<8> KeyStorage;
if (KeyString->getValue(KeyStorage) == "directory") {
Directory = ValueString;
} else if (KeyString->getValue(KeyStorage) == "command") {
@@ -280,12 +300,12 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
ErrorMessage = "Missing key: \"directory\".";
return false;
}
- llvm::SmallString<8> FileStorage;
+ SmallString<8> FileStorage;
StringRef FileName = File->getValue(FileStorage);
- llvm::SmallString<128> NativeFilePath;
+ SmallString<128> NativeFilePath;
if (llvm::sys::path::is_relative(FileName)) {
- llvm::SmallString<8> DirectoryStorage;
- llvm::SmallString<128> AbsolutePath(
+ SmallString<8> DirectoryStorage;
+ SmallString<128> AbsolutePath(
Directory->getValue(DirectoryStorage));
llvm::sys::path::append(AbsolutePath, FileName);
llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index c5002ef9fcfc..d8440d639d06 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -28,18 +28,18 @@ static const char * const InvalidLocation = "";
Replacement::Replacement()
: FilePath(InvalidLocation), Offset(0), Length(0) {}
-Replacement::Replacement(llvm::StringRef FilePath, unsigned Offset,
- unsigned Length, llvm::StringRef ReplacementText)
+Replacement::Replacement(StringRef FilePath, unsigned Offset,
+ unsigned Length, StringRef ReplacementText)
: FilePath(FilePath), Offset(Offset),
Length(Length), ReplacementText(ReplacementText) {}
Replacement::Replacement(SourceManager &Sources, SourceLocation Start,
- unsigned Length, llvm::StringRef ReplacementText) {
+ unsigned Length, StringRef ReplacementText) {
setFromSourceLocation(Sources, Start, Length, ReplacementText);
}
Replacement::Replacement(SourceManager &Sources, const CharSourceRange &Range,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
setFromSourceRange(Sources, Range, ReplacementText);
}
@@ -89,7 +89,7 @@ bool Replacement::Less::operator()(const Replacement &R1,
void Replacement::setFromSourceLocation(SourceManager &Sources,
SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
const std::pair<FileID, unsigned> DecomposedLocation =
Sources.getDecomposedLoc(Start);
const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
@@ -116,7 +116,7 @@ static int getRangeSize(SourceManager &Sources, const CharSourceRange &Range) {
void Replacement::setFromSourceRange(SourceManager &Sources,
const CharSourceRange &Range,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
getRangeSize(Sources, Range), ReplacementText);
}
@@ -135,7 +135,38 @@ bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite) {
return Result;
}
-bool saveRewrittenFiles(Rewriter &Rewrite) {
+RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
+ ArrayRef<std::string> SourcePaths)
+ : ClangTool(Compilations, SourcePaths) {}
+
+Replacements &RefactoringTool::getReplacements() { return Replace; }
+
+int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
+ if (int Result = run(ActionFactory)) {
+ return Result;
+ }
+
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagnosticPrinter, false);
+ SourceManager Sources(Diagnostics, getFiles());
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+
+ if (!applyAllReplacements(Rewrite)) {
+ llvm::errs() << "Skipped some replacements.\n";
+ }
+
+ return saveRewrittenFiles(Rewrite);
+}
+
+bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
+ return tooling::applyAllReplacements(Replace, Rewrite);
+}
+
+int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
E = Rewrite.buffer_end();
I != E; ++I) {
@@ -148,37 +179,11 @@ bool saveRewrittenFiles(Rewriter &Rewrite) {
llvm::raw_fd_ostream FileStream(
Entry->getName(), ErrorInfo, llvm::raw_fd_ostream::F_Binary);
if (!ErrorInfo.empty())
- return false;
+ return 1;
I->second.write(FileStream);
FileStream.flush();
}
- return true;
-}
-
-RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
- ArrayRef<std::string> SourcePaths)
- : Tool(Compilations, SourcePaths) {}
-
-Replacements &RefactoringTool::getReplacements() { return Replace; }
-
-int RefactoringTool::run(FrontendActionFactory *ActionFactory) {
- int Result = Tool.run(ActionFactory);
- LangOptions DefaultLangOptions;
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
- DiagnosticsEngine Diagnostics(
- llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
- &*DiagOpts, &DiagnosticPrinter, false);
- SourceManager Sources(Diagnostics, Tool.getFiles());
- Rewriter Rewrite(Sources, DefaultLangOptions);
- if (!applyAllReplacements(Replace, Rewrite)) {
- llvm::errs() << "Skipped some replacements.\n";
- }
- if (!saveRewrittenFiles(Rewrite)) {
- llvm::errs() << "Could not save rewritten files.\n";
- return 1;
- }
- return Result;
+ return 0;
}
} // end namespace tooling
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index af20254811aa..52855f657f64 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -12,16 +12,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/Tooling.h"
-#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
@@ -48,7 +49,7 @@ static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics,
const std::string DefaultOutputName = "a.out";
clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
BinaryName, llvm::sys::getDefaultTargetTriple(),
- DefaultOutputName, false, *Diagnostics);
+ DefaultOutputName, *Diagnostics);
CompilerDriver->setTitle("clang_based_tool");
return CompilerDriver;
}
@@ -63,7 +64,7 @@ static const clang::driver::ArgStringList *getCC1Arguments(
// failed. Extract that job from the Compilation.
const clang::driver::JobList &Jobs = Compilation->getJobs();
if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> error_msg;
+ SmallString<256> error_msg;
llvm::raw_svector_ostream error_stream(error_msg);
Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
@@ -121,7 +122,7 @@ bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
}
std::string getAbsolutePath(StringRef File) {
- llvm::SmallString<1024> BaseDirectory;
+ SmallString<1024> BaseDirectory;
if (const char *PWD = ::getenv("PWD"))
BaseDirectory = PWD;
else
@@ -136,7 +137,7 @@ std::string getAbsolutePath(StringRef File) {
if (RelativePath.startswith("./")) {
RelativePath = RelativePath.substr(strlen("./"));
}
- llvm::SmallString<1024> AbsolutePath(BaseDirectory);
+ SmallString<1024> AbsolutePath(BaseDirectory);
llvm::sys::path::append(AbsolutePath, RelativePath);
llvm::sys::path::native(Twine(AbsolutePath), PathStorage);
return PathStorage.str();
@@ -163,31 +164,29 @@ bool ToolInvocation::run() {
TextDiagnosticPrinter DiagnosticPrinter(
llvm::errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
+ IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
&*DiagOpts, &DiagnosticPrinter, false);
- const llvm::OwningPtr<clang::driver::Driver> Driver(
+ const OwningPtr<clang::driver::Driver> Driver(
newDriver(&Diagnostics, BinaryName));
// Since the input might only be virtual, don't check whether it exists.
Driver->setCheckInputsExist(false);
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
+ const OwningPtr<clang::driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
const clang::driver::ArgStringList *const CC1Args = getCC1Arguments(
&Diagnostics, Compilation.get());
if (CC1Args == NULL) {
return false;
}
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
+ OwningPtr<clang::CompilerInvocation> Invocation(
newInvocation(&Diagnostics, *CC1Args));
- return runInvocation(BinaryName, Compilation.get(), Invocation.take(),
- *CC1Args);
+ return runInvocation(BinaryName, Compilation.get(), Invocation.take());
}
bool ToolInvocation::runInvocation(
const char *BinaryName,
clang::driver::Compilation *Compilation,
- clang::CompilerInvocation *Invocation,
- const clang::driver::ArgStringList &CC1Args) {
+ clang::CompilerInvocation *Invocation) {
// Show the invocation, with -v.
if (Invocation->getHeaderSearchOpts().Verbose) {
llvm::errs() << "clang Invocation:\n";
@@ -204,11 +203,10 @@ bool ToolInvocation::runInvocation(
// ToolAction 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.
- llvm::OwningPtr<FrontendAction> ScopedToolAction(ToolAction.take());
+ OwningPtr<FrontendAction> ScopedToolAction(ToolAction.take());
// Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics(CC1Args.size(),
- const_cast<char**>(CC1Args.data()));
+ Compiler.createDiagnostics();
if (!Compiler.hasDiagnostics())
return false;
@@ -241,7 +239,7 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
: Files((FileSystemOptions())),
ArgsAdjuster(new ClangSyntaxOnlyAdjuster()) {
for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {
- llvm::SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
+ SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
std::vector<CompileCommand> CompileCommandsForFile =
Compilations.getCompileCommands(File.str());
@@ -298,14 +296,19 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) {
ArgsAdjuster->Adjust(CompileCommands[I].second.CommandLine);
assert(!CommandLine.empty());
CommandLine[0] = MainExecutable;
- llvm::outs() << "Processing: " << File << ".\n";
+ // FIXME: We need a callback mechanism for the tool writer to output a
+ // customized message for each file.
+ DEBUG({
+ llvm::dbgs() << "Processing: " << File << ".\n";
+ });
ToolInvocation Invocation(CommandLine, ActionFactory->create(), &Files);
for (int I = 0, E = MappedFileContents.size(); I != E; ++I) {
Invocation.mapVirtualFile(MappedFileContents[I].first,
MappedFileContents[I].second);
}
if (!Invocation.run()) {
- llvm::outs() << "Error while processing " << File << ".\n";
+ // FIXME: Diagnostics should be used instead.
+ llvm::errs() << "Error while processing " << File << ".\n";
ProcessingFailed = true;
}
}