aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ARCMigrate/ARCMT.cpp75
-rw-r--r--lib/ARCMigrate/CMakeLists.txt3
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp2
-rw-r--r--lib/ARCMigrate/Internals.h2
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp2
-rw-r--r--lib/ARCMigrate/Transforms.cpp4
-rw-r--r--lib/AST/ASTConsumer.cpp5
-rw-r--r--lib/AST/ASTContext.cpp325
-rw-r--r--lib/AST/ASTDiagnostic.cpp277
-rw-r--r--lib/AST/ASTImporter.cpp478
-rw-r--r--lib/AST/CMakeLists.txt3
-rw-r--r--lib/AST/CXXInheritance.cpp32
-rw-r--r--lib/AST/Comment.cpp93
-rw-r--r--lib/AST/CommentBriefParser.cpp51
-rw-r--r--lib/AST/CommentCommandTraits.cpp141
-rw-r--r--lib/AST/CommentDumper.cpp48
-rw-r--r--lib/AST/CommentLexer.cpp62
-rw-r--r--lib/AST/CommentParser.cpp72
-rw-r--r--lib/AST/CommentSema.cpp314
-rw-r--r--lib/AST/Decl.cpp88
-rw-r--r--lib/AST/DeclBase.cpp2
-rw-r--r--lib/AST/DeclCXX.cpp30
-rw-r--r--lib/AST/DeclObjC.cpp269
-rw-r--r--lib/AST/DeclPrinter.cpp18
-rw-r--r--lib/AST/DeclTemplate.cpp86
-rw-r--r--lib/AST/DumpXML.cpp23
-rw-r--r--lib/AST/Expr.cpp299
-rw-r--r--lib/AST/ExprCXX.cpp121
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp61
-rw-r--r--lib/AST/ItaniumMangle.cpp133
-rw-r--r--lib/AST/MicrosoftMangle.cpp242
-rw-r--r--lib/AST/NSAPI.cpp1
-rw-r--r--lib/AST/ParentMap.cpp69
-rw-r--r--lib/AST/RawCommentList.cpp69
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp84
-rw-r--r--lib/AST/Stmt.cpp167
-rw-r--r--lib/AST/StmtDumper.cpp115
-rw-r--r--lib/AST/StmtPrinter.cpp68
-rw-r--r--lib/AST/StmtProfile.cpp16
-rw-r--r--lib/AST/TemplateBase.cpp63
-rw-r--r--lib/AST/Type.cpp55
-rw-r--r--lib/AST/TypeLoc.cpp55
-rw-r--r--lib/AST/TypePrinter.cpp14
-rw-r--r--lib/AST/VTableBuilder.cpp3
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp411
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp66
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp41
-rw-r--r--lib/Analysis/BodyFarm.cpp374
-rw-r--r--lib/Analysis/BodyFarm.h43
-rw-r--r--lib/Analysis/CFG.cpp83
-rw-r--r--lib/Analysis/CMakeLists.txt4
-rw-r--r--lib/Analysis/FormatString.cpp57
-rw-r--r--lib/Analysis/ObjCNoReturn.cpp67
-rw-r--r--lib/Analysis/PrintfFormatString.cpp43
-rw-r--r--lib/Analysis/ReachableCode.cpp4
-rw-r--r--lib/Analysis/ScanfFormatString.cpp36
-rw-r--r--lib/Analysis/ThreadSafety.cpp340
-rw-r--r--lib/Analysis/UninitializedValues.cpp64
-rw-r--r--lib/Basic/ConvertUTF.c24
-rw-r--r--lib/Basic/ConvertUTFWrapper.cpp18
-rw-r--r--lib/Basic/Diagnostic.cpp25
-rw-r--r--lib/Basic/DiagnosticIDs.cpp5
-rw-r--r--lib/Basic/FileManager.cpp7
-rw-r--r--lib/Basic/IdentifierTable.cpp4
-rw-r--r--lib/Basic/Module.cpp11
-rw-r--r--lib/Basic/SourceLocation.cpp7
-rw-r--r--lib/Basic/SourceManager.cpp133
-rw-r--r--lib/Basic/TargetInfo.cpp8
-rw-r--r--lib/Basic/Targets.cpp406
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/CodeGen/ABIInfo.h38
-rw-r--r--lib/CodeGen/BackendUtil.cpp109
-rw-r--r--lib/CodeGen/CGBlocks.cpp138
-rw-r--r--lib/CodeGen/CGBlocks.h26
-rw-r--r--lib/CodeGen/CGBuiltin.cpp430
-rw-r--r--lib/CodeGen/CGCXXABI.cpp2
-rw-r--r--lib/CodeGen/CGCXXABI.h12
-rw-r--r--lib/CodeGen/CGCall.cpp223
-rw-r--r--lib/CodeGen/CGClass.cpp31
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp257
-rw-r--r--lib/CodeGen/CGDebugInfo.h3
-rw-r--r--lib/CodeGen/CGDecl.cpp53
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp77
-rw-r--r--lib/CodeGen/CGException.cpp17
-rw-r--r--lib/CodeGen/CGExpr.cpp568
-rw-r--r--lib/CodeGen/CGExprAgg.cpp32
-rw-r--r--lib/CodeGen/CGExprCXX.cpp71
-rw-r--r--lib/CodeGen/CGExprComplex.cpp5
-rw-r--r--lib/CodeGen/CGExprConstant.cpp41
-rw-r--r--lib/CodeGen/CGExprScalar.cpp482
-rw-r--r--lib/CodeGen/CGObjC.cpp86
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp156
-rw-r--r--lib/CodeGen/CGObjCMac.cpp798
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp7
-rw-r--r--lib/CodeGen/CGObjCRuntime.h8
-rw-r--r--lib/CodeGen/CGRTTI.cpp17
-rw-r--r--lib/CodeGen/CGRecordLayout.h4
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp26
-rw-r--r--lib/CodeGen/CGStmt.cpp128
-rw-r--r--lib/CodeGen/CGVTables.cpp60
-rw-r--r--lib/CodeGen/CodeGenAction.cpp6
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp66
-rw-r--r--lib/CodeGen/CodeGenFunction.h133
-rw-r--r--lib/CodeGen/CodeGenModule.cpp227
-rw-r--r--lib/CodeGen/CodeGenModule.h36
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp57
-rw-r--r--lib/CodeGen/CodeGenTBAA.h15
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp4
-rw-r--r--lib/CodeGen/CodeGenTypes.h6
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp58
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp65
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp6
-rw-r--r--lib/CodeGen/TargetInfo.cpp752
-rw-r--r--lib/Driver/Arg.cpp34
-rw-r--r--lib/Driver/ArgList.cpp41
-rw-r--r--lib/Driver/CC1AsOptions.cpp14
-rw-r--r--lib/Driver/Compilation.cpp100
-rw-r--r--lib/Driver/Driver.cpp248
-rw-r--r--lib/Driver/DriverOptions.cpp14
-rw-r--r--lib/Driver/OptTable.cpp158
-rw-r--r--lib/Driver/Option.cpp333
-rw-r--r--lib/Driver/SanitizerArgs.h106
-rw-r--r--lib/Driver/ToolChain.cpp61
-rw-r--r--lib/Driver/ToolChains.cpp481
-rw-r--r--lib/Driver/ToolChains.h43
-rw-r--r--lib/Driver/Tools.cpp980
-rw-r--r--lib/Driver/Tools.h5
-rw-r--r--lib/Driver/Types.cpp14
-rw-r--r--lib/Driver/WindowsToolChain.cpp14
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp1
-rw-r--r--lib/Frontend/ASTConsumers.cpp5
-rw-r--r--lib/Frontend/ASTMerge.cpp5
-rw-r--r--lib/Frontend/ASTUnit.cpp306
-rw-r--r--lib/Frontend/ChainedDiagnosticConsumer.cpp2
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp22
-rw-r--r--lib/Frontend/CompilerInstance.cpp139
-rw-r--r--lib/Frontend/CompilerInvocation.cpp1261
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp11
-rw-r--r--lib/Frontend/DependencyFile.cpp10
-rw-r--r--lib/Frontend/DependencyGraph.cpp10
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp94
-rw-r--r--lib/Frontend/FrontendAction.cpp76
-rw-r--r--lib/Frontend/FrontendActions.cpp133
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp6
-rw-r--r--lib/Frontend/InitPreprocessor.cpp86
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp7
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp8
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp232
-rw-r--r--lib/Frontend/TextDiagnostic.cpp203
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp10
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp213
-rw-r--r--lib/Frontend/Warnings.cpp5
-rw-r--r--lib/FrontendTool/CMakeLists.txt3
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp9
-rw-r--r--lib/Headers/CMakeLists.txt4
-rw-r--r--lib/Headers/__wmmintrin_aes.h67
-rw-r--r--lib/Headers/__wmmintrin_pclmul.h34
-rw-r--r--lib/Headers/altivec.h26
-rw-r--r--lib/Headers/bmi2intrin.h19
-rw-r--r--lib/Headers/cpuid.h2
-rw-r--r--lib/Headers/f16cintrin.h58
-rw-r--r--lib/Headers/immintrin.h4
-rw-r--r--lib/Headers/module.map37
-rw-r--r--lib/Headers/rtmintrin.h49
-rw-r--r--lib/Headers/unwind.h2
-rw-r--r--lib/Headers/wmmintrin.h41
-rw-r--r--lib/Headers/x86intrin.h4
-rw-r--r--lib/Headers/xmmintrin.h9
-rw-r--r--lib/Lex/HeaderMap.cpp2
-rw-r--r--lib/Lex/HeaderSearch.cpp47
-rw-r--r--lib/Lex/Lexer.cpp75
-rw-r--r--lib/Lex/LiteralSupport.cpp263
-rw-r--r--lib/Lex/MacroArgs.cpp2
-rw-r--r--lib/Lex/MacroInfo.cpp90
-rw-r--r--lib/Lex/ModuleMap.cpp524
-rw-r--r--lib/Lex/PPDirectives.cpp56
-rw-r--r--lib/Lex/PPExpressions.cpp20
-rw-r--r--lib/Lex/PPLexerChange.cpp6
-rw-r--r--lib/Lex/PPMacroExpansion.cpp333
-rw-r--r--lib/Lex/PTHLexer.cpp11
-rw-r--r--lib/Lex/Pragma.cpp22
-rw-r--r--lib/Lex/PreprocessingRecord.cpp56
-rw-r--r--lib/Lex/Preprocessor.cpp66
-rw-r--r--lib/Lex/TokenLexer.cpp88
-rw-r--r--lib/Parse/ParseAST.cpp1
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp6
-rw-r--r--lib/Parse/ParseDecl.cpp224
-rw-r--r--lib/Parse/ParseDeclCXX.cpp190
-rw-r--r--lib/Parse/ParseExpr.cpp179
-rw-r--r--lib/Parse/ParseExprCXX.cpp203
-rw-r--r--lib/Parse/ParseInit.cpp11
-rw-r--r--lib/Parse/ParseObjc.cpp67
-rw-r--r--lib/Parse/ParsePragma.cpp248
-rw-r--r--lib/Parse/ParsePragma.h37
-rw-r--r--lib/Parse/ParseStmt.cpp297
-rw-r--r--lib/Parse/ParseTemplate.cpp10
-rw-r--r--lib/Parse/ParseTentative.cpp131
-rw-r--r--lib/Parse/Parser.cpp272
-rw-r--r--lib/Parse/RAIIObjectsForParser.h10
-rw-r--r--lib/Rewrite/CMakeLists.txt35
-rw-r--r--lib/Rewrite/Core/CMakeLists.txt24
-rw-r--r--lib/Rewrite/Core/DeltaTree.cpp (renamed from lib/Rewrite/DeltaTree.cpp)5
-rw-r--r--lib/Rewrite/Core/HTMLRewrite.cpp (renamed from lib/Rewrite/HTMLRewrite.cpp)5
-rw-r--r--lib/Rewrite/Core/Makefile18
-rw-r--r--lib/Rewrite/Core/RewriteRope.cpp (renamed from lib/Rewrite/RewriteRope.cpp)6
-rw-r--r--lib/Rewrite/Core/Rewriter.cpp (renamed from lib/Rewrite/Rewriter.cpp)2
-rw-r--r--lib/Rewrite/Core/TokenRewriter.cpp (renamed from lib/Rewrite/TokenRewriter.cpp)2
-rw-r--r--lib/Rewrite/Frontend/CMakeLists.txt28
-rw-r--r--lib/Rewrite/Frontend/FixItRewriter.cpp (renamed from lib/Rewrite/FixItRewriter.cpp)2
-rw-r--r--lib/Rewrite/Frontend/FrontendActions.cpp (renamed from lib/Rewrite/FrontendActions.cpp)8
-rw-r--r--lib/Rewrite/Frontend/HTMLPrint.cpp (renamed from lib/Rewrite/HTMLPrint.cpp)6
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp (renamed from lib/Rewrite/InclusionRewriter.cpp)12
-rw-r--r--lib/Rewrite/Frontend/Makefile18
-rw-r--r--lib/Rewrite/Frontend/RewriteMacros.cpp (renamed from lib/Rewrite/RewriteMacros.cpp)4
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp (renamed from lib/Rewrite/RewriteModernObjC.cpp)156
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp (renamed from lib/Rewrite/RewriteObjC.cpp)38
-rw-r--r--lib/Rewrite/Frontend/RewriteTest.cpp (renamed from lib/Rewrite/RewriteTest.cpp)4
-rw-r--r--lib/Rewrite/Makefile10
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp290
-rw-r--r--lib/Sema/CMakeLists.txt3
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp7
-rw-r--r--lib/Sema/DeclSpec.cpp38
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp2
-rw-r--r--lib/Sema/IdentifierResolver.cpp10
-rw-r--r--lib/Sema/JumpDiagnostics.cpp138
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp271
-rw-r--r--lib/Sema/ScopeInfo.cpp189
-rw-r--r--lib/Sema/Sema.cpp64
-rw-r--r--lib/Sema/SemaAccess.cpp17
-rw-r--r--lib/Sema/SemaAttr.cpp23
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp3
-rw-r--r--lib/Sema/SemaCast.cpp68
-rw-r--r--lib/Sema/SemaChecking.cpp706
-rw-r--r--lib/Sema/SemaCodeComplete.cpp86
-rw-r--r--lib/Sema/SemaDecl.cpp840
-rw-r--r--lib/Sema/SemaDeclAttr.cpp135
-rw-r--r--lib/Sema/SemaDeclCXX.cpp687
-rw-r--r--lib/Sema/SemaDeclObjC.cpp145
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp64
-rw-r--r--lib/Sema/SemaExpr.cpp475
-rw-r--r--lib/Sema/SemaExprCXX.cpp163
-rw-r--r--lib/Sema/SemaExprMember.cpp34
-rw-r--r--lib/Sema/SemaExprObjC.cpp124
-rw-r--r--lib/Sema/SemaInit.cpp120
-rw-r--r--lib/Sema/SemaLambda.cpp31
-rw-r--r--lib/Sema/SemaLookup.cpp43
-rw-r--r--lib/Sema/SemaObjCProperty.cpp227
-rw-r--r--lib/Sema/SemaOverload.cpp430
-rw-r--r--lib/Sema/SemaPseudoObject.cpp87
-rw-r--r--lib/Sema/SemaStmt.cpp930
-rw-r--r--lib/Sema/SemaStmtAsm.cpp661
-rw-r--r--lib/Sema/SemaStmtAttr.cpp9
-rw-r--r--lib/Sema/SemaTemplate.cpp370
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp160
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp126
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp172
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--lib/Sema/SemaType.cpp176
-rw-r--r--lib/Sema/TreeTransform.h360
-rw-r--r--lib/Serialization/ASTCommon.cpp3
-rw-r--r--lib/Serialization/ASTReader.cpp2323
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp151
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp35
-rw-r--r--lib/Serialization/ASTWriter.cpp781
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp58
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp28
-rw-r--r--lib/Serialization/GeneratePCH.cpp13
-rw-r--r--lib/Serialization/Module.cpp18
-rw-r--r--lib/Serialization/ModuleManager.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp92
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp109
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt6
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp77
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp1
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp59
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td83
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp72
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp60
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp180
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp550
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp41
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp259
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp87
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp218
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp203
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp94
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp356
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp348
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp46
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp36
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp138
-rw-r--r--lib/StaticAnalyzer/Core/BasicConstraintManager.cpp446
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp517
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp602
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt7
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp166
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp27
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp54
-rw-r--r--lib/StaticAnalyzer/Core/ConstraintManager.cpp39
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp204
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp155
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp414
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp133
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp79
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp351
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp82
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp34
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp306
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp47
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp68
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp308
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp37
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h4
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp25
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp86
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp109
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp1
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp154
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.h4
-rw-r--r--lib/StaticAnalyzer/Frontend/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp2
-rw-r--r--lib/Tooling/CMakeLists.txt7
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp (renamed from lib/Tooling/CommandLineClangTool.cpp)61
-rw-r--r--lib/Tooling/CompilationDatabase.cpp297
-rw-r--r--lib/Tooling/CustomCompilationDatabase.h42
-rw-r--r--lib/Tooling/FileMatchTrie.cpp188
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp303
-rw-r--r--lib/Tooling/Refactoring.cpp11
-rw-r--r--lib/Tooling/Tooling.cpp30
374 files changed, 27784 insertions, 14661 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index f291dec21fda..b57d9964736f 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -14,7 +14,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Lex/Preprocessor.h"
@@ -42,7 +42,7 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
++I;
// Clear the diagnostic and any notes following it.
- List.erase(eraseS, I);
+ I = List.erase(eraseS, I);
continue;
}
@@ -147,54 +147,10 @@ public:
} // end anonymous namespace
-static inline StringRef SimulatorVersionDefineName() {
- return "__IPHONE_OS_VERSION_MIN_REQUIRED=";
-}
-
-/// \brief Parse the simulator version define:
-/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9])
-// and return the grouped values as integers, e.g:
-// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
-// will return Major=4, Minor=2, Micro=1.
-static bool GetVersionFromSimulatorDefine(StringRef define,
- unsigned &Major, unsigned &Minor,
- unsigned &Micro) {
- assert(define.startswith(SimulatorVersionDefineName()));
- StringRef name, version;
- llvm::tie(name, version) = define.split('=');
- if (version.empty())
- return false;
- std::string verstr = version.str();
- char *end;
- unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10);
- if (*end != '\0')
- return false;
- Major = num / 10000;
- num = num % 10000;
- Minor = num / 100;
- Micro = num % 100;
- return true;
-}
-
static bool HasARCRuntime(CompilerInvocation &origCI) {
// This duplicates some functionality from Darwin::AddDeploymentTarget
// but this function is well defined, so keep it decoupled from the driver
// and avoid unrelated complications.
-
- for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size();
- i != e; ++i) {
- StringRef define = origCI.getPreprocessorOpts().Macros[i].first;
- bool isUndef = origCI.getPreprocessorOpts().Macros[i].second;
- if (isUndef)
- continue;
- if (!define.startswith(SimulatorVersionDefineName()))
- continue;
- unsigned Major = 0, Minor = 0, Micro = 0;
- if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
- Major < 10 && Minor < 100 && Micro < 100)
- return Major >= 5;
- }
-
llvm::Triple triple(origCI.getTargetOpts().Triple);
if (triple.getOS() == llvm::Triple::IOS)
@@ -237,18 +193,19 @@ createInvocationForMigration(CompilerInvocation &origCI) {
WarnOpts.push_back("error=arc-unsafe-retained-assign");
CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts);
- CInvok->getLangOpts()->ObjCRuntimeHasWeak = HasARCRuntime(origCI);
+ CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI);
return CInvok.take();
}
static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
- const DiagnosticOptions &diagOpts,
+ DiagnosticOptions *diagOpts,
Preprocessor &PP) {
TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, diagOpts, &printer,
+ /*ShouldOwnClient=*/false));
Diags->setSourceManager(&PP.getSourceManager());
printer.BeginSourceFile(PP.getLangOpts(), &PP);
@@ -286,7 +243,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
assert(DiagClient);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
@@ -314,7 +272,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
}
if (emitPremigrationARCErrors)
- emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(),
+ emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
Unit->getPreprocessor());
if (!plistOut.empty()) {
SmallVector<StoredDiagnostic, 8> arcDiags;
@@ -395,7 +353,8 @@ static bool applyTransforms(CompilerInvocation &origCI,
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
if (outputDir.empty()) {
origCI.getLangOpts()->ObjCAutoRefCount = true;
@@ -434,7 +393,8 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
FileRemapper remapper;
bool err = remapper.initFromDisk(outputDir, *Diags,
@@ -458,7 +418,8 @@ bool arcmt::getFileRemappingsFromFileList(
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
for (ArrayRef<StringRef>::iterator
I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
@@ -574,7 +535,8 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
if (!outputDir.empty()) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
}
}
@@ -593,7 +555,8 @@ bool MigrationProcess::applyTransform(TransformFn trans,
assert(DiagClient);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index f602fc8e5f88..731bcb4fc7f9 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -37,5 +37,6 @@ target_link_libraries(clangARCMigrate
clangAST
clangParse
clangFrontend
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
)
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index e9b49b3039ba..28ca9a56b20e 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Frontend/PreprocessorOptions.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/MemoryBuffer.h"
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 935fc9b52535..1966a9823b92 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -11,8 +11,10 @@
#define LLVM_CLANG_LIB_ARCMIGRATE_INTERNALS_H
#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include <list>
namespace clang {
class Sema;
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 0098f973e63d..dfe14e2b5dd7 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -18,7 +18,7 @@
#include "clang/Edit/EditedSource.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 1175c363163b..805a67d9d188 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -40,7 +40,7 @@ bool MigrationPass::CFBridgingFunctionsDefined() {
bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
bool AllowOnUnknownClass) {
- if (!Ctx.getLangOpts().ObjCRuntimeHasWeak)
+ if (!Ctx.getLangOpts().ObjCARCWeak)
return false;
QualType T = type;
@@ -59,7 +59,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
return false; // id/NSObject is not safe for weak.
if (!AllowOnUnknownClass && !Class->hasDefinition())
return false; // forward classes are not verifiable, therefore not safe.
- if (Class->isArcWeakrefUnavailable())
+ if (Class && Class->isArcWeakrefUnavailable())
return false;
}
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index 1672bc8aed7c..a4e17c03e4e3 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Decl.h"
using namespace clang;
bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
@@ -24,3 +25,7 @@ void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
}
void ASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {}
+
+void ASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
+ HandleTopLevelDecl(DeclGroupRef(D));
+}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c02132329e6d..74c68ae627ce 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/Comment.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -72,6 +73,22 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return NULL;
}
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->isStaticDataMember() &&
+ VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ return NULL;
+ }
+
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
+ if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ return NULL;
+ }
+
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ return NULL;
+ }
+
// TODO: handle comments for function parameters properly.
if (isa<ParmVarDecl>(D))
return NULL;
@@ -196,15 +213,72 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
namespace {
/// If we have a 'templated' declaration for a template, adjust 'D' to
/// refer to the actual template.
+/// If we have an implicit instantiation, adjust 'D' to refer to template.
const Decl *adjustDeclToTemplate(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Is this function declaration part of a function template?
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
- D = FTD;
- } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- if (const ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
- D = CTD;
+ return FTD;
+
+ // Nothing to do if function is not an implicit instantiation.
+ if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
+ return D;
+
+ // Function is an implicit instantiation of a function template?
+ if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
+ return FTD;
+
+ // Function is instantiated from a member definition of a class template?
+ if (const FunctionDecl *MemberDecl =
+ FD->getInstantiatedFromMemberFunction())
+ return MemberDecl;
+
+ return D;
}
- // FIXME: Alias templates?
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // Static data member is instantiated from a member definition of a class
+ // template?
+ if (VD->isStaticDataMember())
+ if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
+ return MemberDecl;
+
+ return D;
+ }
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
+ // Is this class declaration part of a class template?
+ if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
+ return CTD;
+
+ // Class is an implicit instantiation of a class template or partial
+ // specialization?
+ if (const ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(CRD)) {
+ if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation)
+ return D;
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ PU = CTSD->getSpecializedTemplateOrPartial();
+ return PU.is<ClassTemplateDecl*>() ?
+ static_cast<const Decl*>(PU.get<ClassTemplateDecl *>()) :
+ static_cast<const Decl*>(
+ PU.get<ClassTemplatePartialSpecializationDecl *>());
+ }
+
+ // Class is instantiated from a member definition of a class template?
+ if (const MemberSpecializationInfo *Info =
+ CRD->getMemberSpecializationInfo())
+ return Info->getInstantiatedFrom();
+
+ return D;
+ }
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ // Enum is instantiated from a member definition of a class template?
+ if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
+ return MemberDecl;
+
+ return D;
+ }
+ // FIXME: Adjust alias templates?
return D;
}
} // unnamed namespace
@@ -282,23 +356,83 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
return RC;
}
-comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const {
+static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
+ SmallVectorImpl<const NamedDecl *> &Redeclared) {
+ const DeclContext *DC = ObjCMethod->getDeclContext();
+ if (const ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(DC)) {
+ const ObjCInterfaceDecl *ID = IMD->getClassInterface();
+ if (!ID)
+ return;
+ // Add redeclared method here.
+ for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension();
+ ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+ if (ObjCMethodDecl *RedeclaredMethod =
+ ClsExtDecl->getMethod(ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod()))
+ Redeclared.push_back(RedeclaredMethod);
+ }
+ }
+}
+
+comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
+ const Decl *D) const {
+ comments::DeclInfo *ThisDeclInfo = new (*this) comments::DeclInfo;
+ ThisDeclInfo->CommentDecl = D;
+ ThisDeclInfo->IsFilled = false;
+ ThisDeclInfo->fill();
+ ThisDeclInfo->CommentDecl = FC->getDecl();
+ comments::FullComment *CFC =
+ new (*this) comments::FullComment(FC->getBlocks(),
+ ThisDeclInfo);
+ return CFC;
+
+}
+
+comments::FullComment *ASTContext::getCommentForDecl(
+ const Decl *D,
+ const Preprocessor *PP) const {
D = adjustDeclToTemplate(D);
+
const Decl *Canonical = D->getCanonicalDecl();
llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos =
ParsedComments.find(Canonical);
- if (Pos != ParsedComments.end())
+
+ if (Pos != ParsedComments.end()) {
+ if (Canonical != D) {
+ comments::FullComment *FC = Pos->second;
+ comments::FullComment *CFC = cloneFullComment(FC, D);
+ return CFC;
+ }
return Pos->second;
-
+ }
+
const Decl *OriginalDecl;
+
const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl);
- if (!RC)
+ if (!RC) {
+ if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
+ SmallVector<const NamedDecl*, 8> Overridden;
+ if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ 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;
+ }
+ }
+ }
return NULL;
-
+ }
+
+ // If the RawComment was attached to other redeclaration of this Decl, we
+ // should parse the comment in context of that other Decl. This is important
+ // because comments can contain references to parameter names which can be
+ // different across redeclarations.
if (D != OriginalDecl)
- return getCommentForDecl(OriginalDecl);
+ return getCommentForDecl(OriginalDecl, PP);
- comments::FullComment *FC = RC->parse(*this, D);
+ comments::FullComment *FC = RC->parse(*this, PP, D);
ParsedComments[Canonical] = FC;
return FC;
}
@@ -481,6 +615,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
Int128Decl(0), UInt128Decl(0),
BuiltinVaListDecl(0),
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
+ BOOLDecl(0),
CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
FILEDecl(0),
jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0),
@@ -495,6 +630,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DeclarationNames(*this),
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
+ CommentCommandTraits(BumpAlloc),
LastSDM(0, 0),
UniqueBlockByRefTypeID(0)
{
@@ -683,12 +819,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus) { // C++ 3.9.1p5
+ if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5
if (TargetInfo::isTypeSigned(Target.getWCharType()))
InitBuiltinType(WCharTy, BuiltinType::WChar_S);
else // -fshort-wchar makes wchar_t be unsigned.
InitBuiltinType(WCharTy, BuiltinType::WChar_U);
- } else // C99
+ } else // C99 (or C++ using -fno-wchar)
WCharTy = getFromTargetType(Target.getWCharType());
WIntTy = getFromTargetType(Target.getWIntType());
@@ -725,6 +861,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
// Placeholder type for unbridged ARC casts.
InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast);
+ // Placeholder type for builtin functions.
+ InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -909,7 +1048,7 @@ bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD,
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method);
+ = OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
return 0;
@@ -919,7 +1058,7 @@ ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method);
+ = OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
return 0;
@@ -929,7 +1068,7 @@ ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
unsigned
ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method);
+ = OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
return 0;
@@ -938,9 +1077,30 @@ ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const {
void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden) {
+ assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl());
OverriddenMethods[Method].push_back(Overridden);
}
+void ASTContext::getOverriddenMethods(
+ const NamedDecl *D,
+ SmallVectorImpl<const NamedDecl *> &Overridden) const {
+ assert(D);
+
+ if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
+ Overridden.append(CXXMethod->begin_overridden_methods(),
+ CXXMethod->end_overridden_methods());
+ return;
+ }
+
+ const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
+ if (!Method)
+ return;
+
+ SmallVector<const ObjCMethodDecl *, 8> OverDecls;
+ Method->getOverriddenMethods(OverDecls);
+ Overridden.append(OverDecls.begin(), OverDecls.end());
+}
+
void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
assert(!Import->NextLocalImport && "Import declaration already in the chain");
assert(!Import->isFromASTFile() && "Non-local import declaration");
@@ -1062,6 +1222,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
return toCharUnitsFromBits(Align);
}
+// getTypeInfoDataSizeInChars - Return the size of a type, in
+// chars. If the type is a record, its data size is returned. This is
+// the size of the memcpy that's performed when assigning this type
+// using a trivial copy/move assignment operator.
+std::pair<CharUnits, CharUnits>
+ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
+ std::pair<CharUnits, CharUnits> sizeAndAlign = getTypeInfoInChars(T);
+
+ // In C++, objects can sometimes be allocated into the tail padding
+ // of a base-class subobject. We decide whether that's possible
+ // during class layout, so here we can just trust the layout results.
+ if (getLangOpts().CPlusPlus) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl());
+ sizeAndAlign.first = layout.getDataSize();
+ }
+ }
+
+ return sizeAndAlign;
+}
+
std::pair<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(const Type *T) const {
std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
@@ -3353,6 +3534,12 @@ QualType ASTContext::getPointerDiffType() const {
return getFromTargetType(Target->getPtrDiffType(0));
}
+/// \brief Return the unique type for "pid_t" defined in
+/// <sys/types.h>. We need this to compute the correct type for vfork().
+QualType ASTContext::getProcessIDType() const {
+ return getFromTargetType(Target->getProcessIDType());
+}
+
//===----------------------------------------------------------------------===//
// Type Operators
//===----------------------------------------------------------------------===//
@@ -3581,11 +3768,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
return Arg;
case TemplateArgument::Declaration: {
- if (Decl *D = Arg.getAsDecl())
- return TemplateArgument(D->getCanonicalDecl());
- return TemplateArgument((Decl*)0);
+ ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
+ return TemplateArgument(D, Arg.isDeclForReferenceParam());
}
+ case TemplateArgument::NullPtr:
+ return TemplateArgument(getCanonicalType(Arg.getNullPtrType()),
+ /*isNullPtr*/true);
+
case TemplateArgument::Template:
return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
@@ -4297,7 +4487,13 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
QualType BlockTy =
Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
// Encode result type.
- getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), S);
+ if (getLangOpts().EncodeExtendedBlockSig)
+ getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None,
+ BlockTy->getAs<FunctionType>()->getResultType(),
+ S, true /*Extended*/);
+ else
+ getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(),
+ S);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
@@ -4332,7 +4528,11 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
PType = PVDecl->getType();
} else if (PType->isFunctionType())
PType = PVDecl->getType();
- getObjCEncodingForType(PType, S);
+ if (getLangOpts().EncodeExtendedBlockSig)
+ getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, PType,
+ S, true /*Extended*/);
+ else
+ getObjCEncodingForType(PType, S);
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
@@ -5393,6 +5593,65 @@ static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
return VaListTypedefDecl;
}
+static TypedefDecl *
+CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
+ RecordDecl *VaListDecl;
+ 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);
+
+ VaListDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__va_list"));
+
+ VaListDecl->setDeclContext(NS);
+
+ } else {
+ // struct __va_list {
+ VaListDecl = CreateRecordDecl(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ &Context->Idents.get("__va_list"));
+ }
+
+ VaListDecl->startDefinition();
+
+ // void * __ap;
+ FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
+ VaListDecl,
+ SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("__ap"),
+ Context->getPointerType(Context->VoidTy),
+ /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ ICIS_NoInit);
+ Field->setAccess(AS_public);
+ VaListDecl->addDecl(Field);
+
+ // };
+ VaListDecl->completeDefinition();
+
+ // typedef struct __va_list __builtin_va_list;
+ TypeSourceInfo *TInfo
+ = Context->getTrivialTypeSourceInfo(Context->getRecordType(VaListDecl));
+
+ TypedefDecl *VaListTypeDecl
+ = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__builtin_va_list"),
+ TInfo);
+
+ return VaListTypeDecl;
+}
+
static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
TargetInfo::BuiltinVaListKind Kind) {
switch (Kind) {
@@ -5406,6 +5665,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
return CreateX86_64ABIBuiltinVaListDecl(Context);
case TargetInfo::PNaClABIBuiltinVaList:
return CreatePNaClABIBuiltinVaListDecl(Context);
+ case TargetInfo::AAPCSABIBuiltinVaList:
+ return CreateAAPCSABIBuiltinVaListDecl(Context);
}
llvm_unreachable("Unhandled __builtin_va_list type kind");
@@ -5702,7 +5963,7 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
return false;
}
-/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
+/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...>
/// return true if lhs's protocols conform to rhs's protocol; false
/// otherwise.
bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
@@ -5711,8 +5972,8 @@ bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
return false;
}
-/// ObjCQualifiedClassTypesAreCompatible - compare Class<p,...> and
-/// Class<p1, ...>.
+/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
+/// Class<pr1, ...>.
bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
QualType rhs) {
const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>();
@@ -6315,10 +6576,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
for (unsigned i = 0; i < proto_nargs; ++i) {
QualType argTy = proto->getArgType(i);
- // Look at the promotion type of enum types, since that is the type used
+ // Look at the converted type of enum types, since that is the type used
// to pass enum values.
- if (const EnumType *Enum = argTy->getAs<EnumType>())
- argTy = Enum->getDecl()->getPromotionType();
+ if (const EnumType *Enum = argTy->getAs<EnumType>()) {
+ argTy = Enum->getDecl()->getIntegerType();
+ if (argTy.isNull())
+ return QualType();
+ }
if (argTy->isPromotableIntegerType() ||
getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
@@ -6725,7 +6989,7 @@ unsigned ASTContext::getIntWidth(QualType T) const {
return (unsigned)getTypeSize(T);
}
-QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
+QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
assert(T->hasSignedIntegerRepresentation() && "Unexpected type");
// Turn <4 x signed int> -> <4 x unsigned int>
@@ -6959,6 +7223,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
return QualType();
}
break;
+ case 'p':
+ Type = Context.getProcessIDType();
+ break;
}
// If there are modifiers and if we're allowed to parse them, go for it.
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index a605f1a40cb3..0b9c5249448f 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -430,6 +430,15 @@ class TemplateDiff {
/// arguments or the type arguments that are templates.
TemplateDecl *FromTD, *ToTD;
+ /// FromQual, ToQual - Qualifiers for template types.
+ Qualifiers FromQual, ToQual;
+
+ /// FromInt, ToInt - APSInt's for integral arguments.
+ llvm::APSInt FromInt, ToInt;
+
+ /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
+ bool IsValidFromInt, IsValidToInt;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -480,6 +489,21 @@ class TemplateDiff {
FlatTree[CurrentNode].ToExpr = ToExpr;
}
+ /// SetNode - Set FromInt and ToInt of the current node.
+ void SetNode(llvm::APSInt FromInt, llvm::APSInt ToInt,
+ bool IsValidFromInt, bool IsValidToInt) {
+ FlatTree[CurrentNode].FromInt = FromInt;
+ FlatTree[CurrentNode].ToInt = ToInt;
+ FlatTree[CurrentNode].IsValidFromInt = IsValidFromInt;
+ FlatTree[CurrentNode].IsValidToInt = IsValidToInt;
+ }
+
+ /// SetNode - Set FromQual and ToQual of the current node.
+ void SetNode(Qualifiers FromQual, Qualifiers ToQual) {
+ FlatTree[CurrentNode].FromQual = FromQual;
+ FlatTree[CurrentNode].ToQual = ToQual;
+ }
+
/// SetSame - Sets the same flag of the current node.
void SetSame(bool Same) {
FlatTree[CurrentNode].Same = Same;
@@ -557,6 +581,12 @@ class TemplateDiff {
(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;
@@ -575,6 +605,21 @@ class TemplateDiff {
ToTD = FlatTree[ReadNode].ToTD;
}
+ /// GetNode - Gets the FromInt and ToInt.
+ void GetNode(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
+ bool &IsValidFromInt, bool &IsValidToInt) {
+ FromInt = FlatTree[ReadNode].FromInt;
+ ToInt = FlatTree[ReadNode].ToInt;
+ IsValidFromInt = FlatTree[ReadNode].IsValidFromInt;
+ IsValidToInt = FlatTree[ReadNode].IsValidToInt;
+ }
+
+ /// GetNode - Gets the FromQual and ToQual.
+ void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) {
+ FromQual = FlatTree[ReadNode].FromQual;
+ ToQual = FlatTree[ReadNode].ToQual;
+ }
+
/// NodeIsSame - Returns true the arguments are the same.
bool NodeIsSame() {
return FlatTree[ReadNode].Same;
@@ -778,18 +823,21 @@ class TemplateDiff {
if (Context.hasSameType(FromType, ToType)) {
Tree.SetSame(true);
} else {
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
const TemplateSpecializationType *FromArgTST =
GetTemplateSpecializationType(Context, FromType);
const TemplateSpecializationType *ToArgTST =
GetTemplateSpecializationType(Context, ToType);
- if (FromArgTST && ToArgTST) {
- bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST);
- if (SameTemplate) {
- Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
- ToArgTST->getTemplateName().getAsTemplateDecl());
- DiffTemplate(FromArgTST, ToArgTST);
- }
+ if (FromArgTST && ToArgTST &&
+ hasSameTemplate(FromArgTST, ToArgTST)) {
+ FromQual -= QualType(FromArgTST, 0).getQualifiers();
+ ToQual -= QualType(ToArgTST, 0).getQualifiers();
+ Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
+ ToArgTST->getTemplateName().getAsTemplateDecl());
+ Tree.SetNode(FromQual, ToQual);
+ DiffTemplate(FromArgTST, ToArgTST);
}
}
}
@@ -799,12 +847,41 @@ class TemplateDiff {
if (NonTypeTemplateParmDecl *DefaultNTTPD =
dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
Expr *FromExpr, *ToExpr;
- GetExpr(FromIter, DefaultNTTPD, FromExpr);
- GetExpr(ToIter, DefaultNTTPD, ToExpr);
- Tree.SetNode(FromExpr, ToExpr);
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
- Tree.SetDefault(FromIter.isEnd() && FromExpr,
- ToIter.isEnd() && ToExpr);
+ llvm::APSInt FromInt, ToInt;
+ bool HasFromInt = !FromIter.isEnd() &&
+ FromIter->getKind() == TemplateArgument::Integral;
+ bool HasToInt = !ToIter.isEnd() &&
+ ToIter->getKind() == TemplateArgument::Integral;
+ //bool IsValidFromInt = false, IsValidToInt = false;
+ if (HasFromInt)
+ FromInt = FromIter->getAsIntegral();
+ else
+ GetExpr(FromIter, DefaultNTTPD, FromExpr);
+
+ if (HasToInt)
+ ToInt = ToIter->getAsIntegral();
+ else
+ GetExpr(ToIter, DefaultNTTPD, ToExpr);
+
+ if (!HasFromInt && !HasToInt) {
+ Tree.SetNode(FromExpr, ToExpr);
+ Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
+ Tree.SetDefault(FromIter.isEnd() && FromExpr,
+ ToIter.isEnd() && ToExpr);
+ } else {
+ if (!HasFromInt && FromExpr) {
+ FromInt = FromExpr->EvaluateKnownConstInt(Context);
+ HasFromInt = true;
+ }
+ if (!HasToInt && ToExpr) {
+ ToInt = ToExpr->EvaluateKnownConstInt(Context);
+ HasToInt = true;
+ }
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt));
+ Tree.SetDefault(FromIter.isEnd() && HasFromInt,
+ ToIter.isEnd() && HasToInt);
+ }
}
// Handle Templates
@@ -824,6 +901,26 @@ class TemplateDiff {
}
}
+ /// makeTemplateList - Dump every template alias into the vector.
+ static void makeTemplateList(
+ SmallVector<const TemplateSpecializationType*, 1> &TemplateList,
+ const TemplateSpecializationType *TST) {
+ while (TST) {
+ TemplateList.push_back(TST);
+ if (!TST->isTypeAlias())
+ return;
+ TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
+ }
+ }
+
+ /// hasSameBaseTemplate - Returns true when the base templates are the same,
+ /// 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();
+ }
+
/// hasSameTemplate - Returns true if both types are specialized from the
/// same template declaration. If they come from different template aliases,
/// do a parallel ascension search to determine the highest template alias in
@@ -831,49 +928,29 @@ class TemplateDiff {
static bool hasSameTemplate(const TemplateSpecializationType *&FromTST,
const TemplateSpecializationType *&ToTST) {
// Check the top templates if they are the same.
- if (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
- ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier())
+ if (hasSameBaseTemplate(FromTST, ToTST))
return true;
// Create vectors of template aliases.
SmallVector<const TemplateSpecializationType*, 1> FromTemplateList,
ToTemplateList;
- const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST;
- FromTemplateList.push_back(FromTST);
- ToTemplateList.push_back(ToTST);
-
- // Dump every template alias into the vectors.
- while (TempFromTST->isTypeAlias()) {
- TempFromTST =
- TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>();
- if (!TempFromTST)
- break;
- FromTemplateList.push_back(TempFromTST);
- }
- while (TempToTST->isTypeAlias()) {
- TempToTST =
- TempToTST->getAliasedType()->getAs<TemplateSpecializationType>();
- if (!TempToTST)
- break;
- ToTemplateList.push_back(TempToTST);
- }
+ makeTemplateList(FromTemplateList, FromTST);
+ makeTemplateList(ToTemplateList, ToTST);
SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
// Check if the lowest template types are the same. If not, return.
- if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=
- (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())
+ if (!hasSameBaseTemplate(*FromIter, *ToIter))
return false;
// Begin searching up the template aliases. The bottom most template
// matches so move up until one pair does not match. Use the template
// right before that one.
for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) {
- if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=
- (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())
+ if (!hasSameBaseTemplate(*FromIter, *ToIter))
break;
}
@@ -923,7 +1000,9 @@ class TemplateDiff {
bool isVariadic = DefaultTTPD->isParameterPack();
TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
- TemplateDecl *DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
+ TemplateDecl *DefaultTD = 0;
+ if (TA.getKind() != TemplateArgument::Null)
+ DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
if (!Iter.isEnd())
ArgDecl = Iter->getAsTemplate().getAsTemplateDecl();
@@ -1018,6 +1097,15 @@ class TemplateDiff {
Tree.ToDefault(), Tree.NodeIsSame());
return;
}
+
+ if (Tree.NodeIsAPSInt()) {
+ llvm::APSInt FromInt, ToInt;
+ bool IsValidFromInt, IsValidToInt;
+ Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
+ PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
llvm_unreachable("Unable to deduce template difference.");
}
@@ -1027,6 +1115,10 @@ class TemplateDiff {
assert(Tree.HasChildren() && "Template difference not found in diff tree.");
+ Qualifiers FromQual, ToQual;
+ Tree.GetNode(FromQual, ToQual);
+ PrintQualifiers(FromQual, ToQual);
+
OS << FromTD->getNameAsString() << '<';
Tree.MoveToChild();
unsigned NumElideArgs = 0;
@@ -1088,6 +1180,17 @@ class TemplateDiff {
return;
}
+ if (!FromType.isNull() && !ToType.isNull() &&
+ FromType.getLocalUnqualifiedType() ==
+ ToType.getLocalUnqualifiedType()) {
+ Qualifiers FromQual = FromType.getLocalQualifiers(),
+ ToQual = ToType.getLocalQualifiers(),
+ CommonQual;
+ PrintQualifiers(FromQual, ToQual);
+ FromType.getLocalUnqualifiedType().print(OS, Policy);
+ return;
+ }
+
std::string FromTypeStr = FromType.isNull() ? "(no argument)"
: FromType.getAsString();
std::string ToTypeStr = ToType.isNull() ? "(no argument)"
@@ -1177,6 +1280,34 @@ 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) {
+ assert((IsValidFromInt || IsValidToInt) &&
+ "Only one integral argument may be missing.");
+
+ if (Same) {
+ OS << FromInt.toString(10);
+ } else if (!PrintTree) {
+ OS << (FromDefault ? "(default) " : "");
+ Bold();
+ OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ Unbold();
+ } else {
+ OS << (FromDefault ? "[(default) " : "[");
+ Bold();
+ OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ Unbold();
+ OS << " != " << (ToDefault ? "(default) " : "");
+ Bold();
+ OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)");
+ Unbold();
+ OS << ']';
+ }
+ }
+
// Prints the appropriate placeholder for elided template arguments.
void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) {
if (PrintTree) {
@@ -1191,6 +1322,68 @@ class TemplateDiff {
OS << "[" << NumElideArgs << " * ...]";
}
+ // Prints and highlights differences in Qualifiers.
+ void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) {
+ // Both types have no qualifiers
+ if (FromQual.empty() && ToQual.empty())
+ return;
+
+ // Both types have same qualifiers
+ if (FromQual == ToQual) {
+ PrintQualifier(FromQual, /*ApplyBold*/false);
+ return;
+ }
+
+ // Find common qualifiers and strip them from FromQual and ToQual.
+ Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(FromQual,
+ ToQual);
+
+ // The qualifiers are printed before the template name.
+ // Inline printing:
+ // The common qualifiers are printed. Then, qualifiers only in this type
+ // are printed and highlighted. Finally, qualifiers only in the other
+ // type are printed and highlighted inside parentheses after "missing".
+ // Tree printing:
+ // Qualifiers are printed next to each other, inside brackets, and
+ // separated by "!=". The printing order is:
+ // common qualifiers, highlighted from qualifiers, "!=",
+ // common qualifiers, highlighted to qualifiers
+ if (PrintTree) {
+ OS << "[";
+ if (CommonQual.empty() && FromQual.empty()) {
+ Bold();
+ OS << "(no qualifiers) ";
+ Unbold();
+ } else {
+ PrintQualifier(CommonQual, /*ApplyBold*/false);
+ PrintQualifier(FromQual, /*ApplyBold*/true);
+ }
+ OS << "!= ";
+ if (CommonQual.empty() && ToQual.empty()) {
+ Bold();
+ OS << "(no qualifiers)";
+ Unbold();
+ } else {
+ PrintQualifier(CommonQual, /*ApplyBold*/false,
+ /*appendSpaceIfNonEmpty*/!ToQual.empty());
+ PrintQualifier(ToQual, /*ApplyBold*/true,
+ /*appendSpaceIfNonEmpty*/false);
+ }
+ OS << "] ";
+ } else {
+ PrintQualifier(CommonQual, /*ApplyBold*/false);
+ PrintQualifier(FromQual, /*ApplyBold*/true);
+ }
+ }
+
+ void PrintQualifier(Qualifiers Q, bool ApplyBold,
+ bool AppendSpaceIfNonEmpty = true) {
+ if (Q.empty()) return;
+ if (ApplyBold) Bold();
+ Q.print(OS, Policy, AppendSpaceIfNonEmpty);
+ if (ApplyBold) Unbold();
+ }
+
public:
TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,
@@ -1210,6 +1403,9 @@ public:
/// DiffTemplate - Start the template type diffing.
void DiffTemplate() {
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
+
const TemplateSpecializationType *FromOrigTST =
GetTemplateSpecializationType(Context, FromType);
const TemplateSpecializationType *ToOrigTST =
@@ -1224,7 +1420,10 @@ public:
return;
}
+ FromQual -= QualType(FromOrigTST, 0).getQualifiers();
+ ToQual -= QualType(ToOrigTST, 0).getQualifiers();
Tree.SetNode(FromType, ToType);
+ Tree.SetNode(FromQual, ToQual);
// Same base template, but different arguments.
Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 3e952acdcb42..0d4f303af2b5 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -228,16 +228,12 @@ namespace {
public:
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
- if (!Complain)
- return DiagnosticBuilder::getEmpty();
-
+ assert(Complain && "Not allowed to complain");
return C1.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
- if (!Complain)
- return DiagnosticBuilder::getEmpty();
-
+ assert(Complain && "Not allowed to complain");
return C2.getDiagnostics().Report(Loc, DiagID);
}
};
@@ -288,7 +284,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case TemplateArgument::Type:
return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
-
+
case TemplateArgument::Integral:
if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
Arg2.getIntegralType()))
@@ -297,10 +293,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral());
case TemplateArgument::Declaration:
- if (!Arg1.getAsDecl() || !Arg2.getAsDecl())
- return !Arg1.getAsDecl() && !Arg2.getAsDecl();
return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
-
+
+ case TemplateArgument::NullPtr:
+ return true; // FIXME: Is this correct?
+
case TemplateArgument::Template:
return IsStructurallyEquivalent(Context,
Arg1.getAsTemplate(),
@@ -822,33 +819,47 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
FieldDecl *Field1, FieldDecl *Field2) {
RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
-
- if (!IsStructurallyEquivalent(Context,
+
+ // For anonymous structs/unions, match up the anonymous struct/union type
+ // declarations directly, so that we don't go off searching for anonymous
+ // types
+ if (Field1->isAnonymousStructOrUnion() &&
+ Field2->isAnonymousStructOrUnion()) {
+ RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
+ return IsStructurallyEquivalent(Context, D1, D2);
+ }
+
+ if (!IsStructurallyEquivalent(Context,
Field1->getType(), Field2->getType())) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ }
return false;
}
if (Field1->isBitField() != Field2->isBitField()) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- if (Field1->isBitField()) {
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Field1->getBitWidthValue(Context.C1);
- Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
- << Field2->getDeclName();
- } else {
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Field2->getBitWidthValue(Context.C2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
- << Field1->getDeclName();
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ if (Field1->isBitField()) {
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Field1->getBitWidthValue(Context.C1);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Field2->getBitWidthValue(Context.C2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
}
return false;
}
@@ -859,12 +870,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
unsigned Bits2 = Field2->getBitWidthValue(Context.C2);
if (Bits1 != Bits2) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType() << Bits2;
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType() << Bits1;
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType() << Bits2;
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType() << Bits1;
+ }
return false;
}
}
@@ -872,17 +885,65 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+/// \brief Find the index of the given anonymous struct/union within its
+/// context.
+///
+/// \returns Returns the index of this anonymous struct/union in its 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) {
+ ASTContext &Context = Anon->getASTContext();
+ QualType AnonTy = Context.getRecordType(Anon);
+
+ RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
+ if (!Owner)
+ return llvm::Optional<unsigned>();
+
+ unsigned Index = 0;
+ for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
+ DEnd = Owner->noload_decls_end();
+ D != DEnd; ++D) {
+ FieldDecl *F = dyn_cast<FieldDecl>(*D);
+ if (!F || !F->isAnonymousStructOrUnion())
+ continue;
+
+ if (Context.hasSameType(F->getType(), AnonTy))
+ break;
+
+ ++Index;
+ }
+
+ return Index;
+}
+
/// \brief Determine structural equivalence of two records.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
RecordDecl *D1, RecordDecl *D2) {
if (D1->isUnion() != D2->isUnion()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
- << D1->getDeclName() << (unsigned)D1->getTagKind();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
+ << D1->getDeclName() << (unsigned)D1->getTagKind();
+ }
return false;
}
-
+
+ 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 (*Index1 != *Index2)
+ return false;
+ }
+ }
+ }
+
// If both declarations are class template specializations, we know
// the ODR applies, so check the template and template arguments.
ClassTemplateSpecializationDecl *Spec1
@@ -920,12 +981,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
- << D2CXX->getNumBases();
- Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
- << D1CXX->getNumBases();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+ << D2CXX->getNumBases();
+ Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+ << D1CXX->getNumBases();
+ }
return false;
}
@@ -937,38 +1000,44 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
++Base1, ++Base2) {
if (!IsStructurallyEquivalent(Context,
Base1->getType(), Base2->getType())) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
- << Base2->getType()
- << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
+ << Base2->getType()
+ << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ }
return false;
}
// Check virtual vs. non-virtual inheritance mismatch.
if (Base1->isVirtual() != Base2->isVirtual()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(),
- diag::note_odr_virtual_base)
- << Base2->isVirtual() << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->isVirtual()
- << Base1->getSourceRange();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(),
+ diag::note_odr_virtual_base)
+ << Base2->isVirtual() << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->isVirtual()
+ << Base1->getSourceRange();
+ }
return false;
}
}
} else if (D1CXX->getNumBases() > 0) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ }
return false;
}
}
@@ -981,11 +1050,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Field1 != Field1End;
++Field1, ++Field2) {
if (Field2 == Field2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ }
return false;
}
@@ -994,11 +1065,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
if (Field2 != Field2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ }
return false;
}
@@ -1014,12 +1087,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
EC1End = D1->enumerator_end();
EC1 != EC1End; ++EC1, ++EC2) {
if (EC2 == EC2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ }
return false;
}
@@ -1027,25 +1102,29 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
llvm::APSInt Val2 = EC2->getInitVal();
if (!llvm::APSInt::isSameValue(Val1, Val2) ||
!IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName()
+ << EC2->getInitVal().toString(10);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ }
+ return false;
+ }
+ }
+
+ if (EC2 != EC2End) {
+ if (Context.Complain) {
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
<< Context.C2.getTypeDeclType(D2);
Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
<< EC2->getDeclName()
<< EC2->getInitVal().toString(10);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- return false;
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
}
- }
-
- if (EC2 != EC2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName()
- << EC2->getInitVal().toString(10);
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
return false;
}
@@ -1056,20 +1135,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateParameterList *Params1,
TemplateParameterList *Params2) {
if (Params1->size() != Params2->size()) {
- Context.Diag2(Params2->getTemplateLoc(),
- diag::err_odr_different_num_template_parameters)
- << Params1->size() << Params2->size();
- Context.Diag1(Params1->getTemplateLoc(),
- diag::note_odr_template_parameter_list);
+ if (Context.Complain) {
+ Context.Diag2(Params2->getTemplateLoc(),
+ diag::err_odr_different_num_template_parameters)
+ << Params1->size() << Params2->size();
+ Context.Diag1(Params1->getTemplateLoc(),
+ diag::note_odr_template_parameter_list);
+ }
return false;
}
for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
- Context.Diag2(Params2->getParam(I)->getLocation(),
- diag::err_odr_different_template_parameter_kind);
- Context.Diag1(Params1->getParam(I)->getLocation(),
- diag::note_odr_template_parameter_here);
+ if (Context.Complain) {
+ Context.Diag2(Params2->getParam(I)->getLocation(),
+ diag::err_odr_different_template_parameter_kind);
+ Context.Diag1(Params1->getParam(I)->getLocation(),
+ diag::note_odr_template_parameter_here);
+ }
return false;
}
@@ -1087,10 +1170,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateTypeParmDecl *D1,
TemplateTypeParmDecl *D2) {
if (D1->isParameterPack() != D2->isParameterPack()) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
return false;
}
@@ -1100,24 +1185,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NonTypeTemplateParmDecl *D1,
NonTypeTemplateParmDecl *D2) {
- // FIXME: Enable once we have variadic templates.
-#if 0
if (D1->isParameterPack() != D2->isParameterPack()) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
return false;
}
-#endif
// Check types.
if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
- Context.Diag2(D2->getLocation(),
- diag::err_odr_non_type_parameter_type_inconsistent)
- << D2->getType() << D1->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
- << D1->getType();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::err_odr_non_type_parameter_type_inconsistent)
+ << D2->getType() << D1->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
+ << D1->getType();
+ }
return false;
}
@@ -1127,17 +1213,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateTemplateParmDecl *D1,
TemplateTemplateParmDecl *D2) {
- // FIXME: Enable once we have variadic templates.
-#if 0
if (D1->isParameterPack() != D2->isParameterPack()) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
return false;
}
-#endif
-
+
// Check template parameter lists.
return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
D2->getTemplateParameters());
@@ -1509,11 +1594,26 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ExceptionTypes.push_back(ExceptionType);
}
- FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo();
- EPI.Exceptions = ExceptionTypes.data();
-
+ FunctionProtoType::ExtProtoInfo FromEPI = T->getExtProtoInfo();
+ FunctionProtoType::ExtProtoInfo ToEPI;
+
+ ToEPI.ExtInfo = FromEPI.ExtInfo;
+ ToEPI.Variadic = FromEPI.Variadic;
+ ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn;
+ ToEPI.TypeQuals = FromEPI.TypeQuals;
+ ToEPI.RefQualifier = FromEPI.RefQualifier;
+ ToEPI.NumExceptions = ExceptionTypes.size();
+ ToEPI.Exceptions = ExceptionTypes.data();
+ ToEPI.ConsumedArguments = FromEPI.ConsumedArguments;
+ ToEPI.ExceptionSpecType = FromEPI.ExceptionSpecType;
+ ToEPI.NoexceptExpr = Importer.Import(FromEPI.NoexceptExpr);
+ ToEPI.ExceptionSpecDecl = cast_or_null<FunctionDecl>(
+ Importer.Import(FromEPI.ExceptionSpecDecl));
+ ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
+ Importer.Import(FromEPI.ExceptionSpecTemplate));
+
return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(), EPI);
+ ArgTypes.size(), ToEPI);
}
QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -1961,11 +2061,20 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
return TemplateArgument(From, ToType);
}
- case TemplateArgument::Declaration:
- if (Decl *To = Importer.Import(From.getAsDecl()))
- return TemplateArgument(To);
+ case TemplateArgument::Declaration: {
+ ValueDecl *FromD = From.getAsDecl();
+ if (ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(FromD)))
+ return TemplateArgument(To, From.isDeclForReferenceParam());
return TemplateArgument();
-
+ }
+
+ case TemplateArgument::NullPtr: {
+ QualType ToType = Importer.Import(From.getNullPtrType());
+ if (ToType.isNull())
+ return TemplateArgument();
+ return TemplateArgument(ToType, /*isNullPtr*/true);
+ }
+
case TemplateArgument::Template: {
TemplateName ToTemplate = Importer.Import(From.getAsTemplate());
if (ToTemplate.isNull())
@@ -2318,6 +2427,20 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
+ if (D->isAnonymousStructOrUnion() &&
+ 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
+ = findAnonymousStructOrUnionIndex(D)) {
+ if (llvm::Optional<unsigned> Index2
+ = findAnonymousStructOrUnionIndex(FoundRecord)) {
+ if (*Index1 != *Index2)
+ continue;
+ }
+ }
+ }
+
if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
if ((SearchName && !D->isCompleteDefinition())
|| (D->isCompleteDefinition() &&
@@ -2491,8 +2614,30 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import additional name location/type info.
ImportDeclarationNameLoc(D->getNameInfo(), NameInfo);
+ QualType FromTy = D->getType();
+ bool usedDifferentExceptionSpec = false;
+
+ if (const FunctionProtoType *
+ FromFPT = D->getType()->getAs<FunctionProtoType>()) {
+ FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
+ // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the
+ // FunctionDecl that we are importing the FunctionProtoType for.
+ // To avoid an infinite recursion when importing, create the FunctionDecl
+ // with a simplified function type and update it afterwards.
+ if (FromEPI.ExceptionSpecDecl || FromEPI.ExceptionSpecTemplate ||
+ FromEPI.NoexceptExpr) {
+ FunctionProtoType::ExtProtoInfo DefaultEPI;
+ FromTy = Importer.getFromContext().getFunctionType(
+ FromFPT->getResultType(),
+ FromFPT->arg_type_begin(),
+ FromFPT->arg_type_end() - FromFPT->arg_type_begin(),
+ DefaultEPI);
+ usedDifferentExceptionSpec = true;
+ }
+ }
+
// Import the type.
- QualType T = Importer.Import(D->getType());
+ QualType T = Importer.Import(FromTy);
if (T.isNull())
return 0;
@@ -2572,6 +2717,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
ToFunction->setParams(Parameters);
+ if (usedDifferentExceptionSpec) {
+ // Update FunctionProtoType::ExtProtoInfo.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+ ToFunction->setType(T);
+ }
+
// FIXME: Other bits to merge?
// Add this function to the lexical context.
@@ -2596,6 +2749,25 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) {
return VisitCXXMethodDecl(D);
}
+static unsigned getFieldIndex(Decl *F) {
+ RecordDecl *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
+ if (!Owner)
+ return 0;
+
+ unsigned Index = 1;
+ for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
+ DEnd = Owner->noload_decls_end();
+ D != DEnd; ++D) {
+ if (*D == F)
+ return Index;
+
+ if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D))
+ ++Index;
+ }
+
+ return Index;
+}
+
Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
// Import the major distinguishing characteristics of a variable.
DeclContext *DC, *LexicalDC;
@@ -2609,6 +2781,10 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
+ // For anonymous fields, match up by index.
+ if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+ continue;
+
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType())) {
Importer.Imported(D, FoundField);
@@ -2642,6 +2818,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
ToField->setLexicalDeclContext(LexicalDC);
if (ToField->hasInClassInitializer())
ToField->setInClassInitializer(D->getInClassInitializer());
+ ToField->setImplicit(D->isImplicit());
Importer.Imported(D, ToField);
LexicalDC->addDeclInternal(ToField);
return ToField;
@@ -2661,6 +2838,10 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (IndirectFieldDecl *FoundField
= dyn_cast<IndirectFieldDecl>(FoundDecls[I])) {
+ // For anonymous indirect fields, match up by index.
+ if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+ continue;
+
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
Name)) {
@@ -3025,7 +3206,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ResultTy, ResultTInfo, DC,
D->isInstanceMethod(),
D->isVariadic(),
- D->isSynthesized(),
+ D->isPropertyAccessor(),
D->isImplicit(),
D->isDefined(),
D->getImplementationControl(),
@@ -4027,7 +4208,8 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(),
T, E->getValueKind(),
E->getObjectKind(),
- Importer.Import(E->getOperatorLoc()));
+ Importer.Import(E->getOperatorLoc()),
+ E->isFPContractable());
}
Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -4056,7 +4238,8 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
T, E->getValueKind(),
E->getObjectKind(),
CompLHSType, CompResultType,
- Importer.Import(E->getOperatorLoc()));
+ Importer.Import(E->getOperatorLoc()),
+ E->isFPContractable());
}
static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
@@ -4479,7 +4662,8 @@ FileID ASTImporter::Import(FileID FromID) {
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
- ToID = ToSM.createFileIDForMemBuffer(ToBuf);
+ ToID = ToSM.createFileIDForMemBuffer(ToBuf,
+ FromSLoc.getFile().getFileCharacteristic());
}
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index bcc96f912e28..d20d77ef7ea5 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -64,7 +64,10 @@ add_dependencies(clangAST
ClangAttrClasses
ClangAttrList
ClangAttrImpl
+ ClangCommentCommandInfo
ClangCommentNodes
+ ClangCommentHTMLTags
+ ClangCommentHTMLTagsProperties
ClangDeclNodes
ClangDiagnosticAST
ClangDiagnosticComment
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index cf3913bac008..213b214a4e4c 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/SetVector.h"
#include <algorithm>
#include <set>
@@ -25,13 +26,9 @@ void CXXBasePaths::ComputeDeclsFound() {
assert(NumDeclsFound == 0 && !DeclsFound &&
"Already computed the set of declarations");
- SmallVector<NamedDecl *, 8> Decls;
+ llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls;
for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
- Decls.push_back(*Path->Decls.first);
-
- // Eliminate duplicated decls.
- llvm::array_pod_sort(Decls.begin(), Decls.end());
- Decls.erase(std::unique(Decls.begin(), Decls.end()), Decls.end());
+ Decls.insert(*Path->Decls.first);
NumDeclsFound = Decls.size();
DeclsFound = new NamedDecl * [NumDeclsFound];
@@ -258,7 +255,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
}
} else if (VisitBase) {
CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>()
+ = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>()
->getDecl());
if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) {
// C++ [class.member.lookup]p2:
@@ -365,8 +362,8 @@ bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
void *BaseRecord) {
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
"User data for FindBaseClass is not canonical!");
- return Specifier->getType()->getAs<RecordType>()->getDecl()
- ->getCanonicalDecl() == BaseRecord;
+ return Specifier->getType()->castAs<RecordType>()->getDecl()
+ ->getCanonicalDecl() == BaseRecord;
}
bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
@@ -375,14 +372,15 @@ bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
"User data for FindBaseClass is not canonical!");
return Specifier->isVirtual() &&
- Specifier->getType()->getAs<RecordType>()->getDecl()
- ->getCanonicalDecl() == BaseRecord;
+ Specifier->getType()->castAs<RecordType>()->getDecl()
+ ->getCanonicalDecl() == BaseRecord;
}
bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
@@ -398,7 +396,8 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
@@ -416,7 +415,8 @@ bool CXXRecordDecl::
FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
@@ -694,7 +694,7 @@ AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
"Cannot get indirect primary bases for class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
@@ -717,7 +717,7 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
"Cannot get indirect primary bases for class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 8a711f0c1f80..361f8ac61c2a 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -37,11 +38,12 @@ void Comment::dump() const {
// 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);
+ dump(llvm::errs(), NULL, NULL);
}
-void Comment::dump(SourceManager &SM) const {
- dump(llvm::errs(), &SM);
+void Comment::dump(const ASTContext &Context) const {
+ dump(llvm::errs(), &Context.getCommentCommandTraits(),
+ &Context.getSourceManager());
}
namespace {
@@ -149,13 +151,14 @@ void DeclInfo::fill() {
ParamVars = ArrayRef<const ParmVarDecl *>();
TemplateParameters = NULL;
- if (!ThisDecl) {
+ if (!CommentDecl) {
// If there is no declaration, the defaults is our only guess.
IsFilled = true;
return;
}
-
- Decl::Kind K = ThisDecl->getKind();
+ CurrentDecl = CommentDecl;
+
+ Decl::Kind K = CommentDecl->getKind();
switch (K) {
default:
// Defaults are should be good for declarations we don't handle explicitly.
@@ -165,7 +168,7 @@ void DeclInfo::fill() {
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion: {
- const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl);
+ const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
Kind = FunctionKind;
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
FD->getNumParams());
@@ -179,14 +182,14 @@ void DeclInfo::fill() {
if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
K == Decl::CXXDestructor || K == Decl::CXXConversion) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl);
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
IsInstanceMethod = MD->isInstance();
IsClassMethod = !IsInstanceMethod;
}
break;
}
case Decl::ObjCMethod: {
- const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl);
+ const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
Kind = FunctionKind;
ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
MD->param_size());
@@ -197,7 +200,7 @@ void DeclInfo::fill() {
break;
}
case Decl::FunctionTemplate: {
- const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl);
+ const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
Kind = FunctionKind;
TemplateKind = Template;
const FunctionDecl *FD = FTD->getTemplatedDecl();
@@ -208,7 +211,7 @@ void DeclInfo::fill() {
break;
}
case Decl::ClassTemplate: {
- const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl);
+ const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
Kind = ClassKind;
TemplateKind = Template;
TemplateParameters = CTD->getTemplateParameters();
@@ -216,7 +219,7 @@ void DeclInfo::fill() {
}
case Decl::ClassTemplatePartialSpecialization: {
const ClassTemplatePartialSpecializationDecl *CTPSD =
- cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
+ cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
Kind = ClassKind;
TemplateKind = TemplatePartialSpecialization;
TemplateParameters = CTPSD->getTemplateParameters();
@@ -240,12 +243,55 @@ void DeclInfo::fill() {
case Decl::Namespace:
Kind = NamespaceKind;
break;
- case Decl::Typedef:
+ case Decl::Typedef: {
+ Kind = TypedefKind;
+ // If this is a typedef to something we consider a function, extract
+ // arguments and return type.
+ const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
+ const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
+ if (!TSI)
+ break;
+ TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
+ while (true) {
+ TL = TL.IgnoreParens();
+ // Look through qualified types.
+ if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
+ TL = QualifiedTL->getUnqualifiedLoc();
+ continue;
+ }
+ // Look through pointer types.
+ if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
+ TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ if (BlockPointerTypeLoc *BlockPointerTL =
+ dyn_cast<BlockPointerTypeLoc>(&TL)) {
+ TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ if (MemberPointerTypeLoc *MemberPointerTL =
+ dyn_cast<MemberPointerTypeLoc>(&TL)) {
+ TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ // Is this a typedef for a function type?
+ if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ Kind = FunctionKind;
+ ArrayRef<ParmVarDecl *> Params = FTL->getParams();
+ ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
+ Params.size());
+ ResultType = FTL->getResultLoc().getType();
+ break;
+ }
+ break;
+ }
+ break;
+ }
case Decl::TypeAlias:
Kind = TypedefKind;
break;
case Decl::TypeAliasTemplate: {
- const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
+ const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
Kind = TypedefKind;
TemplateKind = Template;
TemplateParameters = TAT->getTemplateParameters();
@@ -259,6 +305,25 @@ void DeclInfo::fill() {
IsFilled = true;
}
+StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
+ assert(isParamIndexValid());
+ return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
+}
+
+StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
+ assert(isPositionValid());
+ const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
+ for (unsigned i = 0, e = getDepth(); i != e; ++i) {
+ if (i == e-1)
+ return TPL->getParam(getIndex(i))->getName();
+ const NamedDecl *Param = TPL->getParam(getIndex(i));
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Param))
+ TPL = TTP->getTemplateParameters();
+ }
+ return "";
+}
+
} // end namespace comments
} // end namespace clang
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 0aebc1e4e3dd..95daa7e3f809 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -15,6 +15,11 @@ namespace clang {
namespace comments {
namespace {
+inline bool isWhitespace(char C) {
+ return C == ' ' || C == '\n' || C == '\r' ||
+ C == '\t' || C == '\f' || C == '\v';
+}
+
/// Convert all whitespace into spaces, remove leading and trailing spaces,
/// compress multiple spaces into one.
void cleanupBrief(std::string &S) {
@@ -23,8 +28,7 @@ void cleanupBrief(std::string &S) {
for (std::string::iterator I = S.begin(), E = S.end();
I != E; ++I) {
const char C = *I;
- if (C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\v' || C == '\f') {
+ if (isWhitespace(C)) {
if (!PrevWasSpace) {
*O++ = ' ';
PrevWasSpace = true;
@@ -40,6 +44,15 @@ void cleanupBrief(std::string &S) {
S.resize(O - S.begin());
}
+
+bool isWhitespace(StringRef Text) {
+ for (StringRef::const_iterator I = Text.begin(), E = Text.end();
+ I != E; ++I) {
+ if (!isWhitespace(*I))
+ return false;
+ }
+ return true;
+}
} // unnamed namespace
BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
@@ -66,19 +79,23 @@ std::string BriefParser::Parse() {
}
if (Tok.is(tok::command)) {
- StringRef Name = Tok.getCommandName();
- if (Traits.isBriefCommand(Name)) {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ if (Info->IsBriefCommand) {
FirstParagraphOrBrief.clear();
InBrief = true;
ConsumeToken();
continue;
}
- if (Traits.isReturnsCommand(Name)) {
+ if (Info->IsReturnsCommand) {
InReturns = true;
+ InBrief = false;
+ InFirstParagraph = false;
ReturnsParagraph += "Returns ";
+ ConsumeToken();
+ continue;
}
// Block commands implicitly start a new paragraph.
- if (Traits.isBlockCommand(Name)) {
+ if (Info->IsBlockCommand) {
// We found an implicit paragraph end.
InFirstParagraph = false;
if (InBrief)
@@ -93,13 +110,29 @@ std::string BriefParser::Parse() {
ReturnsParagraph += ' ';
ConsumeToken();
+ // If the next token is a whitespace only text, ignore it. Thus we allow
+ // two paragraphs to be separated by line that has only whitespace in it.
+ //
+ // We don't need to add a space to the parsed text because we just added
+ // a space for the newline.
+ if (Tok.is(tok::text)) {
+ if (isWhitespace(Tok.getText()))
+ ConsumeToken();
+ }
+
if (Tok.is(tok::newline)) {
ConsumeToken();
- // We found a paragraph end.
- InFirstParagraph = false;
- InReturns = false;
+ // We found a paragraph end. This ends the brief description if
+ // \\brief command or its equivalent was explicitly used.
+ // Stop scanning text because an explicit \\brief paragraph is the
+ // preffered one.
if (InBrief)
break;
+ // End first paragraph if we found some non-whitespace text.
+ if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
+ InFirstParagraph = false;
+ // End the \\returns paragraph because we found the paragraph end.
+ InReturns = false;
}
continue;
}
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index dc7a0bd17532..e7e40fd1090f 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -8,125 +8,64 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentCommandTraits.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
namespace clang {
namespace comments {
-// TODO: tablegen
+#include "clang/AST/CommentCommandInfo.inc"
-bool CommandTraits::isVerbatimBlockCommand(StringRef StartName,
- StringRef &EndName) const {
- const char *Result = llvm::StringSwitch<const char *>(StartName)
- .Case("code", "endcode")
- .Case("verbatim", "endverbatim")
- .Case("htmlonly", "endhtmlonly")
- .Case("latexonly", "endlatexonly")
- .Case("xmlonly", "endxmlonly")
- .Case("manonly", "endmanonly")
- .Case("rtfonly", "endrtfonly")
+CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) :
+ NextID(llvm::array_lengthof(Commands)), Allocator(Allocator)
+{ }
- .Case("dot", "enddot")
- .Case("msc", "endmsc")
-
- .Case("f$", "f$") // Inline LaTeX formula
- .Case("f[", "f]") // Displayed LaTeX formula
- .Case("f{", "f}") // LaTeX environment
-
- .Default(NULL);
-
- if (Result) {
- EndName = Result;
- return true;
- }
-
- for (VerbatimBlockCommandVector::const_iterator
- I = VerbatimBlockCommands.begin(),
- E = VerbatimBlockCommands.end();
- I != E; ++I)
- if (I->StartName == StartName) {
- EndName = I->EndName;
- return true;
- }
-
- return false;
+const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
+ if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
+ return Info;
+ return getRegisteredCommandInfo(Name);
}
-bool CommandTraits::isVerbatimLineCommand(StringRef Name) const {
- bool Result = isDeclarationCommand(Name) || llvm::StringSwitch<bool>(Name)
- .Case("defgroup", true)
- .Case("ingroup", true)
- .Case("addtogroup", true)
- .Case("weakgroup", true)
- .Case("name", true)
-
- .Case("section", true)
- .Case("subsection", true)
- .Case("subsubsection", true)
- .Case("paragraph", true)
-
- .Case("mainpage", true)
- .Case("subpage", true)
- .Case("ref", true)
+const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
+ if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID))
+ return Info;
+ return getRegisteredCommandInfo(CommandID);
+}
- .Default(false);
+const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) {
+ char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
+ memcpy(Name, CommandName.data(), CommandName.size());
+ Name[CommandName.size()] = '\0';
- if (Result)
- return true;
+ // Value-initialize (=zero-initialize in this case) a new CommandInfo.
+ CommandInfo *Info = new (Allocator) CommandInfo();
+ Info->Name = Name;
+ Info->ID = NextID++;
+ Info->IsUnknownCommand = true;
- for (VerbatimLineCommandVector::const_iterator
- I = VerbatimLineCommands.begin(),
- E = VerbatimLineCommands.end();
- I != E; ++I)
- if (I->Name == Name)
- return true;
+ RegisteredCommands.push_back(Info);
- return false;
+ return Info;
}
-bool CommandTraits::isDeclarationCommand(StringRef Name) const {
- return llvm::StringSwitch<bool>(Name)
- // Doxygen commands.
- .Case("fn", true)
- .Case("var", true)
- .Case("property", true)
- .Case("typedef", true)
-
- .Case("overload", true)
-
- // HeaderDoc commands.
- .Case("class", true)
- .Case("interface", true)
- .Case("protocol", true)
- .Case("category", true)
- .Case("template", true)
- .Case("function", true)
- .Case("method", true)
- .Case("callback", true)
- .Case("var", true)
- .Case("const", true)
- .Case("constant", true)
- .Case("property", true)
- .Case("struct", true)
- .Case("union", true)
- .Case("typedef", true)
- .Case("enum", true)
-
- .Default(false);
+const CommandInfo *CommandTraits::getBuiltinCommandInfo(
+ unsigned CommandID) {
+ if (CommandID < llvm::array_lengthof(Commands))
+ return &Commands[CommandID];
+ return NULL;
}
-void CommandTraits::addVerbatimBlockCommand(StringRef StartName,
- StringRef EndName) {
- VerbatimBlockCommand VBC;
- VBC.StartName = StartName;
- VBC.EndName = EndName;
- VerbatimBlockCommands.push_back(VBC);
+const CommandInfo *CommandTraits::getRegisteredCommandInfo(
+ StringRef Name) const {
+ for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) {
+ if (RegisteredCommands[i]->Name == Name)
+ return RegisteredCommands[i];
+ }
+ return NULL;
}
-void CommandTraits::addVerbatimLineCommand(StringRef Name) {
- VerbatimLineCommand VLC;
- VLC.Name = Name;
- VerbatimLineCommands.push_back(VLC);
+const CommandInfo *CommandTraits::getRegisteredCommandInfo(
+ unsigned CommandID) const {
+ return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
}
} // end namespace comments
diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp
index dffc8233a0ca..19d24b2f3a03 100644
--- a/lib/AST/CommentDumper.cpp
+++ b/lib/AST/CommentDumper.cpp
@@ -16,12 +16,20 @@ namespace comments {
namespace {
class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
raw_ostream &OS;
- SourceManager *SM;
+ 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, SourceManager *SM) :
- OS(OS), SM(SM), IndentLevel(0)
+ 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 {
@@ -56,6 +64,15 @@ public:
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) {
@@ -107,7 +124,7 @@ void CommentDumper::visitTextComment(const TextComment *C) {
void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
dumpComment(C);
- OS << " Name=\"" << C->getCommandName() << "\"";
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
switch (C->getRenderKind()) {
case InlineCommandComment::RenderNormal:
OS << " RenderNormal";
@@ -155,7 +172,7 @@ void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
dumpComment(C);
- OS << " Name=\"" << C->getCommandName() << "\"";
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}
@@ -170,8 +187,12 @@ void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
else
OS << " implicitly";
- if (C->hasParamName())
- OS << " Param=\"" << C->getParamName() << "\"";
+ if (C->hasParamName()) {
+ if (C->isParamIndexValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
if (C->isParamIndexValid())
OS << " ParamIndex=" << C->getParamIndex();
@@ -181,7 +202,10 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
dumpComment(C);
if (C->hasParamName()) {
- OS << " Param=\"" << C->getParamName() << "\"";
+ if (C->isPositionValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
}
if (C->isPositionValid()) {
@@ -198,7 +222,7 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
dumpComment(C);
- OS << " Name=\"" << C->getCommandName() << "\""
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
" CloseName=\"" << C->getCloseName() << "\"";
}
@@ -220,8 +244,10 @@ void CommentDumper::visitFullComment(const FullComment *C) {
} // unnamed namespace
-void Comment::dump(llvm::raw_ostream &OS, SourceManager *SM) const {
- CommentDumper D(llvm::errs(), SM);
+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';
}
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index b6516ec126f6..31a09f71d993 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -28,6 +28,9 @@ bool isHTMLHexCharacterReferenceCharacter(char C) {
(C >= 'a' && C <= 'f') ||
(C >= 'A' && C <= 'F');
}
+
+#include "clang/AST/CommentHTMLTags.inc"
+
} // unnamed namespace
StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const {
@@ -223,6 +226,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) {
return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd;
}
+bool isCommandNameStartCharacter(char C) {
+ return (C >= 'a' && C <= 'z') ||
+ (C >= 'A' && C <= 'Z');
+}
+
bool isCommandNameCharacter(char C) {
return (C >= 'a' && C <= 'z') ||
(C >= 'A' && C <= 'Z') ||
@@ -337,7 +345,7 @@ void Lexer::lexCommentText(Token &T) {
}
// Don't make zero-length commands.
- if (!isCommandNameCharacter(*TokenPtr)) {
+ if (!isCommandNameStartCharacter(*TokenPtr)) {
formTextToken(T, TokenPtr);
return;
}
@@ -356,18 +364,23 @@ void Lexer::lexCommentText(Token &T) {
}
const StringRef CommandName(BufferPtr + 1, Length);
- StringRef EndName;
- if (Traits.isVerbatimBlockCommand(CommandName, EndName)) {
- setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName);
+ const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName);
+ if (!Info) {
+ formTokenWithChars(T, TokenPtr, tok::unknown_command);
+ T.setUnknownCommandName(CommandName);
+ return;
+ }
+ if (Info->IsVerbatimBlockCommand) {
+ setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info);
return;
}
- if (Traits.isVerbatimLineCommand(CommandName)) {
- setupAndLexVerbatimLine(T, TokenPtr);
+ if (Info->IsVerbatimLineCommand) {
+ setupAndLexVerbatimLine(T, TokenPtr, Info);
return;
}
formTokenWithChars(T, TokenPtr, tok::command);
- T.setCommandName(CommandName);
+ T.setCommandID(Info->getID());
return;
}
@@ -420,14 +433,15 @@ void Lexer::lexCommentText(Token &T) {
void Lexer::setupAndLexVerbatimBlock(Token &T,
const char *TextBegin,
- char Marker, StringRef EndName) {
+ char Marker, const CommandInfo *Info) {
+ assert(Info->IsVerbatimBlockCommand);
+
VerbatimBlockEndCommandName.clear();
VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@");
- VerbatimBlockEndCommandName.append(EndName);
+ VerbatimBlockEndCommandName.append(Info->EndCommandName);
- StringRef Name(BufferPtr + 1, TextBegin - (BufferPtr + 1));
formTokenWithChars(T, TextBegin, tok::verbatim_block_begin);
- T.setVerbatimBlockName(Name);
+ T.setVerbatimBlockID(Info->getID());
// 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
@@ -468,7 +482,7 @@ again:
const char *End = BufferPtr + VerbatimBlockEndCommandName.size();
StringRef Name(BufferPtr + 1, End - (BufferPtr + 1));
formTokenWithChars(T, End, tok::verbatim_block_end);
- T.setVerbatimBlockName(Name);
+ T.setVerbatimBlockID(Traits.getCommandInfo(Name)->getID());
State = LS_Normal;
return;
} else {
@@ -498,10 +512,11 @@ void Lexer::lexVerbatimBlockBody(Token &T) {
lexVerbatimBlockFirstLine(T);
}
-void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin) {
- const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1);
+void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin,
+ const CommandInfo *Info) {
+ assert(Info->IsVerbatimLineCommand);
formTokenWithChars(T, TextBegin, tok::verbatim_line_name);
- T.setVerbatimLineName(Name);
+ T.setVerbatimLineID(Info->getID());
State = LS_VerbatimLineText;
}
@@ -585,8 +600,12 @@ void Lexer::setupAndLexHTMLStartTag(Token &T) {
assert(BufferPtr[0] == '<' &&
isHTMLIdentifierStartingCharacter(BufferPtr[1]));
const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd);
-
StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1));
+ if (!isHTMLTagName(Name)) {
+ formTextToken(T, TagNameEnd);
+ return;
+ }
+
formTokenWithChars(T, TagNameEnd, tok::html_start_tag);
T.setHTMLTagStartName(Name);
@@ -665,11 +684,16 @@ void Lexer::setupAndLexHTMLEndTag(Token &T) {
const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd);
const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd);
+ StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin);
+ if (!isHTMLTagName(Name)) {
+ formTextToken(T, TagNameEnd);
+ return;
+ }
const char *End = skipWhitespace(TagNameEnd, CommentEnd);
formTokenWithChars(T, End, tok::html_end_tag);
- T.setHTMLTagEndName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin));
+ T.setHTMLTagEndName(Name);
if (BufferPtr != CommentEnd && *BufferPtr == '>')
State = LS_HTMLEndTag;
@@ -683,11 +707,11 @@ void Lexer::lexHTMLEndTag(Token &T) {
}
Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits,
- SourceLocation FileLoc, const CommentOptions &CommOpts,
+ SourceLocation FileLoc,
const char *BufferStart, const char *BufferEnd):
Allocator(Allocator), Traits(Traits),
BufferStart(BufferStart), BufferEnd(BufferEnd),
- FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart),
+ FileLoc(FileLoc), BufferPtr(BufferStart),
CommentState(LCS_BeforeComment), State(LS_Normal) {
}
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index 43abf6a476a8..d0a84741b6f2 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -132,8 +132,8 @@ class TextTokenRetokenizer {
Result.setKind(tok::text);
Result.setLength(TokLength);
#ifndef NDEBUG
- Result.TextPtr1 = "<UNSET>";
- Result.TextLen1 = 7;
+ Result.TextPtr = "<UNSET>";
+ Result.IntVal = 7;
#endif
Result.setText(Text);
}
@@ -312,26 +312,26 @@ BlockCommandComment *Parser::parseBlockCommand() {
BlockCommandComment *BC;
bool IsParam = false;
bool IsTParam = false;
- unsigned NumArgs = 0;
- if (Traits.isParamCommand(Tok.getCommandName())) {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ if (Info->IsParamCommand) {
IsParam = true;
PC = S.actOnParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandName());
- } if (Traits.isTParamCommand(Tok.getCommandName())) {
+ Tok.getCommandID());
+ } if (Info->IsTParamCommand) {
IsTParam = true;
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandName());
+ Tok.getCommandID());
} else {
- NumArgs = Traits.getBlockCommandNumArgs(Tok.getCommandName());
BC = S.actOnBlockCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandName());
+ Tok.getCommandID());
}
consumeToken();
- if (Tok.is(tok::command) && Traits.isBlockCommand(Tok.getCommandName())) {
+ if (Tok.is(tok::command) &&
+ Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
ParagraphComment *Paragraph = S.actOnParagraphComment(
@@ -348,7 +348,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
}
}
- if (IsParam || IsTParam || NumArgs > 0) {
+ if (IsParam || IsTParam || Info->NumArgs > 0) {
// In order to parse command arguments we need to retokenize a few
// following text tokens.
TextTokenRetokenizer Retokenizer(Allocator, *this);
@@ -358,7 +358,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
else if (IsTParam)
parseTParamCommandArgs(TPC, Retokenizer);
else
- parseBlockCommandArgs(BC, Retokenizer, NumArgs);
+ parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs);
Retokenizer.putBackLeftoverTokens();
}
@@ -394,14 +394,14 @@ InlineCommandComment *Parser::parseInlineCommand() {
if (ArgTokValid) {
IC = S.actOnInlineCommand(CommandTok.getLocation(),
CommandTok.getEndLocation(),
- CommandTok.getCommandName(),
+ CommandTok.getCommandID(),
ArgTok.getLocation(),
ArgTok.getEndLocation(),
ArgTok.getText());
} else {
IC = S.actOnInlineCommand(CommandTok.getLocation(),
CommandTok.getEndLocation(),
- CommandTok.getCommandName());
+ CommandTok.getCommandID());
}
Retokenizer.putBackLeftoverTokens();
@@ -540,23 +540,39 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
assert(Content.size() != 0);
break; // Block content or EOF ahead, finish this parapgaph.
- case tok::command:
- if (Traits.isBlockCommand(Tok.getCommandName())) {
+ case tok::unknown_command:
+ Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
+ Tok.getEndLocation(),
+ Tok.getUnknownCommandName()));
+ consumeToken();
+ continue;
+
+ case tok::command: {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ if (Info->IsBlockCommand) {
if (Content.size() == 0)
return parseBlockCommand();
break; // Block command ahead, finish this parapgaph.
}
- if (Traits.isInlineCommand(Tok.getCommandName())) {
- Content.push_back(parseInlineCommand());
+ if (Info->IsVerbatimBlockEndCommand) {
+ Diag(Tok.getLocation(),
+ diag::warn_verbatim_block_end_without_start)
+ << Info->Name
+ << SourceRange(Tok.getLocation(), Tok.getEndLocation());
+ consumeToken();
continue;
}
-
- // Not a block command, not an inline command ==> an unknown command.
- Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
- Tok.getEndLocation(),
- Tok.getCommandName()));
- consumeToken();
+ if (Info->IsUnknownCommand) {
+ Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
+ Tok.getEndLocation(),
+ Info->getID()));
+ consumeToken();
+ continue;
+ }
+ assert(Info->IsInlineCommand);
+ Content.push_back(parseInlineCommand());
continue;
+ }
case tok::newline: {
consumeToken();
@@ -606,7 +622,7 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
VerbatimBlockComment *VB =
S.actOnVerbatimBlockStart(Tok.getLocation(),
- Tok.getVerbatimBlockName());
+ Tok.getVerbatimBlockID());
consumeToken();
// Don't create an empty line if verbatim opening command is followed
@@ -634,8 +650,9 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
}
if (Tok.is(tok::verbatim_block_end)) {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());
S.actOnVerbatimBlockFinish(VB, Tok.getLocation(),
- Tok.getVerbatimBlockName(),
+ Info->Name,
S.copyArray(llvm::makeArrayRef(Lines)));
consumeToken();
} else {
@@ -666,7 +683,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() {
}
VerbatimLineComment *VL = S.actOnVerbatimLine(NameTok.getLocation(),
- NameTok.getVerbatimLineName(),
+ NameTok.getVerbatimLineID(),
TextBegin,
Text);
consumeToken();
@@ -676,6 +693,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() {
BlockContentComment *Parser::parseBlockContent() {
switch (Tok.getKind()) {
case tok::text:
+ case tok::unknown_command:
case tok::command:
case tok::html_start_tag:
case tok::html_end_tag:
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index c39ee573ef6f..08ecb3a994d7 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -13,15 +13,22 @@
#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"
namespace clang {
namespace comments {
+namespace {
+#include "clang/AST/CommentHTMLTagsProperties.inc"
+} // unnamed namespace
+
Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
- DiagnosticsEngine &Diags, const CommandTraits &Traits) :
+ DiagnosticsEngine &Diags, CommandTraits &Traits,
+ const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -29,7 +36,7 @@ void Sema::setDecl(const Decl *D) {
return;
ThisDeclInfo = new (Allocator) DeclInfo;
- ThisDeclInfo->ThisDecl = D;
+ ThisDeclInfo->CommentDecl = D;
ThisDeclInfo->IsFilled = false;
}
@@ -40,8 +47,8 @@ ParagraphComment *Sema::actOnParagraphComment(
BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
- return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name);
+ unsigned CommandID) {
+ return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
}
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
@@ -55,18 +62,19 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
checkBlockCommandDuplicate(Command);
checkReturnsCommand(Command);
+ checkDeprecatedCommand(Command);
}
ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
+ unsigned CommandID) {
ParamCommandComment *Command =
- new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
- << Command->getCommandNameRange();
+ << Command->getCommandNameRange(Traits);
return Command;
}
@@ -142,56 +150,6 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
ArgLocEnd),
Arg);
Command->setArgs(llvm::makeArrayRef(A, 1));
-
- if (!isFunctionDecl()) {
- // We already warned that this \\param is not attached to a function decl.
- return;
- }
-
- ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
-
- // Check that referenced parameter name is in the function decl.
- const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars);
- if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) {
- Command->setParamIndex(ResolvedParamIndex);
- if (ParamVarDocs[ResolvedParamIndex]) {
- SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- Diag(ArgLocBegin, diag::warn_doc_param_duplicate)
- << Arg << ArgRange;
- ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
- Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
- << PrevCommand->getParamNameRange();
- }
- ParamVarDocs[ResolvedParamIndex] = Command;
- return;
- }
-
- SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- Diag(ArgLocBegin, diag::warn_doc_param_not_found)
- << Arg << ArgRange;
-
- // No parameters -- can't suggest a correction.
- if (ParamVars.size() == 0)
- return;
-
- unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
- if (ParamVars.size() == 1) {
- // If function has only one parameter then only that parameter
- // can be documented.
- CorrectedParamIndex = 0;
- } else {
- // Do typo correction.
- CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars);
- }
- if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
- const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex];
- if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
- Diag(ArgLocBegin, diag::note_doc_param_name_suggestion)
- << CorrectedII->getName()
- << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
- }
-
- return;
}
void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
@@ -202,14 +160,14 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
+ unsigned CommandID) {
TParamCommandComment *Command =
- new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name);
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
if (!isTemplateOrSpecialization())
Diag(Command->getLocation(),
diag::warn_doc_tparam_not_attached_to_a_template_decl)
- << Command->getCommandNameRange();
+ << Command->getCommandNameRange(Traits);
return Command;
}
@@ -285,19 +243,20 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
- StringRef CommandName) {
+ unsigned CommandID) {
ArrayRef<InlineCommandComment::Argument> Args;
+ StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
return new (Allocator) InlineCommandComment(
CommandLocBegin,
CommandLocEnd,
- CommandName,
+ CommandID,
getInlineCommandRenderKind(CommandName),
Args);
}
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
- StringRef CommandName,
+ unsigned CommandID,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg) {
@@ -305,21 +264,29 @@ InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
ArgLocEnd),
Arg);
+ StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
return new (Allocator) InlineCommandComment(
CommandLocBegin,
CommandLocEnd,
- CommandName,
+ CommandID,
getInlineCommandRenderKind(CommandName),
llvm::makeArrayRef(A, 1));
}
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
+ StringRef CommandName) {
+ unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
+ return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
+}
+
+InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID) {
ArrayRef<InlineCommandComment::Argument> Args;
return new (Allocator) InlineCommandComment(
- LocBegin, LocEnd, Name,
+ LocBegin, LocEnd, CommandID,
InlineCommandComment::RenderNormal,
Args);
}
@@ -331,11 +298,12 @@ TextComment *Sema::actOnText(SourceLocation LocBegin,
}
VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
- StringRef Name) {
+ unsigned CommandID) {
+ StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
return new (Allocator) VerbatimBlockComment(
Loc,
- Loc.getLocWithOffset(1 + Name.size()),
- Name);
+ Loc.getLocWithOffset(1 + CommandName.size()),
+ CommandID);
}
VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
@@ -353,13 +321,13 @@ void Sema::actOnVerbatimBlockFinish(
}
VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
- StringRef Name,
+ unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) {
return new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
- Name,
+ CommandID,
TextBegin,
Text);
}
@@ -445,30 +413,35 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
FullComment *Sema::actOnFullComment(
ArrayRef<BlockContentComment *> Blocks) {
- return new (Allocator) FullComment(Blocks, ThisDeclInfo);
+ FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
+ resolveParamCommandIndexes(FC);
+ return FC;
}
void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
+ if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
+ return;
+
ParagraphComment *Paragraph = Command->getParagraph();
if (Paragraph->isWhitespace()) {
SourceLocation DiagLoc;
if (Command->getNumArgs() > 0)
DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
if (!DiagLoc.isValid())
- DiagLoc = Command->getCommandNameRange().getEnd();
+ DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
- << Command->getCommandName()
+ << Command->getCommandName(Traits)
<< Command->getSourceRange();
}
}
void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
- if (!Traits.isReturnsCommand(Command->getCommandName()))
+ if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
return;
if (isFunctionDecl()) {
if (ThisDeclInfo->ResultType->isVoidType()) {
unsigned DiagKind;
- switch (ThisDeclInfo->ThisDecl->getKind()) {
+ switch (ThisDeclInfo->CommentDecl->getKind()) {
default:
if (ThisDeclInfo->IsObjCMethod)
DiagKind = 3;
@@ -484,7 +457,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_attached_to_a_void_function)
- << Command->getCommandName()
+ << Command->getCommandName(Traits)
<< DiagKind
<< Command->getSourceRange();
}
@@ -492,20 +465,20 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
- << Command->getCommandName()
+ << Command->getCommandName(Traits)
<< Command->getSourceRange();
}
void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
- StringRef Name = Command->getCommandName();
+ const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
const BlockCommandComment *PrevCommand = NULL;
- if (Traits.isBriefCommand(Name)) {
+ if (Info->IsBriefCommand) {
if (!BriefCommand) {
BriefCommand = Command;
return;
}
PrevCommand = BriefCommand;
- } else if (Traits.isReturnsCommand(Name)) {
+ } else if (Info->IsReturnsCommand) {
if (!ReturnsCommand) {
ReturnsCommand = Command;
return;
@@ -515,18 +488,153 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
// We don't want to check this command for duplicates.
return;
}
+ StringRef CommandName = Command->getCommandName(Traits);
+ StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
- << Name
+ << CommandName
<< Command->getSourceRange();
- if (Name == PrevCommand->getCommandName())
+ if (CommandName == PrevCommandName)
Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
- << PrevCommand->getCommandName()
- << Command->getSourceRange();
+ << PrevCommandName
+ << PrevCommand->getSourceRange();
else
Diag(PrevCommand->getLocation(),
diag::note_doc_block_command_previous_alias)
- << PrevCommand->getCommandName()
- << Name;
+ << PrevCommandName
+ << CommandName;
+}
+
+void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
+ if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
+ return;
+
+ const Decl *D = ThisDeclInfo->CommentDecl;
+ if (!D)
+ return;
+
+ if (D->hasAttr<DeprecatedAttr>() ||
+ D->hasAttr<AvailabilityAttr>() ||
+ D->hasAttr<UnavailableAttr>())
+ return;
+
+ Diag(Command->getLocation(),
+ diag::warn_doc_deprecated_not_sync)
+ << Command->getSourceRange();
+
+ // Try to emit a fixit with a deprecation attribute.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Don't emit a Fix-It for non-member function definitions. GCC does not
+ // accept attributes on them.
+ const DeclContext *Ctx = FD->getDeclContext();
+ if ((!Ctx || !Ctx->isRecord()) &&
+ FD->doesThisDeclarationHaveABody())
+ return;
+
+ StringRef AttributeSpelling = "__attribute__((deprecated))";
+ if (PP) {
+ TokenValue Tokens[] = {
+ tok::kw___attribute, tok::l_paren, tok::l_paren,
+ PP->getIdentifierInfo("deprecated"),
+ tok::r_paren, tok::r_paren
+ };
+ StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
+ Tokens);
+ if (!MacroName.empty())
+ AttributeSpelling = MacroName;
+ }
+
+ SmallString<64> TextToInsert(" ");
+ TextToInsert += AttributeSpelling;
+ Diag(FD->getLocEnd(),
+ diag::note_add_deprecation_attr)
+ << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
+ TextToInsert);
+ }
+}
+
+void Sema::resolveParamCommandIndexes(const FullComment *FC) {
+ if (!isFunctionDecl()) {
+ // We already warned that \\param commands are not attached to a function
+ // decl.
+ return;
+ }
+
+ llvm::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;
+
+ ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
+ ParamVarDocs.resize(ParamVars.size(), NULL);
+
+ // First pass over all \\param commands: resolve all parameter names.
+ for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
+ I != E; ++I) {
+ ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
+ if (!PCC || !PCC->hasParamName())
+ continue;
+ StringRef ParamName = PCC->getParamNameAsWritten();
+
+ // Check that referenced parameter name is in the function decl.
+ const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
+ ParamVars);
+ if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
+ UnresolvedParamCommands.push_back(PCC);
+ continue;
+ }
+ PCC->setParamIndex(ResolvedParamIndex);
+ if (ParamVarDocs[ResolvedParamIndex]) {
+ SourceRange ArgRange = PCC->getParamNameRange();
+ Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
+ << ParamName << ArgRange;
+ ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
+ Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
+ << PrevCommand->getParamNameRange();
+ }
+ ParamVarDocs[ResolvedParamIndex] = PCC;
+ }
+
+ // Find parameter declarations that have no corresponding \\param.
+ llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
+ for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
+ if (!ParamVarDocs[i])
+ OrphanedParamDecls.push_back(ParamVars[i]);
+ }
+
+ // Second pass over unresolved \\param commands: do typo correction.
+ // Suggest corrections from a set of parameter declarations that have no
+ // corresponding \\param.
+ for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
+ const ParamCommandComment *PCC = UnresolvedParamCommands[i];
+
+ SourceRange ArgRange = PCC->getParamNameRange();
+ StringRef ParamName = PCC->getParamNameAsWritten();
+ Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
+ << ParamName << ArgRange;
+
+ // All parameters documented -- can't suggest a correction.
+ if (OrphanedParamDecls.size() == 0)
+ continue;
+
+ unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
+ if (OrphanedParamDecls.size() == 1) {
+ // If one parameter is not documented then that parameter is the only
+ // possible suggestion.
+ CorrectedParamIndex = 0;
+ } else {
+ // Do typo correction.
+ CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
+ OrphanedParamDecls);
+ }
+ if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
+ const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
+ if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
+ Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
+ << CorrectedII->getName()
+ << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
+ }
+ }
}
bool Sema::isFunctionDecl() {
@@ -553,7 +661,6 @@ ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
void Sema::inspectThisDecl() {
ThisDeclInfo->fill();
- ParamVarDocs.resize(ThisDeclInfo->ParamVars.size(), NULL);
}
unsigned Sema::resolveParmVarReference(StringRef Name,
@@ -629,7 +736,7 @@ unsigned Sema::correctTypoInParmVarReference(
if (Corrector.getBestDecl())
return Corrector.getBestDeclIndex();
else
- return ParamCommandComment::InvalidParamIndex;;
+ return ParamCommandComment::InvalidParamIndex;
}
namespace {
@@ -700,7 +807,7 @@ StringRef Sema::correctTypoInTParamReference(
InlineCommandComment::RenderKind
Sema::getInlineCommandRenderKind(StringRef Name) const {
- assert(Traits.isInlineCommand(Name));
+ assert(Traits.getCommandInfo(Name)->IsInlineCommand);
return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
.Case("b", InlineCommandComment::RenderBold)
@@ -709,31 +816,6 @@ Sema::getInlineCommandRenderKind(StringRef Name) const {
.Default(InlineCommandComment::RenderNormal);
}
-bool Sema::isHTMLEndTagOptional(StringRef Name) {
- return llvm::StringSwitch<bool>(Name)
- .Case("p", true)
- .Case("li", true)
- .Case("dt", true)
- .Case("dd", true)
- .Case("tr", true)
- .Case("th", true)
- .Case("td", true)
- .Case("thead", true)
- .Case("tfoot", true)
- .Case("tbody", true)
- .Case("colgroup", true)
- .Default(false);
-}
-
-bool Sema::isHTMLEndTagForbidden(StringRef Name) {
- return llvm::StringSwitch<bool>(Name)
- .Case("br", true)
- .Case("hr", true)
- .Case("img", true)
- .Case("col", true)
- .Default(false);
-}
-
} // end namespace comments
} // end namespace clang
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index d5b0be3ba4b1..7b13755979f1 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -126,12 +126,12 @@ static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args,
break;
case TemplateArgument::Declaration:
- // The decl can validly be null as the representation of nullptr
- // arguments, valid only in C++0x.
- if (Decl *D = Args[I].getAsDecl()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
- }
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
+ LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
+ break;
+
+ case TemplateArgument::NullPtr:
+ LV.mergeWithMin(getLVForType(Args[I].getNullPtrType()));
break;
case TemplateArgument::Template:
@@ -193,7 +193,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
// anyway.
return TSK != TSK_ExplicitInstantiationDeclaration &&
TSK != TSK_ExplicitInstantiationDefinition &&
- FD->hasBody(Def) && Def->isInlined();
+ FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>();
}
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
@@ -213,12 +213,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() == SC_Static)
return LinkageInfo::internal();
- // - an object or reference that is explicitly declared const
- // and neither explicitly declared extern nor previously
- // declared to have external linkage; or
- // (there is no equivalent in C99)
+ // - a non-volatile object or reference that is explicitly declared const
+ // or constexpr and neither explicitly declared extern nor previously
+ // declared to have external linkage; or (there is no equivalent in C99)
if (Context.getLangOpts().CPlusPlus &&
- Var->getType().isConstant(Context) &&
+ Var->getType().isConstQualified() &&
+ !Var->getType().isVolatileQualified() &&
Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern) {
bool FoundExtern = false;
@@ -236,8 +236,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
for (; PrevVar; PrevVar = PrevVar->getPreviousDecl())
if (PrevVar->getStorageClass() == SC_PrivateExtern)
break;
- if (PrevVar)
- return PrevVar->getLinkageAndVisibility();
+ if (PrevVar)
+ return PrevVar->getLinkageAndVisibility();
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -341,25 +341,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
- if (!Context.getLangOpts().CPlusPlus &&
- (Var->getStorageClass() == SC_Extern ||
- Var->getStorageClass() == SC_PrivateExtern)) {
-
- // 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 VarDecl *PrevVar = Var->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(PrevVar, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
- }
+ // 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.
// - a function, unless it has internal linkage; or
} else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -841,13 +825,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
LV.mergeVisibility(*Vis, true);
}
-
- if (const VarDecl *Prev = Var->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
+ // 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;
}
}
@@ -903,7 +884,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionProtoType *FT = 0;
if (FD->hasWrittenPrototype())
- FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+ FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>());
OS << *FD << '(';
if (FT) {
@@ -1204,8 +1185,11 @@ void VarDecl::setStorageClass(StorageClass SC) {
}
SourceRange VarDecl::getSourceRange() const {
- if (getInit())
- return SourceRange(getOuterLocStart(), getInit()->getLocEnd());
+ if (const Expr *Init = getInit()) {
+ SourceLocation InitEnd = Init->getLocEnd();
+ if (InitEnd.isValid())
+ return SourceRange(getOuterLocStart(), InitEnd);
+ }
return DeclaratorDecl::getSourceRange();
}
@@ -1859,7 +1843,7 @@ unsigned FunctionDecl::getBuiltinID() const {
/// based on its FunctionType. This is the length of the ParamInfo array
/// after it has been created.
unsigned FunctionDecl::getNumParams() const {
- const FunctionType *FT = getType()->getAs<FunctionType>();
+ const FunctionType *FT = getType()->castAs<FunctionType>();
if (isa<FunctionNoProtoType>(FT))
return 0;
return cast<FunctionProtoType>(FT)->getNumArgs();
@@ -2514,7 +2498,7 @@ unsigned FieldDecl::getFieldIndex() const {
unsigned Index = 0;
const RecordDecl *RD = getParent();
const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ bool IsMsStruct = RD->isMsStruct(getASTContext());
for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++Index) {
@@ -2762,6 +2746,17 @@ void RecordDecl::completeDefinition() {
TagDecl::completeDefinition();
}
+/// isMsStruct - Get whether or not this record uses ms_struct layout.
+/// This which can be turned on with an attribute, pragma, or the
+/// -mms-bitfields command-line option.
+bool RecordDecl::isMsStruct(const ASTContext &C) const {
+ return hasAttr<MsStructAttr>() || C.getLangOpts().MSBitfields == 1;
+}
+
+static bool isFieldOrIndirectField(Decl::Kind K) {
+ return FieldDecl::classofKind(K) || IndirectFieldDecl::classofKind(K);
+}
+
void RecordDecl::LoadFieldsFromExternalStorage() const {
ExternalASTSource *Source = getASTContext().getExternalSource();
assert(hasExternalLexicalStorage() && Source && "No external storage?");
@@ -2771,7 +2766,8 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
SmallVector<Decl*, 64> Decls;
LoadedFieldsFromExternalStorage = true;
- switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) {
+ switch (Source->FindExternalLexicalDecls(this, isFieldOrIndirectField,
+ Decls)) {
case ELR_Success:
break;
@@ -2783,7 +2779,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
#ifndef NDEBUG
// Check that all decls we got were FieldDecls.
for (unsigned i=0, e=Decls.size(); i != e; ++i)
- assert(isa<FieldDecl>(Decls[i]));
+ assert(isa<FieldDecl>(Decls[i]) || isa<IndirectFieldDecl>(Decls[i]));
#endif
if (Decls.empty())
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index f9ce46def5b9..4400d503f263 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -961,7 +961,7 @@ DeclContext::lookup_result
ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
ArrayRef<NamedDecl*> Decls) {
- ASTContext &Context = DC->getParentASTContext();;
+ ASTContext &Context = DC->getParentASTContext();
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 2f21e4cbd652..82e630acefba 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -90,11 +90,12 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
}
CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
- SourceLocation Loc, bool Dependent) {
+ TypeSourceInfo *Info, SourceLocation Loc,
+ bool Dependent) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
0, 0);
R->IsBeingDefined = true;
- R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent);
+ R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -239,10 +240,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// -- 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.
+ // 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())
+ if (!BaseClassDecl->hasTrivialMoveConstructor() ||
+ !(BaseClassDecl->hasDeclaredMoveConstructor() ||
+ BaseClassDecl->needsImplicitMoveConstructor()))
data().HasTrivialMoveConstructor = false;
// C++0x [class.copy]p27:
@@ -254,7 +258,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
- if (!BaseClassDecl->hasTrivialMoveAssignment())
+ if (!BaseClassDecl->hasTrivialMoveAssignment() ||
+ !(BaseClassDecl->hasDeclaredMoveAssignment() ||
+ BaseClassDecl->needsImplicitMoveAssignment()))
data().HasTrivialMoveAssignment = false;
// C++11 [class.ctor]p6:
@@ -466,7 +472,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
!isa<IndirectFieldDecl>(D) &&
- (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class))
+ (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class ||
+ cast<TagDecl>(D)->getTagKind() == TTK_Interface))
data().HasOnlyCMembers = false;
// Ignore friends and invalid declarations.
@@ -828,7 +835,9 @@ NotASpecialMember:;
// FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
- if (!FieldRec->hasTrivialMoveConstructor())
+ if (!FieldRec->hasTrivialMoveConstructor() ||
+ !(FieldRec->hasDeclaredMoveConstructor() ||
+ FieldRec->needsImplicitMoveConstructor()))
data().HasTrivialMoveConstructor = false;
// C++0x [class.copy]p27:
@@ -840,7 +849,9 @@ NotASpecialMember:;
// FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
- if (!FieldRec->hasTrivialMoveAssignment())
+ if (!FieldRec->hasTrivialMoveAssignment() ||
+ !(FieldRec->hasDeclaredMoveAssignment() ||
+ FieldRec->needsImplicitMoveAssignment()))
data().HasTrivialMoveAssignment = false;
if (!FieldRec->hasTrivialDestructor())
@@ -936,7 +947,8 @@ NotASpecialMember:;
}
bool CXXRecordDecl::isCLike() const {
- if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull())
+ if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
+ !TemplateOrInstantiation.isNull())
return false;
if (!hasDefinition())
return true;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 4d48ad8e4f5a..65a987836ff8 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/ASTMutationListener.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -93,6 +94,16 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
return 0;
}
+IdentifierInfo *
+ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
+ SmallString<128> ivarName;
+ {
+ llvm::raw_svector_ostream os(ivarName);
+ os << '_' << getIdentifier()->getName();
+ }
+ return &Ctx.Idents.get(ivarName.str());
+}
+
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *
@@ -179,6 +190,21 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return 0;
}
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
+ for (ObjCContainerDecl::prop_iterator P = prop_begin(),
+ E = prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ PM[Prop->getIdentifier()] = Prop;
+ }
+ for (ObjCInterfaceDecl::all_protocol_iterator
+ PI = all_referenced_protocol_begin(),
+ E = all_referenced_protocol_end(); PI != E; ++PI)
+ (*PI)->collectPropertiesToImplement(PM);
+ // 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.
+}
+
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
@@ -414,16 +440,15 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
DeclContext *contextDecl,
bool isInstance,
bool isVariadic,
- bool isSynthesized,
+ bool isPropertyAccessor,
bool isImplicitlyDeclared,
bool isDefined,
ImplementationControl impControl,
bool HasRelatedResultType) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
- isInstance,
- isVariadic, isSynthesized, isImplicitlyDeclared,
- isDefined,
+ isInstance, isVariadic, isPropertyAccessor,
+ isImplicitlyDeclared, isDefined,
impControl,
HasRelatedResultType);
}
@@ -434,6 +459,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
Selector(), QualType(), 0, 0);
}
+Stmt *ObjCMethodDecl::getBody() const {
+ return Body.get(getASTContext().getExternalSource());
+}
+
void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
assert(PrevMethod);
getASTContext().setObjCMethodRedeclaration(PrevMethod, this);
@@ -707,6 +736,224 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
llvm_unreachable("unknown method context");
}
+static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods,
+ bool MovedToSuper) {
+ if (!Container)
+ return;
+
+ // In categories look for overriden methods from protocols. A method from
+ // category is not "overriden" since it is considered as the "same" method
+ // (same USR) as the one from the interface.
+ if (const ObjCCategoryDecl *
+ Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Check whether we have a matching method at this category but only if we
+ // are at the super class level.
+ if (MovedToSuper)
+ if (ObjCMethodDecl *
+ Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this category; there is no need to look
+ // into its protocols.
+ Methods.push_back(Overridden);
+ return;
+ }
+
+ for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
+ PEnd = Category->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+ return;
+ }
+
+ // Check whether we have a matching method at this level.
+ if (const ObjCMethodDecl *
+ Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this level; there is no need to look
+ // into other protocols or categories.
+ Methods.push_back(Overridden);
+ return;
+ }
+
+ if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){
+ for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
+ PEnd = Protocol->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+ }
+
+ if (const ObjCInterfaceDecl *
+ Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
+ PEnd = Interface->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+
+ for (const ObjCCategoryDecl *Category = Interface->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ CollectOverriddenMethodsRecurse(Category, Method, Methods,
+ MovedToSuper);
+
+ if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
+ return CollectOverriddenMethodsRecurse(Super, Method, Methods,
+ /*MovedToSuper=*/true);
+ }
+}
+
+static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
+ CollectOverriddenMethodsRecurse(Container, Method, Methods,
+ /*MovedToSuper=*/false);
+}
+
+static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &overridden) {
+ assert(Method->isOverriding());
+
+ if (const ObjCProtocolDecl *
+ ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
+ CollectOverriddenMethods(ProtD, Method, overridden);
+
+ } else if (const ObjCImplDecl *
+ IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
+ const ObjCInterfaceDecl *ID = IMD->getClassInterface();
+ if (!ID)
+ return;
+ // 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 = IFaceMeth;
+ CollectOverriddenMethods(ID, Method, overridden);
+
+ } else if (const ObjCCategoryDecl *
+ CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
+ const ObjCInterfaceDecl *ID = CatD->getClassInterface();
+ if (!ID)
+ return;
+ // 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 = IFaceMeth;
+ CollectOverriddenMethods(ID, Method, overridden);
+
+ } else {
+ CollectOverriddenMethods(
+ dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
+ Method, overridden);
+ }
+}
+
+static void collectOnCategoriesAfterLocation(SourceLocation Loc,
+ const ObjCInterfaceDecl *Class,
+ SourceManager &SM,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
+ if (!Class)
+ return;
+
+ for (const ObjCCategoryDecl *Category = Class->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
+ CollectOverriddenMethodsRecurse(Category, Method, Methods, true);
+
+ collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
+ Method, Methods);
+}
+
+/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
+/// returns false.
+/// You'd think that in that case there are no overrides but categories can
+/// "introduce" new overridden methods that are missed by Sema because the
+/// overrides lookup that it does for methods, inside implementations, will
+/// stop at the interface level (if there is a method there) and not look
+/// further in super classes.
+/// Methods in an implementation can overide methods in super class's category
+/// but not in current class's category. But, such methods
+static void collectOverriddenMethodsFast(SourceManager &SM,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
+ assert(!Method->isOverriding());
+
+ const ObjCContainerDecl *
+ ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
+ if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
+ return;
+ const ObjCInterfaceDecl *Class = Method->getClassInterface();
+ if (!Class)
+ return;
+
+ collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
+ SM, Method, Methods);
+}
+
+void ObjCMethodDecl::getOverriddenMethods(
+ SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const {
+ const ObjCMethodDecl *Method = this;
+
+ if (Method->isRedeclaration()) {
+ Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
+ getMethod(Method->getSelector(), Method->isInstanceMethod());
+ }
+
+ if (!Method->isOverriding()) {
+ collectOverriddenMethodsFast(getASTContext().getSourceManager(),
+ Method, Overridden);
+ } else {
+ collectOverriddenMethodsSlow(Method, Overridden);
+ assert(!Overridden.empty() &&
+ "ObjCMethodDecl's overriding bit is not as expected");
+ }
+}
+
+const ObjCPropertyDecl *
+ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
+ Selector Sel = getSelector();
+ unsigned NumArgs = Sel.getNumArgs();
+ if (NumArgs > 1)
+ return 0;
+
+ if (!isInstanceMethod() || getMethodFamily() != OMF_None)
+ return 0;
+
+ if (isPropertyAccessor()) {
+ const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
+ bool IsGetter = (NumArgs == 0);
+
+ for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(),
+ E = Container->prop_end();
+ I != E; ++I) {
+ Selector NextSel = IsGetter ? (*I)->getGetterName()
+ : (*I)->getSetterName();
+ if (NextSel == Sel)
+ return *I;
+ }
+
+ llvm_unreachable("Marked as a property accessor but no property found!");
+ }
+
+ if (!CheckOverrides)
+ return 0;
+
+ typedef SmallVector<const ObjCMethodDecl *, 8> OverridesTy;
+ OverridesTy Overrides;
+ getOverriddenMethods(Overrides);
+ for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end();
+ I != E; ++I) {
+ if (const ObjCPropertyDecl *Prop = (*I)->findPropertyDecl(false))
+ return Prop;
+ }
+
+ return 0;
+
+}
+
//===----------------------------------------------------------------------===//
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//
@@ -1081,6 +1328,20 @@ 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));
+ }
+ // Scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(),
+ E = protocol_end(); PI != E; ++PI)
+ (*PI)->collectPropertiesToImplement(PM);
+}
+
+
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 7f47604dece3..386ad66c9917 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -105,6 +105,8 @@ static QualType GetBaseType(QualType T) {
break;
else if (const PointerType* PTy = BaseType->getAs<PointerType>())
BaseType = PTy->getPointeeType();
+ else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
+ BaseType = BPy->getPointeeType();
else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
BaseType = ATy->getElementType();
else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
@@ -189,6 +191,9 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
}
void DeclPrinter::prettyPrintAttributes(Decl *D) {
+ if (Policy.SuppressAttributes)
+ return;
+
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
@@ -220,6 +225,9 @@ void DeclPrinter::Print(AccessSpecifier AS) {
//----------------------------------------------------------------------------
void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
+ if (Policy.TerseOutput)
+ return;
+
if (Indent)
Indentation += Policy.Indentation;
@@ -459,7 +467,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (I)
Proto += ", ";
- Proto += FT->getExceptionType(I).getAsString(SubPolicy);;
+ Proto += FT->getExceptionType(I).getAsString(SubPolicy);
}
Proto += ")";
} else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
@@ -550,7 +558,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << " = 0";
else if (D->isDeletedAsWritten())
Out << " = delete";
- else if (D->doesThisDeclarationHaveABody()) {
+ else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
// parameters.
@@ -621,13 +629,13 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
ImplicitInit = D->getInitStyle() == VarDecl::CallInit &&
Construct->getNumArgs() == 0 && !Construct->isListInitialization();
if (!ImplicitInit) {
- if (D->getInitStyle() == VarDecl::CallInit)
+ if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << "(";
else if (D->getInitStyle() == VarDecl::CInit) {
Out << " = ";
}
Init->printPretty(Out, 0, Policy, Indentation);
- if (D->getInitStyle() == VarDecl::CallInit)
+ if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << ")";
}
}
@@ -869,7 +877,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isVariadic())
Out << ", ...";
- if (OMD->getBody()) {
+ if (OMD->getBody() && !Policy.TerseOutput) {
Out << ' ';
OMD->getBody()->printPretty(Out, 0, Policy);
Out << '\n';
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a7e89994afe8..a70983f4c962 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
- NumParams(NumParams) {
- for (unsigned Idx = 0; Idx < NumParams; ++Idx)
- begin()[Idx] = Params[Idx];
+ NumParams(NumParams), ContainsUnexpandedParameterPack(false) {
+ assert(this->NumParams == NumParams && "Too many template parameters");
+ for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
+ NamedDecl *P = Params[Idx];
+ begin()[Idx] = P;
+
+ if (!P->isTemplateParameterPack()) {
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
+ if (NTTP->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
+ if (TTP->getTemplateParameters()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ // FIXME: If a default argument contains an unexpanded parameter pack, the
+ // template parameter list does too.
+ }
+ }
}
TemplateParameterList *
@@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
void TemplateTemplateParmDecl::anchor() { }
+TemplateTemplateParmDecl::TemplateTemplateParmDecl(
+ DeclContext *DC, SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id, TemplateParameterList *Params,
+ unsigned NumExpansions, TemplateParameterList * const *Expansions)
+ : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
+ TemplateParmPosition(D, P), DefaultArgument(),
+ DefaultArgumentWasInherited(false), ParameterPack(true),
+ ExpandedParameterPack(true), NumExpandedParams(NumExpansions) {
+ if (Expansions)
+ std::memcpy(reinterpret_cast<void*>(this + 1), Expansions,
+ sizeof(TemplateParameterList*) * NumExpandedParams);
+}
+
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
@@ -587,12 +616,35 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
}
TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id,
+ TemplateParameterList *Params,
+ llvm::ArrayRef<TemplateParameterList*> Expansions) {
+ void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
+ sizeof(TemplateParameterList*) * Expansions.size());
+ return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
+ Expansions.size(),
+ Expansions.data());
+}
+
+TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false,
0, 0);
}
+TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NumExpansions) {
+ unsigned Size = sizeof(TemplateTemplateParmDecl) +
+ sizeof(TemplateParameterList*) * NumExpansions;
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0,
+ NumExpansions, 0);
+}
+
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
@@ -712,13 +764,27 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
SourceRange
ClassTemplateSpecializationDecl::getSourceRange() const {
if (ExplicitInfo) {
- SourceLocation Begin = getExternLoc();
- if (Begin.isInvalid())
- Begin = getTemplateKeywordLoc();
- SourceLocation End = getRBraceLoc();
- if (End.isInvalid())
- End = getTypeAsWritten()->getTypeLoc().getEndLoc();
- return SourceRange(Begin, End);
+ SourceLocation Begin = getTemplateKeywordLoc();
+ if (Begin.isValid()) {
+ // Here we have an explicit (partial) specialization or instantiation.
+ assert(getSpecializationKind() == TSK_ExplicitSpecialization ||
+ getSpecializationKind() == TSK_ExplicitInstantiationDeclaration ||
+ getSpecializationKind() == TSK_ExplicitInstantiationDefinition);
+ if (getExternLoc().isValid())
+ Begin = getExternLoc();
+ SourceLocation End = getRBraceLoc();
+ if (End.isInvalid())
+ End = getTypeAsWritten()->getTypeLoc().getEndLoc();
+ return SourceRange(Begin, End);
+ }
+ // An implicit instantiation of a class template partial specialization
+ // uses ExplicitInfo to record the TypeAsWritten, but the source
+ // locations should be retrieved from the instantiation pattern.
+ typedef ClassTemplatePartialSpecializationDecl CTPSDecl;
+ CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this));
+ CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember();
+ assert(inst_from != 0);
+ return inst_from->getSourceRange();
}
else {
// No explicit info available.
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 84f3fc491cb0..5f43fbc251a0 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -1,4 +1,4 @@
-//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===//
+//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -64,6 +64,8 @@ template <class Impl> struct XMLDeclVisitor {
static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D))
void dispatch(Decl *D) {
+ if (D->isUsed())
+ static_cast<Impl*>(this)->set("used", "1");
switch (D->getKind()) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
@@ -316,12 +318,12 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::NullPtr:
// FIXME: Implement!
break;
case TemplateArgument::Declaration: {
- if (Decl *D = A.getAsDecl())
- visitDeclRef(D);
+ visitDeclRef(A.getAsDecl());
break;
}
case TemplateArgument::Integral: {
@@ -841,7 +843,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("instance", D->isInstanceMethod());
setFlag("variadic", D->isVariadic());
- setFlag("synthesized", D->isSynthesized());
+ setFlag("property_accessor", D->isPropertyAccessor());
setFlag("defined", D->isDefined());
setFlag("related_result_type", D->hasRelatedResultType());
}
@@ -920,6 +922,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
case CC_X86Pascal: return set("cc", "x86_pascal");
case CC_AAPCS: return set("cc", "aapcs");
case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
+ case CC_PnaclCall: return set("cc", "pnaclcall");
}
}
@@ -974,6 +977,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("const", T->isConst());
setFlag("volatile", T->isVolatile());
setFlag("restrict", T->isRestrict());
+ switch (T->getExceptionSpecType()) {
+ case EST_None: break;
+ case EST_DynamicNone: set("exception_spec", "throw()"); break;
+ case EST_Dynamic: set("exception_spec", "throw(T)"); break;
+ case EST_MSAny: set("exception_spec", "throw(...)"); break;
+ case EST_BasicNoexcept: set("exception_spec", "noexcept"); break;
+ case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break;
+ case EST_Unevaluated: set("exception_spec", "unevaluated"); break;
+ case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break;
+ }
}
void visitFunctionProtoTypeChildren(FunctionProtoType *T) {
push("parameters");
@@ -1023,7 +1036,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
void Decl::dumpXML() const {
- dump(llvm::errs());
+ dumpXML(llvm::errs());
}
void Decl::dumpXML(raw_ostream &out) const {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 24361efafa6c..f3a2e0563872 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -48,6 +48,75 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
return cast<CXXRecordDecl>(D);
}
+const Expr *
+Expr::skipRValueSubobjectAdjustments(
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
+ const Expr *E = this;
+ while (true) {
+ E = E->IgnoreParens();
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if ((CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase) &&
+ E->getType()->isRecordType()) {
+ E = CE->getSubExpr();
+ CXXRecordDecl *Derived
+ = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+ Adjustments.push_back(SubobjectAdjustment(CE, Derived));
+ continue;
+ }
+
+ if (CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ assert(ME->getBase()->getType()->isRecordType());
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ E = ME->getBase();
+ Adjustments.push_back(SubobjectAdjustment(Field));
+ continue;
+ }
+ }
+ } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->isPtrMemOp()) {
+ assert(BO->getRHS()->isRValue());
+ E = BO->getLHS();
+ const MemberPointerType *MPT =
+ BO->getRHS()->getType()->getAs<MemberPointerType>();
+ Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
+ }
+ }
+
+ // Nothing changed.
+ break;
+ }
+ return E;
+}
+
+const Expr *
+Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const {
+ const Expr *E = this;
+ // Look through single-element init lists that claim to be lvalues. They're
+ // just syntactic wrappers in this case.
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue())
+ E = ILE->getInit(0);
+ }
+
+ // Look through expressions for materialized temporaries (for now).
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ MTE = M;
+ E = M->GetTemporaryExpr();
+ }
+
+ if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
+ E = DAE->getExpr();
+ return E;
+}
+
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
@@ -784,19 +853,19 @@ void StringLiteral::setString(ASTContext &C, StringRef Str,
switch(CharByteWidth) {
case 1: {
char *AStrData = new (C) char[Length];
- std::memcpy(AStrData,Str.data(),Str.size());
+ std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
StrData.asChar = AStrData;
break;
}
case 2: {
uint16_t *AStrData = new (C) uint16_t[Length];
- std::memcpy(AStrData,Str.data(),Str.size());
+ std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
StrData.asUInt16 = AStrData;
break;
}
case 4: {
uint32_t *AStrData = new (C) uint32_t[Length];
- std::memcpy(AStrData,Str.data(),Str.size());
+ std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
StrData.asUInt32 = AStrData;
break;
}
@@ -869,7 +938,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++".
-const char *UnaryOperator::getOpcodeStr(Opcode Op) {
+StringRef UnaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
case UO_PostInc: return "++";
case UO_PostDec: return "--";
@@ -923,18 +992,18 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
//===----------------------------------------------------------------------===//
CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- Expr **args, unsigned numargs, QualType t, ExprValueKind VK,
+ ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc)
: Expr(SC, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
fn->isInstantiationDependent(),
fn->containsUnexpandedParameterPack()),
- NumArgs(numargs) {
+ NumArgs(args.size()) {
- SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs];
+ SubExprs = new (C) Stmt*[args.size()+PREARGS_START+NumPreArgs];
SubExprs[FN] = fn;
- for (unsigned i = 0; i != numargs; ++i) {
+ for (unsigned i = 0; i != args.size(); ++i) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
@@ -951,18 +1020,18 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
+CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
: Expr(CallExprClass, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
fn->isInstantiationDependent(),
fn->containsUnexpandedParameterPack()),
- NumArgs(numargs) {
+ NumArgs(args.size()) {
- SubExprs = new (C) Stmt*[numargs+PREARGS_START];
+ SubExprs = new (C) Stmt*[args.size()+PREARGS_START];
SubExprs[FN] = fn;
- for (unsigned i = 0; i != numargs; ++i) {
+ for (unsigned i = 0; i != args.size(); ++i) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
@@ -1123,15 +1192,15 @@ SourceLocation CallExpr::getLocEnd() const {
OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
- Expr** exprsPtr, unsigned numExprs,
+ ArrayRef<OffsetOfNode> comps,
+ ArrayRef<Expr*> exprs,
SourceLocation RParenLoc) {
void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
- sizeof(OffsetOfNode) * numComps +
- sizeof(Expr*) * numExprs);
+ sizeof(OffsetOfNode) * comps.size() +
+ sizeof(Expr*) * exprs.size());
- return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps,
- exprsPtr, numExprs, RParenLoc);
+ return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs,
+ RParenLoc);
}
OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
@@ -1144,8 +1213,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
- Expr** exprsPtr, unsigned numExprs,
+ ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc)
: Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary,
/*TypeDependent=*/false,
@@ -1153,19 +1221,19 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
tsi->getType()->isInstantiationDependentType(),
tsi->getType()->containsUnexpandedParameterPack()),
OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi),
- NumComps(numComps), NumExprs(numExprs)
+ NumComps(comps.size()), NumExprs(exprs.size())
{
- for(unsigned i = 0; i < numComps; ++i) {
- setComponent(i, compsPtr[i]);
+ for (unsigned i = 0; i != comps.size(); ++i) {
+ setComponent(i, comps[i]);
}
- for(unsigned i = 0; i < numExprs; ++i) {
- if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent())
+ for (unsigned i = 0; i != exprs.size(); ++i) {
+ if (exprs[i]->isTypeDependent() || exprs[i]->isValueDependent())
ExprBits.ValueDependent = true;
- if (exprsPtr[i]->containsUnexpandedParameterPack())
+ if (exprs[i]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
- setIndexExpr(i, exprsPtr[i]);
+ setIndexExpr(i, exprs[i]);
}
}
@@ -1259,9 +1327,12 @@ SourceLocation MemberExpr::getLocStart() const {
return MemberLoc;
}
SourceLocation MemberExpr::getLocEnd() const {
+ SourceLocation EndLoc = getMemberNameInfo().getEndLoc();
if (hasExplicitTemplateArgs())
- return getRAngleLoc();
- return getMemberNameInfo().getEndLoc();
+ EndLoc = getRAngleLoc();
+ else if (EndLoc.isInvalid())
+ EndLoc = getBase()->getLocEnd();
+ return EndLoc;
}
void CastExpr::CheckCastConsistency() const {
@@ -1311,12 +1382,16 @@ void CastExpr::CheckCastConsistency() const {
assert(getType()->isBlockPointerType());
assert(getSubExpr()->getType()->isBlockPointerType());
goto CheckNoBasePath;
-
+
+ case CK_FunctionToPointerDecay:
+ assert(getType()->isPointerType());
+ assert(getSubExpr()->getType()->isFunctionType());
+ goto CheckNoBasePath;
+
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
case CK_NullToMemberPointer:
case CK_NullToPointer:
case CK_ConstructorConversion:
@@ -1357,6 +1432,7 @@ void CastExpr::CheckCastConsistency() const {
case CK_IntegralComplexToBoolean:
case CK_LValueBitCast: // -> bool&
case CK_UserDefinedConversion: // operator bool()
+ case CK_BuiltinFnToFnPtr:
CheckNoBasePath:
assert(path_empty() && "Cast kind should not have a base path!");
break;
@@ -1469,6 +1545,8 @@ const char *CastExpr::getCastKindName() const {
return "NonAtomicToAtomic";
case CK_CopyAndAutoreleaseBlockObject:
return "CopyAndAutoreleaseBlockObject";
+ case CK_BuiltinFnToFnPtr:
+ return "BuiltinFnToFnPtr";
}
llvm_unreachable("Unhandled cast kind!");
@@ -1564,7 +1642,7 @@ CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
-const char *BinaryOperator::getOpcodeStr(Opcode Op) {
+StringRef BinaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
case BO_PtrMemD: return ".*";
case BO_PtrMemI: return "->*";
@@ -1666,16 +1744,15 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
}
InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
- Expr **initExprs, unsigned numInits,
- SourceLocation rbraceloc)
+ ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
- InitExprs(C, numInits),
- LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0)
+ InitExprs(C, initExprs.size()),
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
{
sawArrayRangeDesignator(false);
setInitializesStdInitializerList(false);
- for (unsigned I = 0; I != numInits; ++I) {
+ for (unsigned I = 0; I != initExprs.size(); ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
if (initExprs[I]->isValueDependent())
@@ -1686,7 +1763,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
ExprBits.ContainsUnexpandedParameterPack = true;
}
- InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits);
+ InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end());
}
void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
@@ -1723,15 +1800,15 @@ void InitListExpr::setArrayFiller(Expr *filler) {
bool InitListExpr::isStringLiteralInit() const {
if (getNumInits() != 1)
return false;
- const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(getType());
- if (!CAT || !CAT->getElementType()->isIntegerType())
+ const ArrayType *AT = getType()->getAsArrayTypeUnsafe();
+ if (!AT || !AT->getElementType()->isIntegerType())
return false;
- const Expr *Init = getInit(0)->IgnoreParenImpCasts();
+ const Expr *Init = getInit(0)->IgnoreParens();
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
}
SourceRange InitListExpr::getSourceRange() const {
- if (SyntacticForm)
+ if (InitListExpr *SyntacticForm = getSyntacticForm())
return SyntacticForm->getSourceRange();
SourceLocation Beg = LBraceLoc, End = RBraceLoc;
if (Beg.isInvalid()) {
@@ -1945,6 +2022,11 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
}
+ // If we don't know precisely what we're looking at, let's not warn.
+ case UnresolvedLookupExprClass:
+ case CXXUnresolvedConstructExprClass:
+ return false;
+
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass:
return false;
@@ -2014,6 +2096,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
R1 = getSourceRange();
return true;
}
+ case CXXFunctionalCastExprClass:
case CStyleCastExprClass: {
// Ignore an explicit cast to void unless the operand is a non-trivial
// volatile lvalue.
@@ -2032,6 +2115,10 @@ 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)
@@ -2641,6 +2728,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case UnresolvedMemberExprClass:
case PackExpansionExprClass:
case SubstNonTypeTemplateParmPackExprClass:
+ case FunctionParmPackExprClass:
llvm_unreachable("shouldn't see dependent / unresolved nodes here");
case DeclRefExprClass:
@@ -2995,6 +3083,24 @@ const ObjCPropertyRefExpr *Expr::getObjCProperty() const {
return cast<ObjCPropertyRefExpr>(E);
}
+bool Expr::isObjCSelfExpr() const {
+ const Expr *E = IgnoreParenImpCasts();
+
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE)
+ return false;
+
+ const ImplicitParamDecl *Param = dyn_cast<ImplicitParamDecl>(DRE->getDecl());
+ if (!Param)
+ return false;
+
+ const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(Param->getDeclContext());
+ if (!M)
+ return false;
+
+ return M->getSelfDecl() == Param;
+}
+
FieldDecl *Expr::getBitField() {
Expr *E = this->IgnoreParens();
@@ -3339,33 +3445,29 @@ Selector ObjCMessageExpr::getSelector() const {
return Selector(SelectorOrMethod);
}
-ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+QualType ObjCMessageExpr::getReceiverType() const {
switch (getReceiverKind()) {
case Instance:
- if (const ObjCObjectPointerType *Ptr
- = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>())
- return Ptr->getInterfaceDecl();
- break;
-
+ return getInstanceReceiver()->getType();
case Class:
- if (const ObjCObjectType *Ty
- = getClassReceiver()->getAs<ObjCObjectType>())
- return Ty->getInterface();
- break;
-
+ return getClassReceiver();
case SuperInstance:
- if (const ObjCObjectPointerType *Ptr
- = getSuperType()->getAs<ObjCObjectPointerType>())
- return Ptr->getInterfaceDecl();
- break;
-
case SuperClass:
- if (const ObjCObjectType *Iface
- = getSuperType()->getAs<ObjCObjectType>())
- return Iface->getInterface();
- break;
+ return getSuperType();
}
+ llvm_unreachable("unexpected receiver kind");
+}
+
+ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+ QualType T = getReceiverType();
+
+ if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
+ return Ptr->getInterfaceDecl();
+
+ if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>())
+ return Ty->getInterface();
+
return 0;
}
@@ -3386,17 +3488,17 @@ bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
return getCond()->EvaluateKnownConstInt(C) != 0;
}
-ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
+ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
QualType Type, SourceLocation BLoc,
SourceLocation RP)
: Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
Type->isDependentType(), Type->isDependentType(),
Type->isInstantiationDependentType(),
Type->containsUnexpandedParameterPack()),
- BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr)
+ BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(args.size())
{
- SubExprs = new (C) Stmt*[nexpr];
- for (unsigned i = 0; i < nexpr; i++) {
+ SubExprs = new (C) Stmt*[args.size()];
+ for (unsigned i = 0; i != args.size(); i++) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
@@ -3421,8 +3523,9 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
- TypeSourceInfo **AssocTypes, Expr **AssocExprs,
- unsigned NumAssocs, SourceLocation DefaultLoc,
+ ArrayRef<TypeSourceInfo*> AssocTypes,
+ ArrayRef<Expr*> AssocExprs,
+ SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack,
unsigned ResultIndex)
@@ -3434,19 +3537,21 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
AssocExprs[ResultIndex]->isValueDependent(),
AssocExprs[ResultIndex]->isInstantiationDependent(),
ContainsUnexpandedParameterPack),
- AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
- SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
- ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
- RParenLoc(RParenLoc) {
+ AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]),
+ SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]),
+ NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex),
+ GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
SubExprs[CONTROLLING] = ControllingExpr;
- std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
- std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+ assert(AssocTypes.size() == AssocExprs.size());
+ std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes);
+ std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
- TypeSourceInfo **AssocTypes, Expr **AssocExprs,
- unsigned NumAssocs, SourceLocation DefaultLoc,
+ ArrayRef<TypeSourceInfo*> AssocTypes,
+ ArrayRef<Expr*> AssocExprs,
+ SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack)
: Expr(GenericSelectionExprClass,
@@ -3457,13 +3562,14 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
/*isValueDependent=*/true,
/*isInstantiationDependent=*/true,
ContainsUnexpandedParameterPack),
- AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
- SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
- ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
- RParenLoc(RParenLoc) {
+ AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]),
+ SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]),
+ NumAssocs(AssocExprs.size()), ResultIndex(-1U), GenericLoc(GenericLoc),
+ DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
SubExprs[CONTROLLING] = ControllingExpr;
- std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
- std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+ assert(AssocTypes.size() == AssocExprs.size());
+ std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes);
+ std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
//===----------------------------------------------------------------------===//
@@ -3483,8 +3589,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
bool GNUSyntax,
- Expr **IndexExprs,
- unsigned NumIndexExprs,
+ ArrayRef<Expr*> IndexExprs,
Expr *Init)
: Expr(DesignatedInitExprClass, Ty,
Init->getValueKind(), Init->getObjectKind(),
@@ -3492,7 +3597,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
Init->isInstantiationDependent(),
Init->containsUnexpandedParameterPack()),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
- NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
+ NumDesignators(NumDesignators), NumSubExprs(IndexExprs.size() + 1) {
this->Designators = new (C) Designator[NumDesignators];
// Record the initializer itself.
@@ -3542,20 +3647,20 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
}
}
- assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions");
+ assert(IndexIdx == IndexExprs.size() && "Wrong number of index expressions");
}
DesignatedInitExpr *
DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
- Expr **IndexExprs, unsigned NumIndexExprs,
+ ArrayRef<Expr*> IndexExprs,
SourceLocation ColonOrEqualLoc,
bool UsesColonSyntax, Expr *Init) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
- sizeof(Stmt *) * (NumIndexExprs + 1), 8);
+ sizeof(Stmt *) * (IndexExprs.size() + 1), 8);
return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
- IndexExprs, NumIndexExprs, Init);
+ IndexExprs, Init);
}
DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
@@ -3651,13 +3756,13 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
}
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
- Expr **exprs, unsigned nexprs,
+ ArrayRef<Expr*> exprs,
SourceLocation rparenloc)
: Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
false, false, false, false),
- NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) {
- Exprs = new (C) Stmt*[nexprs];
- for (unsigned i = 0; i != nexprs; ++i) {
+ NumExprs(exprs.size()), LParenLoc(lparenloc), RParenLoc(rparenloc) {
+ Exprs = new (C) Stmt*[exprs.size()];
+ for (unsigned i = 0; i != exprs.size(); ++i) {
if (exprs[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (exprs[i]->isValueDependent())
@@ -3902,14 +4007,14 @@ ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C,
getMethod, setMethod, RB);
}
-AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr,
+AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args,
QualType t, AtomicOp op, SourceLocation RP)
: Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
false, false, false, false),
- NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
+ NumSubExprs(args.size()), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
{
- assert(nexpr == getNumSubExprs(op) && "wrong number of subexpressions");
- for (unsigned i = 0; i < nexpr; i++) {
+ assert(args.size() == getNumSubExprs(op) && "wrong number of subexpressions");
+ for (unsigned i = 0; i != args.size(); i++) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 3fa49e0e18b9..55722a2a99af 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -51,6 +51,26 @@ QualType CXXUuidofExpr::getTypeOperand() const {
.getUnqualifiedType();
}
+// static
+UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
+ // Optionally remove one level of pointer, reference or array indirection.
+ const Type *Ty = QT.getTypePtr();
+ if (QT->isPointerType() || QT->isReferenceType())
+ Ty = QT->getPointeeType().getTypePtr();
+ else if (QT->isArrayType())
+ Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
+
+ // Loop all record redeclaration looking for an uuid attribute.
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
+ E = RD->redecls_end(); I != E; ++I) {
+ if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
+ return Uuid;
+ }
+
+ return 0;
+}
+
// CXXScalarValueInitExpr
SourceRange CXXScalarValueInitExpr::getSourceRange() const {
SourceLocation Start = RParenLoc;
@@ -63,24 +83,24 @@ SourceRange CXXScalarValueInitExpr::getSourceRange() const {
CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize,
- Expr **placementArgs, unsigned numPlaceArgs,
+ ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle,
Expr *initializer, QualType ty,
TypeSourceInfo *allocatedTypeInfo,
- SourceLocation startLoc, SourceRange directInitRange)
+ SourceRange Range, SourceRange directInitRange)
: Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary,
ty->isDependentType(), ty->isDependentType(),
ty->isInstantiationDependentType(),
ty->containsUnexpandedParameterPack()),
SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens),
- StartLoc(startLoc), DirectInitRange(directInitRange),
+ Range(Range), DirectInitRange(directInitRange),
GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {
assert((initializer != 0 || initializationStyle == NoInit) &&
"Only NoInit can have no initializer.");
StoredInitializationStyle = initializer ? initializationStyle + 1 : 0;
- AllocateArgsArray(C, arraySize != 0, numPlaceArgs, initializer != 0);
+ AllocateArgsArray(C, arraySize != 0, placementArgs.size(), initializer != 0);
unsigned i = 0;
if (Array) {
if (arraySize->isInstantiationDependent())
@@ -102,7 +122,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = initializer;
}
- for (unsigned j = 0; j < NumPlacementArgs; ++j) {
+ for (unsigned j = 0; j != placementArgs.size(); ++j) {
if (placementArgs[j]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (placementArgs[j]->containsUnexpandedParameterPack())
@@ -110,6 +130,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = placementArgs[j];
}
+
+ switch (getInitializationStyle()) {
+ case CallInit:
+ this->Range.setEnd(DirectInitRange.getEnd()); break;
+ case ListInit:
+ this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break;
+ default: break;
+ }
}
void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
@@ -127,18 +155,6 @@ bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
-SourceLocation CXXNewExpr::getEndLoc() const {
- switch (getInitializationStyle()) {
- case NoInit:
- return AllocatedTypeInfo->getTypeLoc().getEndLoc();
- case CallInit:
- return DirectInitRange.getEnd();
- case ListInit:
- return getInitializer()->getSourceRange().getEnd();
- }
- llvm_unreachable("bogus initialization style");
-}
-
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
const Expr *Arg = getArgument();
@@ -227,7 +243,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
TemplateKWLoc, NameInfo,
ADL, /*Overload*/ true, Args,
- Begin, End, /*StdIsAssociated=*/false);
+ Begin, End);
}
UnresolvedLookupExpr *
@@ -697,15 +713,14 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
- Cons, false, Args, NumArgs,
+ Cons, false, Args,
HadMultipleCandidates, /*FIXME*/false, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
@@ -719,14 +734,14 @@ SourceRange CXXTemporaryObjectExpr::getSourceRange() const {
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr*> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
- Elidable, Args, NumArgs,
+ Elidable, Args,
HadMultipleCandidates, ListInitialization,
ZeroInitialization, ConstructKind,
ParenRange);
@@ -735,7 +750,7 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
- Expr **args, unsigned numargs,
+ ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
@@ -745,16 +760,16 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
T->isDependentType(), T->isDependentType(),
T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs),
+ Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
ZeroInitialization(ZeroInitialization),
ConstructKind(ConstructKind), Args(0)
{
if (NumArgs) {
- Args = new (C) Stmt*[NumArgs];
+ Args = new (C) Stmt*[args.size()];
- for (unsigned i = 0; i != NumArgs; ++i) {
+ for (unsigned i = 0; i != args.size(); ++i) {
assert(args[i] && "NULL argument in CXXConstructExpr");
if (args[i]->isValueDependent())
@@ -877,9 +892,12 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
QualType T = Context.getTypeDeclType(Class);
unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (Captures.size() + 1);
- if (!ArrayIndexVars.empty())
- Size += sizeof(VarDecl *) * ArrayIndexVars.size()
- + sizeof(unsigned) * (Captures.size() + 1);
+ if (!ArrayIndexVars.empty()) {
+ Size += sizeof(unsigned) * (Captures.size() + 1);
+ // Realign for following VarDecl array.
+ Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<VarDecl*>());
+ Size += sizeof(VarDecl *) * ArrayIndexVars.size();
+ }
void *Mem = Context.Allocate(Size);
return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
Captures, ExplicitParams, ExplicitResultType,
@@ -997,8 +1015,7 @@ ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
SourceLocation LParenLoc,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceLocation RParenLoc)
: Expr(CXXUnresolvedConstructExprClass,
Type->getType().getNonReferenceType(),
@@ -1011,9 +1028,9 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
Type(Type),
LParenLoc(LParenLoc),
RParenLoc(RParenLoc),
- NumArgs(NumArgs) {
+ NumArgs(Args.size()) {
Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1);
- for (unsigned I = 0; I != NumArgs; ++I) {
+ for (unsigned I = 0; I != Args.size(); ++I) {
if (Args[I]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
@@ -1025,13 +1042,11 @@ CXXUnresolvedConstructExpr *
CXXUnresolvedConstructExpr::Create(ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceLocation RParenLoc) {
void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
- sizeof(Expr *) * NumArgs);
- return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc,
- Args, NumArgs, RParenLoc);
+ sizeof(Expr *) * Args.size());
+ return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, Args, RParenLoc);
}
CXXUnresolvedConstructExpr *
@@ -1300,6 +1315,34 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
return TemplateArgument(Arguments, NumArguments);
}
+FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
+ SourceLocation NameLoc,
+ unsigned NumParams,
+ Decl * const *Params)
+ : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary,
+ true, true, true, true),
+ ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) {
+ if (Params)
+ std::uninitialized_copy(Params, Params + NumParams,
+ reinterpret_cast<Decl**>(this+1));
+}
+
+FunctionParmPackExpr *
+FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
+ ParmVarDecl *ParamPack, SourceLocation NameLoc,
+ llvm::ArrayRef<Decl*> Params) {
+ return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
+ sizeof(ParmVarDecl*) * Params.size()))
+ FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
+}
+
+FunctionParmPackExpr *
+FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) {
+ return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
+ sizeof(ParmVarDecl*) * NumParams))
+ FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
+}
+
TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc,
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index f16d70b5da1b..24ec6bb02074 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// ObjC instance variables are lvalues
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
+ case Expr::FunctionParmPackExprClass:
return Cl::CL_LValue;
// C99 6.5.2.5p5 says that compound literals are lvalues.
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 06c41a2e7ea2..6e0b5fca60c0 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -953,7 +953,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
else
- Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+ Info.Note(Base.get<const Expr*>()->getExprLoc(),
diag::note_constexpr_temporary_here);
}
@@ -987,6 +987,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
+ // Check if this is a thread-local variable.
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
+ if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
+ if (Var->isThreadSpecified())
+ return false;
+ }
+ }
+
// Allow address constant expressions to be past-the-end pointers. This is
// an extension: the standard requires them to point to an object.
if (!IsReferenceType)
@@ -2586,7 +2594,7 @@ public:
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
- assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
SubobjectDesignator Designator(BaseTy);
@@ -2665,7 +2673,7 @@ public:
if (E->isArrow()) {
if (!EvaluatePointer(E->getBase(), Result, this->Info))
return false;
- BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
+ BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType();
} else if (E->getBase()->isRValue()) {
assert(E->getBase()->getType()->isRecordType());
if (!EvaluateTemporary(E->getBase(), Result, this->Info))
@@ -2878,19 +2886,13 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
}
bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
- if (E->isTypeOperand())
+ if (!E->isPotentiallyEvaluated())
return Success(E);
- CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl();
- // FIXME: The standard says "a typeid expression whose operand is of a
- // polymorphic class type" is not a constant expression, but it probably
- // means "a typeid expression whose operand is potentially evaluated".
- if (RD && RD->isPolymorphic()) {
- Info.Diag(E, diag::note_constexpr_typeid_polymorphic)
- << E->getExprOperand()->getType()
- << E->getExprOperand()->getSourceRange();
- return false;
- }
- return Success(E);
+
+ Info.Diag(E, diag::note_constexpr_typeid_polymorphic)
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
+ return false;
}
bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
@@ -3036,7 +3038,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() == BO_Sub)
AdditionalOffset = -AdditionalOffset;
- QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
+ QualType Pointee = PExp->getType()->castAs<PointerType>()->getPointeeType();
return HandleLValueArrayAdjustment(Info, E, Result, Pointee,
AdditionalOffset);
}
@@ -4288,6 +4290,16 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Error(E);
}
+ case Builtin::BI__builtin_bswap16:
+ case Builtin::BI__builtin_bswap32:
+ case Builtin::BI__builtin_bswap64: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.byteSwap(), E);
+ }
+
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
@@ -4902,7 +4914,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero())
return false;
const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
- const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
+ const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>();
if (!LHSExpr || !RHSExpr)
return false;
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
@@ -5176,7 +5188,7 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
QualType Ty = E->getTypeOfArgument();
if (Ty->isVectorType()) {
- unsigned n = Ty->getAs<VectorType>()->getNumElements();
+ unsigned n = Ty->castAs<VectorType>()->getNumElements();
// The vec_step built-in functions that take a 3-component
// vector return 4. (OpenCL 1.1 spec 6.11.12)
@@ -5349,6 +5361,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralRealToComplex:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -5753,7 +5766,7 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
}
bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {
- QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType ElemTy = E->getType()->castAs<ComplexType>()->getElementType();
if (ElemTy->isRealFloatingType()) {
Result.makeComplexFloat();
APFloat Zero = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(ElemTy));
@@ -5835,6 +5848,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -5911,9 +5925,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
return HandleIntToFloatCast(Info, E, From, Result.IntReal,
To, Result.FloatReal) &&
@@ -6177,11 +6191,9 @@ 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().CPlusPlus0x)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
- else
- Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
if (!EvaluateVoid(E, Info))
return false;
} else if (Info.getLangOpts().CPlusPlus0x) {
@@ -6470,6 +6482,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::OpaqueValueExprClass:
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::FunctionParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::MaterializeTemporaryExprClass:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 7c7a5e5de387..851944a42b6e 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -343,17 +343,10 @@ private:
void mangleCXXDtorType(CXXDtorType T);
void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs);
- void mangleTemplateArgs(TemplateName Template,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgument *TemplateArgs,
+ void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgumentList &AL);
- void mangleTemplateArg(const NamedDecl *P, TemplateArgument A);
- void mangleUnresolvedTemplateArgs(const TemplateArgument *args,
- unsigned numArgs);
+ void mangleTemplateArgs(const TemplateArgumentList &AL);
+ void mangleTemplateArg(TemplateArgument A);
void mangleTemplateParameter(unsigned Index);
@@ -570,8 +563,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleUnscopedTemplateName(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
return;
}
@@ -593,8 +585,7 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD,
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
} else {
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
}
@@ -693,9 +684,10 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
if (Value.isSigned() && Value.isNegative()) {
Out << 'n';
- Value.abs().print(Out, true);
- } else
- Value.print(Out, Value.isSigned());
+ Value.abs().print(Out, /*signed*/ false);
+ } else {
+ Value.print(Out, /*signed*/ false);
+ }
}
void CXXNameMangler::mangleNumber(int64_t Number) {
@@ -737,8 +729,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
- TST->getNumArgs());
+ mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
} else if (const DependentTemplateSpecializationType *DTST
@@ -751,7 +742,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
} else {
// We use the QualType mangle type variant here because it handles
// substitutions.
@@ -942,7 +933,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
}
}
- mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
break;
}
@@ -959,7 +950,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
const DependentTemplateSpecializationType *tst
= cast<DependentTemplateSpecializationType>(type);
mangleSourceName(tst->getIdentifier());
- mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
break;
}
}
@@ -1228,8 +1219,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
}
else {
manglePrefix(DC, NoFunction);
@@ -1246,8 +1236,7 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
Out << 'N';
mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
Out << 'E';
}
@@ -1341,11 +1330,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}
Out << "Ul";
- DeclarationName Name
- = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- const FunctionProtoType *Proto
- = cast<CXXMethodDecl>(*Lambda->lookup(Name).first)->getType()->
- getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
+ getAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
Out << "E";
@@ -1423,8 +1409,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
}
else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
return;
@@ -2110,6 +2095,7 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
// ::= Dv [<dimension expression>] _ <element type>
// <extended element type> ::= <element type>
// ::= p # AltiVec vector pixel
+// ::= b # Altivec vector bool
void CXXNameMangler::mangleType(const VectorType *T) {
if ((T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
@@ -2174,7 +2160,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getArgs(), T->getNumArgs());
addSubstitution(QualType(T, 0));
}
}
@@ -2200,7 +2186,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getArgs(), T->getNumArgs());
Out << 'E';
}
@@ -2414,7 +2400,6 @@ recurse:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
case Expr::CXXUuidofExprClass:
- case Expr::CXXNoexceptExprClass:
case Expr::CUDAKernelCallExprClass:
case Expr::AsTypeExprClass:
case Expr::PseudoObjectExprClass:
@@ -2606,6 +2591,11 @@ recurse:
Out <<"_E";
break;
+ case Expr::CXXNoexceptExprClass:
+ Out << "nx";
+ mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand());
+ break;
+
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
@@ -2808,7 +2798,15 @@ recurse:
// };
Out << "_SUBSTPACK_";
break;
-
+
+ case Expr::FunctionParmPackExprClass: {
+ // FIXME: not clear how to mangle this!
+ const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
+ Out << "v110_SUBSTPACK";
+ mangleFunctionParam(FPPE->getParameterPack());
+ break;
+ }
+
case Expr::DependentScopeDeclRefExprClass: {
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity);
@@ -3043,50 +3041,28 @@ void CXXNameMangler::mangleTemplateArgs(
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
- mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument());
- Out << 'E';
-}
-
-void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
- NumTemplateArgs);
-
- mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs);
-}
-
-void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args,
- unsigned numArgs) {
- // <template-args> ::= I <template-arg>+ E
- Out << 'I';
- for (unsigned i = 0; i != numArgs; ++i)
- mangleTemplateArg(0, args[i]);
+ mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument());
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgumentList &AL) {
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0, e = AL.size(); i != e; ++i)
- mangleTemplateArg(PL.getParam(i), AL[i]);
+ mangleTemplateArg(AL[i]);
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgument *TemplateArgs,
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(PL.getParam(i), TemplateArgs[i]);
+ mangleTemplateArg(TemplateArgs[i]);
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
- TemplateArgument A) {
+void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
@@ -3135,25 +3111,12 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
break;
case TemplateArgument::Declaration: {
- assert(P && "Missing template parameter for declaration argument");
// <expr-primary> ::= L <mangled-name> E # external name
- // <expr-primary> ::= L <type> 0 E
// Clang produces AST's where pointer-to-member-function expressions
// and pointer-to-function expressions are represented as a declaration not
// an expression. We compensate for it here to produce the correct mangling.
- const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
-
- // Handle NULL pointer arguments.
- if (!A.getAsDecl()) {
- Out << "L";
- mangleType(Parameter->getType());
- Out << "0E";
- break;
- }
-
-
- NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
- bool compensateMangling = !Parameter->getType()->isReferenceType();
+ ValueDecl *D = A.getAsDecl();
+ bool compensateMangling = !A.isDeclForReferenceParam();
if (compensateMangling) {
Out << 'X';
mangleOperatorName(OO_Amp, 1);
@@ -3176,14 +3139,20 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
break;
}
-
+ case TemplateArgument::NullPtr: {
+ // <expr-primary> ::= L <type> 0 E
+ Out << 'L';
+ mangleType(A.getNullPtrType());
+ Out << "0E";
+ break;
+ }
case TemplateArgument::Pack: {
// Note: proposal by Mike Herrick on 12/20/10
Out << 'J';
for (TemplateArgument::pack_iterator PA = A.pack_begin(),
PAEnd = A.pack_end();
PA != PAEnd; ++PA)
- mangleTemplateArg(P, *PA);
+ mangleTemplateArg(*PA);
Out << 'E';
}
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index e2cee7f52cfb..5d5b83d9a30b 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include <map>
@@ -56,7 +57,7 @@ public:
void mangleVariableEncoding(const VarDecl *VD);
void mangleNumber(int64_t Number);
void mangleNumber(const llvm::APSInt &Value);
- void mangleType(QualType T, SourceRange Range);
+ void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true);
private:
void disableBackReferences() { UseNameBackReferences = false; }
@@ -68,6 +69,7 @@ private:
void manglePostfix(const DeclContext *DC, bool NoFunction=false);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
+ void manglePointerQualifiers(Qualifiers Quals);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleTemplateInstantiationName(const TemplateDecl *TD,
@@ -75,7 +77,7 @@ private:
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleLocalName(const FunctionDecl *FD);
- void mangleTypeRepeated(QualType T, SourceRange Range);
+ void mangleArgumentType(QualType T, SourceRange Range);
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
@@ -95,6 +97,7 @@ private:
void mangleFunctionClass(const FunctionDecl *FD);
void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number);
+ void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
void mangleTemplateArgs(
@@ -266,18 +269,18 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
Out << '4';
// Now mangle the type.
// <variable-type> ::= <type> <cvr-qualifiers>
- // ::= <type> A # pointers, references, arrays
+ // ::= <type> <pointee-cvr-qualifiers> # pointers, references
// Pointers and references are odd. The type of 'int * const foo;' gets
// mangled as 'QAHA' instead of 'PAHB', for example.
TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
QualType Ty = TL.getType();
if (Ty->isPointerType() || Ty->isReferenceType()) {
mangleType(Ty, TL.getSourceRange());
- Out << 'A';
+ mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
} else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
// Global arrays are funny, too.
mangleType(AT, true);
- Out << 'A';
+ mangleQualifiers(Ty.getQualifiers(), false);
} else {
mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange());
mangleQualifiers(Ty.getLocalQualifiers(), false);
@@ -304,39 +307,23 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
}
void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
- // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
- // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
- // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
- if (Number < 0) {
- Out << '?';
- Number = -Number;
- }
- // There's a special shorter mangling for 0, but Microsoft
- // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
- if (Number >= 1 && Number <= 10)
- Out << Number-1;
- else {
- // We have to build up the encoding in reverse order, so it will come
- // out right when we write it out.
- char Encoding[16];
- char *EndPtr = Encoding+sizeof(Encoding);
- char *CurPtr = EndPtr;
- do {
- *--CurPtr = 'A' + (Number % 16);
- Number /= 16;
- } while (Number);
- Out.write(CurPtr, EndPtr-CurPtr);
- Out << '@';
- }
+ llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false);
+ APSNumber = Number;
+ mangleNumber(APSNumber);
}
void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
+ // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
+ // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
+ // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
if (Value.isSigned() && Value.isNegative()) {
Out << '?';
mangleNumber(llvm::APSInt(Value.abs()));
return;
}
llvm::APSInt Temp(Value);
+ // There's a special shorter mangling for 0, but Microsoft
+ // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
if (Value.uge(1) && Value.ule(10)) {
--Temp;
Temp.print(Out, false);
@@ -348,10 +335,10 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
char *CurPtr = EndPtr;
llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned());
NibbleMask = 0xf;
- for (int i = 0, e = Value.getActiveBits() / 4; i != e; ++i) {
+ do {
*--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf);
Temp = Temp.lshr(4);
- }
+ } while (Temp != 0);
Out.write(CurPtr, EndPtr-CurPtr);
Out << '@';
}
@@ -386,7 +373,7 @@ isTemplate(const NamedDecl *ND,
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
TypeSourceInfo *TSI = Spec->getTypeAsWritten();
if (TSI) {
- TemplateSpecializationTypeLoc &TSTL =
+ TemplateSpecializationTypeLoc TSTL =
cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
@@ -784,6 +771,23 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T,
}
void
+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);
+ return;
+ }
+
+ // As bad as this diagnostic is, it's better than crashing.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+}
+
+void
MicrosoftCXXNameMangler::mangleTemplateArgs(
const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
// <template-args> ::= {<type> | <integer-literal>}+ @
@@ -800,21 +804,19 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(
case TemplateArgument::Integral:
mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
break;
- case TemplateArgument::Expression: {
- // See if this is a constant expression.
- Expr *TAE = TA.getAsExpr();
- llvm::APSInt Value;
- if (TAE->isIntegerConstantExpr(Value, Context.getASTContext())) {
- mangleIntegerLiteral(TAE->getType(), Value);
- break;
- }
- /* fallthrough */
- } default: {
+ 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|ERROR|"
- "template|template pack expansion|expression|parameter pack}0 "
+ "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)
<< TA.getKind()
@@ -879,43 +881,60 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
// ::= 3 # ?
// ::= 4 # ?
// ::= 5 # not really based
+ bool HasConst = Quals.hasConst(),
+ HasVolatile = Quals.hasVolatile();
if (!IsMember) {
- if (!Quals.hasVolatile()) {
- if (!Quals.hasConst())
- Out << 'A';
- else
- Out << 'B';
+ if (HasConst && HasVolatile) {
+ Out << 'D';
+ } else if (HasVolatile) {
+ Out << 'C';
+ } else if (HasConst) {
+ Out << 'B';
} else {
- if (!Quals.hasConst())
- Out << 'C';
- else
- Out << 'D';
+ Out << 'A';
}
} else {
- if (!Quals.hasVolatile()) {
- if (!Quals.hasConst())
- Out << 'Q';
- else
- Out << 'R';
+ if (HasConst && HasVolatile) {
+ Out << 'T';
+ } else if (HasVolatile) {
+ Out << 'S';
+ } else if (HasConst) {
+ Out << 'R';
} else {
- if (!Quals.hasConst())
- Out << 'S';
- else
- Out << 'T';
+ Out << 'Q';
}
}
// FIXME: For now, just drop all extension qualifiers on the floor.
}
-void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range) {
+void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
+ // <pointer-cvr-qualifiers> ::= P # no qualifiers
+ // ::= Q # const
+ // ::= R # volatile
+ // ::= S # const volatile
+ bool HasConst = Quals.hasConst(),
+ HasVolatile = Quals.hasVolatile();
+ if (HasConst && HasVolatile) {
+ Out << 'S';
+ } else if (HasVolatile) {
+ Out << 'R';
+ } else if (HasConst) {
+ Out << 'Q';
+ } else {
+ Out << 'P';
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
+ SourceRange Range) {
void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
if (Found == TypeBackReferences.end()) {
size_t OutSizeBefore = Out.GetNumBytesInBuffer();
- mangleType(T,Range);
+ mangleType(T, Range, false);
// See if it's worth creating a back reference.
// Only types longer than 1 character are considered
@@ -930,38 +949,30 @@ void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range)
}
}
-void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) {
+void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
+ bool MangleQualifiers) {
// Only operate on the canonical type!
T = getASTContext().getCanonicalType(T);
-
+
Qualifiers Quals = T.getLocalQualifiers();
- if (Quals) {
- // We have to mangle these now, while we still have enough information.
- // <pointer-cvr-qualifiers> ::= P # pointer
- // ::= Q # const pointer
- // ::= R # volatile pointer
- // ::= S # const volatile pointer
- if (T->isAnyPointerType() || T->isMemberPointerType() ||
- T->isBlockPointerType()) {
- if (!Quals.hasVolatile())
- Out << 'Q';
- else {
- if (!Quals.hasConst())
- Out << 'R';
- else
- Out << 'S';
- }
- } else
- // Just emit qualifiers like normal.
- // NB: When we mangle a pointer/reference type, and the pointee
- // type has no qualifiers, the lack of qualifier gets mangled
- // in there.
- mangleQualifiers(Quals, false);
- } else if (T->isAnyPointerType() || T->isMemberPointerType() ||
- T->isBlockPointerType()) {
- Out << 'P';
+ // We have to mangle these now, while we still have enough information.
+ if (T->isAnyPointerType() || T->isMemberPointerType() ||
+ T->isBlockPointerType()) {
+ manglePointerQualifiers(Quals);
+ } else if (Quals && MangleQualifiers) {
+ mangleQualifiers(Quals, false);
}
- switch (T->getTypeClass()) {
+
+ SplitQualType split = T.split();
+ const Type *ty = split.Ty;
+
+ // If we're mangling a qualified array type, push the qualifiers to
+ // the element type.
+ if (split.Quals && isa<ArrayType>(T)) {
+ ty = Context.getASTContext().getAsArrayType(T);
+ }
+
+ switch (ty->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT) \
case Type::CLASS: \
@@ -969,7 +980,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) {
return;
#define TYPE(CLASS, PARENT) \
case Type::CLASS: \
- mangleType(static_cast<const CLASS##Type*>(T.getTypePtr()), Range); \
+ mangleType(cast<CLASS##Type>(ty), Range); \
break;
#include "clang/AST/TypeNodes.def"
#undef ABSTRACT_TYPE
@@ -1059,6 +1070,8 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
SourceRange) {
// Structors only appear in decls, so at this point we know it's not a
// structor type.
+ // FIXME: This may not be lambda-friendly.
+ Out << "$$A6";
mangleType(T, NULL, false, false);
}
void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
@@ -1117,14 +1130,14 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
- mangleTypeRepeated(Type, (*Parm)->getSourceRange());
+ mangleArgumentType(Type, (*Parm)->getSourceRange());
}
} else {
// Happens for function pointer type arguments for example.
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
ArgEnd = Proto->arg_type_end();
Arg != ArgEnd; ++Arg)
- mangleTypeRepeated(*Arg, SourceRange());
+ mangleArgumentType(*Arg, SourceRange());
}
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
@@ -1214,7 +1227,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
if (CC == CC_Default) {
if (IsInstMethod) {
const FunctionProtoType *FPT =
- T->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
+ T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
bool isVariadic = FPT->isVariadic();
CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
} else {
@@ -1260,10 +1273,10 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
// <class-type> ::= V <name>
// <enum-type> ::= W <size> <name>
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
- mangleType(static_cast<const TagType*>(T));
+ mangleType(cast<TagType>(T));
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) {
- mangleType(static_cast<const TagType*>(T));
+ mangleType(cast<TagType>(T));
}
void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
switch (T->getDecl()->getTagKind()) {
@@ -1271,6 +1284,7 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
Out << 'T';
break;
case TTK_Struct:
+ case TTK_Interface:
Out << 'U';
break;
case TTK_Class:
@@ -1286,37 +1300,39 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
}
// <type> ::= <array-type>
-// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+]
-// <element-type> # as global
+// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
+// [Y <dimension-count> <dimension>+]
+// <element-type> # as global
// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+]
-// <element-type> # as param
+// <element-type> # as param
// It's supposed to be the other way around, but for some strange reason, it
// isn't. Today this behavior is retained for the sole purpose of backwards
// compatibility.
void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) {
// This isn't a recursive mangling, so now we have to do it all in this
// one call.
- if (IsGlobal)
- Out << 'P';
- else
+ if (IsGlobal) {
+ manglePointerQualifiers(T->getElementType().getQualifiers());
+ } else {
Out << 'Q';
+ }
mangleExtraDimensions(T->getElementType());
}
void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
SmallVector<llvm::APInt, 3> Dimensions;
@@ -1409,10 +1425,8 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
Out << '6';
mangleType(FT, NULL, false, false);
} else {
- if (!PointeeTy.hasQualifiers())
- // Lack of qualifiers is mangled as 'A'.
- Out << 'A';
- mangleType(PointeeTy, Range);
+ mangleQualifiers(PointeeTy.getQualifiers(), false);
+ mangleType(PointeeTy, Range, false);
}
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
@@ -1497,7 +1511,9 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
SourceRange Range) {
Out << "_E";
- mangleType(T->getPointeeType(), Range);
+
+ QualType pointee = T->getPointeeType();
+ mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false);
}
void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T,
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 39077d1766e8..0837509194bc 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::ARCUnbridgedCast:
case BuiltinType::Half:
case BuiltinType::PseudoObject:
+ case BuiltinType::BuiltinFn:
break;
}
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index fa87afd0fa22..113592860b77 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -20,22 +20,63 @@ using namespace clang;
typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;
-static void BuildParentMap(MapTy& M, Stmt* S) {
- for (Stmt::child_range I = S->children(); I; ++I)
- if (*I) {
- // Prefer the first time we see this statement in the traversal.
- // This is important for PseudoObjectExprs.
- Stmt *&Parent = M[*I];
- if (!Parent) {
- Parent = S;
- BuildParentMap(M, *I);
+enum OpaqueValueMode {
+ OV_Transparent,
+ OV_Opaque
+};
+
+static void BuildParentMap(MapTy& M, Stmt* S,
+ OpaqueValueMode OVMode = OV_Transparent) {
+
+ switch (S->getStmtClass()) {
+ case Stmt::PseudoObjectExprClass: {
+ assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
+ PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
+
+ M[POE->getSyntacticForm()] = S;
+ BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
+
+ for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(),
+ E = POE->semantics_end();
+ I != E; ++I) {
+ M[*I] = S;
+ BuildParentMap(M, *I, OV_Opaque);
+ }
+ break;
+ }
+ case Stmt::BinaryConditionalOperatorClass: {
+ assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
+ BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S);
+
+ M[BCO->getCommon()] = S;
+ BuildParentMap(M, BCO->getCommon(), OV_Transparent);
+
+ M[BCO->getCond()] = S;
+ BuildParentMap(M, BCO->getCond(), OV_Opaque);
+
+ M[BCO->getTrueExpr()] = S;
+ BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque);
+
+ M[BCO->getFalseExpr()] = S;
+ BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent);
+
+ break;
+ }
+ case Stmt::OpaqueValueExprClass:
+ if (OVMode == OV_Transparent) {
+ OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
+ M[OVE->getSourceExpr()] = S;
+ BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);
+ }
+ break;
+ default:
+ for (Stmt::child_range I = S->children(); I; ++I) {
+ if (*I) {
+ M[*I] = S;
+ BuildParentMap(M, *I, OVMode);
}
}
-
- // Also include the source expr tree of an OpaqueValueExpr in the map.
- if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) {
- M[OVE->getSourceExpr()] = S;
- BuildParentMap(M, OVE->getSourceExpr());
+ break;
}
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index a5a32870577a..80b627293e42 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -143,11 +143,10 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const {
// a separate allocator for all temporary stuff.
llvm::BumpPtrAllocator Allocator;
- comments::CommandTraits Traits;
- comments::Lexer L(Allocator, Traits,
- Range.getBegin(), comments::CommentOptions(),
+ comments::Lexer L(Allocator, Context.getCommentCommandTraits(),
+ Range.getBegin(),
RawText.begin(), RawText.end());
- comments::BriefParser P(L, Traits);
+ comments::BriefParser P(L, Context.getCommentCommandTraits());
const std::string Result = P.Parse();
const unsigned BriefTextLength = Result.size();
@@ -160,19 +159,22 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const {
}
comments::FullComment *RawComment::parse(const ASTContext &Context,
+ const Preprocessor *PP,
const Decl *D) const {
// Make sure that RawText is valid.
getRawText(Context.getSourceManager());
- comments::CommandTraits Traits;
- comments::Lexer L(Context.getAllocator(), Traits,
- getSourceRange().getBegin(), comments::CommentOptions(),
+ comments::Lexer L(Context.getAllocator(), Context.getCommentCommandTraits(),
+ getSourceRange().getBegin(),
RawText.begin(), RawText.end());
comments::Sema S(Context.getAllocator(), Context.getSourceManager(),
- Context.getDiagnostics(), Traits);
+ Context.getDiagnostics(),
+ Context.getCommentCommandTraits(),
+ PP);
S.setDecl(D);
comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(),
- Context.getDiagnostics(), Traits);
+ Context.getDiagnostics(),
+ Context.getCommentCommandTraits());
return P.parseFullComment();
}
@@ -182,26 +184,22 @@ bool containsOnlyWhitespace(StringRef Str) {
return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos;
}
-bool onlyWhitespaceBetweenComments(SourceManager &SM,
- const RawComment &C1, const RawComment &C2) {
- std::pair<FileID, unsigned> C1EndLocInfo = SM.getDecomposedLoc(
- C1.getSourceRange().getEnd());
- std::pair<FileID, unsigned> C2BeginLocInfo = SM.getDecomposedLoc(
- C2.getSourceRange().getBegin());
+bool onlyWhitespaceBetween(SourceManager &SM,
+ SourceLocation Loc1, SourceLocation Loc2) {
+ std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1);
+ std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2);
- // Question does not make sense if comments are located in different files.
- if (C1EndLocInfo.first != C2BeginLocInfo.first)
+ // Question does not make sense if locations are in different files.
+ if (Loc1Info.first != Loc2Info.first)
return false;
bool Invalid = false;
- const char *Buffer = SM.getBufferData(C1EndLocInfo.first, &Invalid).data();
+ const char *Buffer = SM.getBufferData(Loc1Info.first, &Invalid).data();
if (Invalid)
return false;
- StringRef TextBetweenComments(Buffer + C1EndLocInfo.second,
- C2BeginLocInfo.second - C1EndLocInfo.second);
-
- return containsOnlyWhitespace(TextBetweenComments);
+ StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second);
+ return containsOnlyWhitespace(Text);
}
} // unnamed namespace
@@ -221,11 +219,13 @@ void RawCommentList::addComment(const RawComment &RC,
}
if (OnlyWhitespaceSeen) {
- if (!onlyWhitespaceBetweenComments(SourceMgr, LastComment, RC))
+ if (!onlyWhitespaceBetween(SourceMgr,
+ PrevCommentEndLoc,
+ RC.getSourceRange().getBegin()))
OnlyWhitespaceSeen = false;
}
- LastComment = RC;
+ PrevCommentEndLoc = RC.getSourceRange().getEnd();
// Ordinary comments are not interesting for us.
if (RC.isOrdinary())
@@ -244,15 +244,20 @@ void RawCommentList::addComment(const RawComment &RC,
// Merge comments only if there is only whitespace between them.
// Can't merge trailing and non-trailing comments.
- // Merge trailing comments if they are on same or consecutive lines.
+ // Merge comments if they are on same or consecutive lines.
+ bool Merged = false;
if (OnlyWhitespaceSeen &&
- (C1.isTrailingComment() == C2.isTrailingComment()) &&
- (!C1.isTrailingComment() ||
- C1.getEndLine(SourceMgr) + 1 >= C2.getBeginLine(SourceMgr))) {
- SourceRange MergedRange(C1.getSourceRange().getBegin(),
- C2.getSourceRange().getEnd());
- *Comments.back() = RawComment(SourceMgr, MergedRange, true);
- } else
+ (C1.isTrailingComment() == C2.isTrailingComment())) {
+ unsigned C1EndLine = C1.getEndLine(SourceMgr);
+ unsigned C2BeginLine = C2.getBeginLine(SourceMgr);
+ if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) {
+ SourceRange MergedRange(C1.getSourceRange().getBegin(),
+ C2.getSourceRange().getEnd());
+ *Comments.back() = RawComment(SourceMgr, MergedRange, true);
+ Merged = true;
+ }
+ }
+ if (!Merged)
Comments.push_back(new (Allocator) RawComment(RC));
OnlyWhitespaceSeen = true;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index d5df63f7d151..4dfffc45e49c 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -789,8 +789,8 @@ protected:
void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
- RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
- void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
+ RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
+ void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
public:
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
@@ -1557,6 +1557,13 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset);
(void)Allowed;
assert(Allowed && "Base subobject externally placed at overlapping offset");
+
+ if (InferAlignment && Offset < getDataSize().RoundUpToAlignment(BaseAlign)){
+ // The externally-supplied base offset is before the base offset we
+ // computed. Assume that the structure is packed.
+ Alignment = CharUnits::One();
+ InferAlignment = false;
+ }
}
if (!Base->Class->isEmpty()) {
@@ -1574,12 +1581,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
IsUnion = RD->isUnion();
+ IsMsStruct = RD->isMsStruct(Context);
+ }
- Packed = D->hasAttr<PackedAttr>();
-
- IsMsStruct = D->hasAttr<MsStructAttr>();
+ Packed = D->hasAttr<PackedAttr>();
// Honor the default struct packing maximum alignment flag.
if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
@@ -1616,7 +1623,6 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
if (ExternalLayout) {
if (ExternalAlign > 0) {
Alignment = Context.toCharUnitsFromBits(ExternalAlign);
- UnpackedAlignment = Alignment;
} else {
// The external source didn't have alignment information; infer it.
InferAlignment = true;
@@ -2085,7 +2091,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
ZeroLengthBitfield = 0;
}
- if (Context.getLangOpts().MSBitfields || IsMsStruct) {
+ if (IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -2166,11 +2172,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
}
void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
- if (ExternalLayout) {
- setSize(ExternalSize);
- return;
- }
-
// In C++, records cannot be of size 0.
if (Context.getLangOpts().CPlusPlus && getSizeInBits() == 0) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
@@ -2184,20 +2185,37 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
setSize(CharUnits::One());
}
+ // Finally, round the size of the record up to the alignment of the
+ // record itself.
+ uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpackedSizeInBits =
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.toBits(UnpackedAlignment));
+ CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
+ uint64_t RoundedSize
+ = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment));
+
+ if (ExternalLayout) {
+ // If we're inferring alignment, and the external size is smaller than
+ // our size after we've rounded up to alignment, conservatively set the
+ // alignment to 1.
+ if (InferAlignment && ExternalSize < RoundedSize) {
+ Alignment = CharUnits::One();
+ InferAlignment = false;
+ }
+ setSize(ExternalSize);
+ return;
+ }
+
+
// MSVC doesn't round up to the alignment of the record with virtual bases.
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (isMicrosoftCXXABI() && RD->getNumVBases())
return;
}
- // Finally, round the size of the record up to the alignment of the
- // record itself.
- uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
- uint64_t UnpackedSizeInBits =
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.toBits(UnpackedAlignment));
- CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
- setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
+ // Set the size to the final size.
+ setSize(RoundedSize);
unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
@@ -2255,7 +2273,7 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
if (InferAlignment && ExternalFieldOffset < ComputedOffset) {
// The externally-supplied field offset is before the field offset we
// computed. Assume that the structure is packed.
- Alignment = CharUnits::fromQuantity(1);
+ Alignment = CharUnits::One();
InferAlignment = false;
}
@@ -2263,6 +2281,20 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
return ExternalFieldOffset;
}
+/// \brief Get diagnostic %select index for tag kind for
+/// field padding diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for field padding diagnostic!");
+ }
+}
+
void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
uint64_t UnpaddedOffset,
uint64_t UnpackedOffset,
@@ -2291,14 +2323,14 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
}
if (D->getIdentifier())
Diag(D->getLocation(), diag::warn_padded_struct_field)
- << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << getPaddingDiagFromTagKind(D->getParent()->getTagKind())
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not
<< D->getIdentifier();
else
Diag(D->getLocation(), diag::warn_padded_struct_anon_field)
- << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << getPaddingDiagFromTagKind(D->getParent()->getTagKind())
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
@@ -2508,8 +2540,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have.
- ObjCContainerDecl *Key =
- Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
+ const ObjCContainerDecl *Key =
+ Impl ? (const ObjCContainerDecl*) Impl : (const ObjCContainerDecl*) D;
if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
return *Entry;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 77452c9d9d1c..eafcf92eee82 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -320,15 +321,52 @@ bool Stmt::hasImplicitControlFlow() const {
}
}
-Expr *AsmStmt::getOutputExpr(unsigned i) {
- return cast<Expr>(Exprs[i]);
+std::string AsmStmt::generateAsmString(ASTContext &C) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->generateAsmString(C);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->generateAsmString(C);
+ llvm_unreachable("unknown asm statement kind!");
}
-/// getOutputConstraint - Return the constraint string for the specified
-/// output operand. All output constraints are known to be non-empty (either
-/// '=' or '+').
StringRef AsmStmt::getOutputConstraint(unsigned i) const {
- return getOutputConstraintLiteral(i)->getString();
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getOutputConstraint(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getOutputConstraint(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+const Expr *AsmStmt::getOutputExpr(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getOutputExpr(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getOutputExpr(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+StringRef AsmStmt::getInputConstraint(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getInputConstraint(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getInputConstraint(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+const Expr *AsmStmt::getInputExpr(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getInputExpr(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getInputExpr(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+StringRef AsmStmt::getClobber(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getClobber(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getClobber(i);
+ llvm_unreachable("unknown asm statement kind!");
}
/// getNumPlusOperands - Return the number of output operands that have a "+"
@@ -341,22 +379,35 @@ unsigned AsmStmt::getNumPlusOperands() const {
return Res;
}
-Expr *AsmStmt::getInputExpr(unsigned i) {
+StringRef GCCAsmStmt::getClobber(unsigned i) const {
+ return getClobberStringLiteral(i)->getString();
+}
+
+Expr *GCCAsmStmt::getOutputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i]);
+}
+
+/// getOutputConstraint - Return the constraint string for the specified
+/// output operand. All output constraints are known to be non-empty (either
+/// '=' or '+').
+StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const {
+ return getOutputConstraintLiteral(i)->getString();
+}
+
+Expr *GCCAsmStmt::getInputExpr(unsigned i) {
return cast<Expr>(Exprs[i + NumOutputs]);
}
-void AsmStmt::setInputExpr(unsigned i, Expr *E) {
+void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
Exprs[i + NumOutputs] = E;
}
-
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
-StringRef AsmStmt::getInputConstraint(unsigned i) const {
+StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
return getInputConstraintLiteral(i)->getString();
}
-
-void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
+void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
IdentifierInfo **Names,
StringLiteral **Constraints,
Stmt **Exprs,
@@ -390,7 +441,7 @@ void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
-int AsmStmt::getNamedOperand(StringRef SymbolicName) const {
+int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
unsigned NumPlusOperands = 0;
// Check if this is an output operand.
@@ -410,7 +461,7 @@ int AsmStmt::getNamedOperand(StringRef SymbolicName) const {
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
-unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
+unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
ASTContext &C, unsigned &DiagOffs) const {
StringRef Str = getAsmString()->getString();
const char *StrStart = Str.begin();
@@ -548,6 +599,44 @@ unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
}
}
+/// Assemble final IR asm string (GCC-style).
+std::string GCCAsmStmt::generateAsmString(ASTContext &C) const {
+ // Analyze the asm string to decompose it into its pieces. We know that Sema
+ // has already done this, so it is guaranteed to be successful.
+ SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces;
+ unsigned DiagOffs;
+ AnalyzeAsmString(Pieces, C, DiagOffs);
+
+ std::string AsmString;
+ for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
+ if (Pieces[i].isString())
+ AsmString += Pieces[i].getString();
+ else if (Pieces[i].getModifier() == '\0')
+ AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo());
+ else
+ AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' +
+ Pieces[i].getModifier() + '}';
+ }
+ return AsmString;
+}
+
+/// Assemble final IR asm string (MS-style).
+std::string MSAsmStmt::generateAsmString(ASTContext &C) const {
+ // FIXME: This needs to be translated into the IR string representation.
+ return AsmStr;
+}
+
+Expr *MSAsmStmt::getOutputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i]);
+}
+
+Expr *MSAsmStmt::getInputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i + NumOutputs]);
+}
+void MSAsmStmt::setInputExpr(unsigned i, Expr *E) {
+ Exprs[i + NumOutputs] = E;
+}
+
QualType CXXCatchStmt::getCaughtType() const {
if (ExceptionDecl)
return ExceptionDecl->getType();
@@ -558,15 +647,14 @@ QualType CXXCatchStmt::getCaughtType() const {
// Constructors
//===----------------------------------------------------------------------===//
-AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
- bool isvolatile, bool msasm,
- unsigned numoutputs, unsigned numinputs,
- IdentifierInfo **names, StringLiteral **constraints,
- Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, SourceLocation rparenloc)
- : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
- , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
- , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {
+GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
+ bool isvolatile, unsigned numoutputs, unsigned numinputs,
+ IdentifierInfo **names, StringLiteral **constraints,
+ Expr **exprs, StringLiteral *asmstr,
+ unsigned numclobbers, StringLiteral **clobbers,
+ SourceLocation rparenloc)
+ : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
+ numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
unsigned NumExprs = NumOutputs + NumInputs;
@@ -585,26 +673,37 @@ AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
SourceLocation lbraceloc, bool issimple, bool isvolatile,
- ArrayRef<Token> asmtoks, ArrayRef<IdentifierInfo*> inputs,
- ArrayRef<IdentifierInfo*> outputs, StringRef asmstr,
- ArrayRef<StringRef> clobbers, SourceLocation endloc)
- : Stmt(MSAsmStmtClass), AsmLoc(asmloc), LBraceLoc(lbraceloc), EndLoc(endloc),
- AsmStr(asmstr.str()), IsSimple(issimple), IsVolatile(isvolatile),
- NumAsmToks(asmtoks.size()), NumInputs(inputs.size()),
- NumOutputs(outputs.size()), NumClobbers(clobbers.size()) {
+ ArrayRef<Token> asmtoks, unsigned numoutputs,
+ unsigned numinputs, ArrayRef<IdentifierInfo*> names,
+ ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs,
+ StringRef asmstr, ArrayRef<StringRef> clobbers,
+ SourceLocation endloc)
+ : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
+ numinputs, clobbers.size()), LBraceLoc(lbraceloc),
+ EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) {
unsigned NumExprs = NumOutputs + NumInputs;
Names = new (C) IdentifierInfo*[NumExprs];
- for (unsigned i = 0, e = NumOutputs; i != e; ++i)
- Names[i] = outputs[i];
- for (unsigned i = NumOutputs, e = NumExprs; i != e; ++i)
- Names[i] = inputs[i];
+ for (unsigned i = 0, e = NumExprs; i != e; ++i)
+ Names[i] = names[i];
+
+ Exprs = new (C) Stmt*[NumExprs];
+ for (unsigned i = 0, e = NumExprs; i != e; ++i)
+ Exprs[i] = exprs[i];
AsmToks = new (C) Token[NumAsmToks];
for (unsigned i = 0, e = NumAsmToks; i != e; ++i)
AsmToks[i] = asmtoks[i];
+ Constraints = new (C) StringRef[NumExprs];
+ for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+ size_t size = constraints[i].size();
+ char *dest = new (C) char[size];
+ std::strncpy(dest, constraints[i].data(), size);
+ Constraints[i] = StringRef(dest, size);
+ }
+
Clobbers = new (C) StringRef[NumClobbers];
for (unsigned i = 0, e = NumClobbers; i != e; ++i) {
// FIXME: Avoid the allocation/copy if at all possible.
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 962e35269c18..fbc990f6b3c2 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Stmt::dump/Stmt::print methods, which dump out the
+// This file implements the Stmt::dump method, which dumps out the
// AST in a form that exposes type details and other fields.
//
//===----------------------------------------------------------------------===//
@@ -30,6 +30,7 @@ namespace {
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
@@ -41,46 +42,64 @@ namespace {
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-1), MaxDepth(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;
- ++IndentLevel;
- if (S) {
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
- VisitDeclStmt(DS);
- else {
- Visit(S);
-
- // Print out children.
- Stmt::child_range CI = S->children();
- if (CI) {
- while (CI) {
- OS << '\n';
- DumpSubTree(*CI++);
- }
- }
- }
- OS << ')';
- } else {
- Indent();
+ IndentScope Indent(*this);
+
+ if (!S) {
OS << "<<<NULL>>>";
+ return;
+ }
+
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ return;
}
- --IndentLevel;
+
+ Visit(S);
+ for (Stmt::child_range CI = S->children(); CI; CI++)
+ DumpSubTree(*CI);
}
void DumpDeclarator(Decl *D);
- void Indent() const {
- for (int i = 0, e = IndentLevel; i < e; ++i)
- OS << " ";
+ void indent() {
+ if (IsFirstLine)
+ IsFirstLine = false;
+ else
+ OS << "\n";
+ OS.indent(IndentLevel * 2);
+ OS << "(";
+ IndentLevel++;
+ }
+
+ void unindent() {
+ OS << ")";
+ IndentLevel--;
}
void DumpType(QualType T) {
@@ -96,9 +115,8 @@ namespace {
}
void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
- Indent();
- OS << "(" << Node->getStmtClassName()
- << " " << (void*)Node;
+ OS << Node->getStmtClassName()
+ << " " << (const void*)Node;
DumpSourceRange(Node);
}
void DumpValueKind(ExprValueKind K) {
@@ -262,7 +280,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// If this is a vardecl with an initializer, emit it.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getInit()) {
- OS << " =\n";
+ OS << " =";
DumpSubTree(V->getInit());
}
}
@@ -294,9 +312,9 @@ void StmtDumper::DumpDeclarator(Decl *D) {
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
OS << "label " << *LD;
} else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
- OS << "\"static_assert(\n";
+ OS << "\"static_assert(";
DumpSubTree(SAD->getAssertExpr());
- OS << ",\n";
+ OS << ",";
DumpSubTree(SAD->getMessage());
OS << ");\"";
} else {
@@ -306,17 +324,12 @@ void StmtDumper::DumpDeclarator(Decl *D) {
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
DumpStmt(Node);
- OS << "\n";
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
DI != DE; ++DI) {
+ IndentScope Indent(*this);
Decl* D = *DI;
- ++IndentLevel;
- Indent();
OS << (void*) D << " ";
DumpDeclarator(D);
- if (DI+1 != DE)
- OS << "\n";
- --IndentLevel;
}
}
@@ -503,35 +516,29 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *block = Node->getBlockDecl();
OS << " decl=" << block;
- IndentLevel++;
if (block->capturesCXXThis()) {
- OS << '\n'; Indent(); OS << "(capture this)";
+ IndentScope Indent(*this);
+ OS << "capture this";
}
for (BlockDecl::capture_iterator
i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
- OS << '\n';
- Indent();
- OS << "(capture ";
+ 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());
- OS << ")";
}
- IndentLevel--;
- OS << '\n';
DumpSubTree(block->getBody());
}
void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
DumpExpr(Node);
- if (Expr *Source = Node->getSourceExpr()) {
- OS << '\n';
+ if (Expr *Source = Node->getSourceExpr())
DumpSubTree(Source);
- }
}
// GNU extensions.
@@ -589,15 +596,11 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
- ++IndentLevel;
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
- OS << "\n";
- Indent();
- OS << "(cleanup ";
+ IndentScope Indent(*this);
+ OS << "cleanup ";
DumpDeclRef(Node->getObject(i));
- OS << ")";
}
- --IndentLevel;
}
void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
@@ -734,7 +737,6 @@ void Stmt::dump(SourceManager &SM) const {
void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
StmtDumper P(&SM, OS, 4);
P.DumpSubTree(const_cast<Stmt*>(this));
- OS << "\n";
}
/// dump - This does a local dump of the specified AST fragment. It dumps the
@@ -743,19 +745,16 @@ void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
void Stmt::dump() const {
StmtDumper P(0, llvm::errs(), 4);
P.DumpSubTree(const_cast<Stmt*>(this));
- llvm::errs() << "\n";
}
/// 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));
- llvm::errs() << "\n";
}
/// 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));
- llvm::errs() << "\n";
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index c0960ce6a244..57eb1a95181c 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -61,7 +61,7 @@ namespace {
void PrintRawCompoundStmt(CompoundStmt *S);
void PrintRawDecl(Decl *D);
- void PrintRawDeclStmt(DeclStmt *S);
+ void PrintRawDeclStmt(const DeclStmt *S);
void PrintRawIfStmt(IfStmt *If);
void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
void PrintCallArgs(CallExpr *E);
@@ -121,8 +121,8 @@ void StmtPrinter::PrintRawDecl(Decl *D) {
D->print(OS, Policy, IndentLevel);
}
-void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
- DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
+void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) {
+ DeclStmt::const_decl_iterator Begin = S->decl_begin(), End = S->decl_end();
SmallVector<Decl*, 2> Decls;
for ( ; Begin != End; ++Begin)
Decls.push_back(*Begin);
@@ -187,7 +187,10 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
OS << "if (";
- PrintExpr(If->getCond());
+ if (const DeclStmt *DS = If->getConditionVariableDeclStmt())
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(If->getCond());
OS << ')';
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
@@ -224,7 +227,10 @@ void StmtPrinter::VisitIfStmt(IfStmt *If) {
void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
Indent() << "switch (";
- PrintExpr(Node->getCond());
+ if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(Node->getCond());
OS << ")";
// Pretty print compoundstmt bodies (very common).
@@ -240,7 +246,10 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
Indent() << "while (";
- PrintExpr(Node->getCond());
+ if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(Node->getCond());
OS << ")\n";
PrintStmt(Node->getBody());
}
@@ -366,7 +375,7 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
}
-void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
+void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
Indent() << "asm ";
if (Node->isVolatile())
@@ -422,7 +431,7 @@ void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
if (i != 0)
OS << ", ";
- VisitStringLiteral(Node->getClobber(i));
+ VisitStringLiteral(Node->getClobberStringLiteral(i));
}
OS << ");\n";
@@ -734,10 +743,30 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
case BuiltinType::UInt128: OS << "Ui128"; break;
}
}
-void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
+
+static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
+ bool PrintSuffix) {
SmallString<16> Str;
Node->getValue().toString(Str);
OS << Str;
+ if (Str.find_first_not_of("-0123456789") == StringRef::npos)
+ OS << '.'; // Trailing dot in order to separate from ints.
+
+ if (!PrintSuffix)
+ return;
+
+ // Emit suffixes. Float literals are always a builtin float type.
+ switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ default: llvm_unreachable("Unexpected type for float literal!");
+ case BuiltinType::Half: break; // FIXME: suffix?
+ case BuiltinType::Double: break; // no suffix.
+ case BuiltinType::Float: OS << 'F'; break;
+ case BuiltinType::LongDouble: OS << 'L'; break;
+ }
+}
+
+void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
+ PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true);
}
void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
@@ -907,7 +936,7 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
OS << Node->getAccessor().getName();
}
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
- OS << "(" << Node->getType().getAsString(Policy) << ")";
+ OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")";
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
@@ -1110,6 +1139,8 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
PrintExpr(Node->getArg(0));
OS << ' ' << OpStrings[Kind];
}
+ } else if (Kind == OO_Arrow) {
+ PrintExpr(Node->getArg(0));
} else if (Kind == OO_Call) {
PrintExpr(Node->getArg(0));
OS << '(';
@@ -1217,7 +1248,12 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
OS << Int->getValue().toString(10, /*isSigned*/false);
break;
}
- case UserDefinedLiteral::LOK_Floating:
+ case UserDefinedLiteral::LOK_Floating: {
+ // Print floating literal without suffix.
+ FloatingLiteral *Float = cast<FloatingLiteral>(Node->getCookedLiteral());
+ PrintFloatingLiteral(OS, Float, /*PrintSuffix=*/false);
+ break;
+ }
case UserDefinedLiteral::LOK_String:
case UserDefinedLiteral::LOK_Character:
PrintExpr(Node->getCookedLiteral());
@@ -1379,10 +1415,12 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
OS << "::";
OS << "new ";
unsigned NumPlace = E->getNumPlacementArgs();
- if (NumPlace > 0) {
+ if (NumPlace > 0 && !isa<CXXDefaultArgExpr>(E->getPlacementArg(0))) {
OS << "(";
PrintExpr(E->getPlacementArg(0));
for (unsigned i = 1; i < NumPlace; ++i) {
+ if (isa<CXXDefaultArgExpr>(E->getPlacementArg(i)))
+ break;
OS << ", ";
PrintExpr(E->getPlacementArg(i));
}
@@ -1429,6 +1467,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
OS << '.';
if (E->getQualifier())
E->getQualifier()->print(OS, Policy);
+ OS << "~";
std::string TypeS;
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
@@ -1531,6 +1570,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsFunction: return "__is_function";
case UTT_IsFundamental: return "__is_fundamental";
case UTT_IsIntegral: return "__is_integral";
+ case UTT_IsInterfaceClass: return "__is_interface_class";
case UTT_IsLiteral: return "__is_literal";
case UTT_IsLvalueReference: return "__is_lvalue_reference";
case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer";
@@ -1647,6 +1687,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmExpr(
Visit(Node->getReplacement());
}
+void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ OS << *E->getParameterPack();
+}
+
void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
PrintExpr(Node->GetTemporaryExpr());
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 2168b64d5b23..bfd3132506ec 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -158,7 +158,7 @@ void StmtProfiler::VisitReturnStmt(const ReturnStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitAsmStmt(const AsmStmt *S) {
+void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
VisitStmt(S);
ID.AddBoolean(S->isVolatile());
ID.AddBoolean(S->isSimple());
@@ -175,7 +175,7 @@ void StmtProfiler::VisitAsmStmt(const AsmStmt *S) {
}
ID.AddInteger(S->getNumClobbers());
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
- VisitStringLiteral(S->getClobber(I));
+ VisitStringLiteral(S->getClobberStringLiteral(I));
}
void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
@@ -973,6 +973,14 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmExpr(
Visit(E->getReplacement());
}
+void StmtProfiler::VisitFunctionParmPackExpr(const FunctionParmPackExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getParameterPack());
+ ID.AddInteger(S->getNumExpansions());
+ for (FunctionParmPackExpr::iterator I = S->begin(), E = S->end(); I != E; ++I)
+ VisitDecl(*I);
+}
+
void StmtProfiler::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *S) {
VisitExpr(S);
@@ -1165,6 +1173,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
VisitDecl(Arg.getAsDecl());
break;
+ case TemplateArgument::NullPtr:
+ VisitType(Arg.getNullPtrType());
+ break;
+
case TemplateArgument::Integral:
Arg.getAsIntegral().Profile(ID);
VisitType(Arg.getIntegralType());
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 95ff4edf1d6b..e9ee385457f8 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -77,7 +77,7 @@ TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context,
const TemplateArgument *Args,
unsigned NumArgs) {
if (NumArgs == 0)
- return TemplateArgument(0, 0);
+ return getEmptyPack();
TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs];
std::copy(Args, Args + NumArgs, Storage);
@@ -99,12 +99,11 @@ bool TemplateArgument::isDependent() const {
return true;
case Declaration:
- if (Decl *D = getAsDecl()) {
- if (DeclContext *DC = dyn_cast<DeclContext>(D))
- return DC->isDependentContext();
- return D->getDeclContext()->isDependentContext();
- }
-
+ if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
+ return DC->isDependentContext();
+ return getAsDecl()->getDeclContext()->isDependentContext();
+
+ case NullPtr:
return false;
case Integral:
@@ -141,11 +140,11 @@ bool TemplateArgument::isInstantiationDependent() const {
return true;
case Declaration:
- if (Decl *D = getAsDecl()) {
- if (DeclContext *DC = dyn_cast<DeclContext>(D))
- return DC->isDependentContext();
- return D->getDeclContext()->isDependentContext();
- }
+ if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
+ return DC->isDependentContext();
+ return getAsDecl()->getDeclContext()->isDependentContext();
+
+ case NullPtr:
return false;
case Integral:
@@ -174,6 +173,7 @@ bool TemplateArgument::isPackExpansion() const {
case Integral:
case Pack:
case Template:
+ case NullPtr:
return false;
case TemplateExpansion:
@@ -195,6 +195,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
case Declaration:
case Integral:
case TemplateExpansion:
+ case NullPtr:
break;
case Type:
@@ -286,12 +287,16 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
switch (getKind()) {
case Null:
case Type:
- case Declaration:
case Expression:
case Template:
case TemplateExpansion:
+ case NullPtr:
return TypeOrValue == Other.TypeOrValue;
+ case Declaration:
+ return getAsDecl() == Other.getAsDecl() &&
+ isDeclForReferenceParam() && Other.isDeclForReferenceParam();
+
case Integral:
return getIntegralType() == Other.getIntegralType() &&
getAsIntegral() == Other.getAsIntegral();
@@ -319,12 +324,13 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
case TemplateExpansion:
return TemplateArgument(getAsTemplateOrTemplatePattern());
-
+
case Declaration:
case Integral:
case Pack:
case Null:
case Template:
+ case NullPtr:
return TemplateArgument();
}
@@ -348,18 +354,20 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
}
case Declaration: {
- if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) {
- if (ND->getDeclName()) {
- Out << *ND;
- } else {
- Out << "<anonymous>";
- }
+ NamedDecl *ND = cast<NamedDecl>(getAsDecl());
+ if (ND->getDeclName()) {
+ // FIXME: distinguish between pointer and reference args?
+ Out << *ND;
} else {
- Out << "nullptr";
+ Out << "<anonymous>";
}
break;
}
-
+
+ case NullPtr:
+ Out << "nullptr";
+ break;
+
case Template:
getAsTemplate().print(Out, Policy);
break;
@@ -411,6 +419,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
case TemplateArgument::Declaration:
return getSourceDeclExpression()->getSourceRange();
+ case TemplateArgument::NullPtr:
+ return getSourceNullPtrExpression()->getSourceRange();
+
case TemplateArgument::Type:
if (TypeSourceInfo *TSI = getTypeSourceInfo())
return TSI->getTypeLoc().getSourceRange();
@@ -430,6 +441,8 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc());
case TemplateArgument::Integral:
+ return getSourceIntegralExpression()->getSourceRange();
+
case TemplateArgument::Pack:
case TemplateArgument::Null:
return SourceRange();
@@ -490,6 +503,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
getTemplateNameLoc());
case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
case TemplateArgument::Template:
case TemplateArgument::Integral:
case TemplateArgument::Pack:
@@ -512,8 +526,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << Arg.getAsType();
case TemplateArgument::Declaration:
- if (Decl *D = Arg.getAsDecl())
- return DB << D;
+ return DB << Arg.getAsDecl();
+
+ case TemplateArgument::NullPtr:
return DB << "nullptr";
case TemplateArgument::Integral:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index abefae44b2ba..580ec50ca1f8 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -288,18 +288,17 @@ QualType QualType::IgnoreParens(QualType T) {
return T;
}
-/// \brief This will check for a TypedefType by removing any existing sugar
-/// until it reaches a TypedefType or a non-sugared type.
-template <> const TypedefType *Type::getAs() const {
- const Type *Cur = this;
-
+/// \brief This will check for a T (which should be a Type which can act as
+/// sugar, such as a TypedefType) by removing any existing sugar until it
+/// reaches a T or a non-sugared type.
+template<typename T> static const T *getAsSugar(const Type *Cur) {
while (true) {
- if (const TypedefType *TDT = dyn_cast<TypedefType>(Cur))
- return TDT;
+ if (const T *Sugar = dyn_cast<T>(Cur))
+ return Sugar;
switch (Cur->getTypeClass()) {
#define ABSTRACT_TYPE(Class, Parent)
#define TYPE(Class, Parent) \
- case Class: { \
+ case Type::Class: { \
const Class##Type *Ty = cast<Class##Type>(Cur); \
if (!Ty->isSugared()) return 0; \
Cur = Ty->desugar().getTypePtr(); \
@@ -310,6 +309,14 @@ template <> const TypedefType *Type::getAs() const {
}
}
+template <> const TypedefType *Type::getAs() const {
+ return getAsSugar<TypedefType>(this);
+}
+
+template <> const TemplateSpecializationType *Type::getAs() const {
+ return getAsSugar<TemplateSpecializationType>(this);
+}
+
/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
/// sugar off the given type. This should produce an object of the
/// same dynamic type as the canonical type.
@@ -357,9 +364,15 @@ bool Type::isStructureType() const {
return RT->getDecl()->isStruct();
return false;
}
+bool Type::isInterfaceType() const {
+ if (const RecordType *RT = getAs<RecordType>())
+ return RT->getDecl()->isInterface();
+ return false;
+}
bool Type::isStructureOrClassType() const {
if (const RecordType *RT = getAs<RecordType>())
- return RT->getDecl()->isStruct() || RT->getDecl()->isClass();
+ return RT->getDecl()->isStruct() || RT->getDecl()->isClass() ||
+ RT->getDecl()->isInterface();
return false;
}
bool Type::isVoidPointerType() const {
@@ -499,10 +512,18 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
return 0;
}
-const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
+const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
+ QualType PointeeType;
if (const PointerType *PT = getAs<PointerType>())
- if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>())
- return dyn_cast<CXXRecordDecl>(RT->getDecl());
+ PointeeType = PT->getPointeeType();
+ else if (const ReferenceType *RT = getAs<ReferenceType>())
+ PointeeType = RT->getPointeeType();
+ else
+ return 0;
+
+ if (const RecordType *RT = PointeeType->getAs<RecordType>())
+ return dyn_cast<CXXRecordDecl>(RT->getDecl());
+
return 0;
}
@@ -1205,8 +1226,6 @@ bool QualType::isCXX11PODType(ASTContext &Context) const {
return false;
case Qualifiers::OCL_None:
- if (ty->isObjCLifetimeType())
- return false;
break;
}
}
@@ -1317,6 +1336,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
case TST_typename: return ETK_Typename;
case TST_class: return ETK_Class;
case TST_struct: return ETK_Struct;
+ case TST_interface: return ETK_Interface;
case TST_union: return ETK_Union;
case TST_enum: return ETK_Enum;
}
@@ -1327,6 +1347,7 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
switch(TypeSpec) {
case TST_class: return TTK_Class;
case TST_struct: return TTK_Struct;
+ case TST_interface: return TTK_Interface;
case TST_union: return TTK_Union;
case TST_enum: return TTK_Enum;
}
@@ -1339,6 +1360,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) {
switch (Kind) {
case TTK_Class: return ETK_Class;
case TTK_Struct: return ETK_Struct;
+ case TTK_Interface: return ETK_Interface;
case TTK_Union: return ETK_Union;
case TTK_Enum: return ETK_Enum;
}
@@ -1350,6 +1372,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
case ETK_Class: return TTK_Class;
case ETK_Struct: return TTK_Struct;
+ case ETK_Interface: return TTK_Interface;
case ETK_Union: return TTK_Union;
case ETK_Enum: return TTK_Enum;
case ETK_None: // Fall through.
@@ -1367,6 +1390,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
return false;
case ETK_Class:
case ETK_Struct:
+ case ETK_Interface:
case ETK_Union:
case ETK_Enum:
return true;
@@ -1381,6 +1405,7 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
case ETK_Typename: return "typename";
case ETK_Class: return "class";
case ETK_Struct: return "struct";
+ case ETK_Interface: return "__interface";
case ETK_Union: return "union";
case ETK_Enum: return "enum";
}
@@ -1480,6 +1505,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Dependent: return "<dependent type>";
case UnknownAny: return "<unknown type>";
case ARCUnbridgedCast: return "<ARC unbridged cast type>";
+ case BuiltinFn: return "<builtin fn type>";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
@@ -1516,6 +1542,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86Pascal: return "pascal";
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
+ case CC_PnaclCall: return "pnaclcall";
}
llvm_unreachable("Invalid calling convention.");
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index c7bb7da4d17b..58c4cbd00c8a 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -98,23 +98,38 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc Cur = *this;
+ TypeLoc LeftMost = Cur;
while (true) {
switch (Cur.getTypeLocClass()) {
- // FIXME: Currently QualifiedTypeLoc does not have a source range
- // case Qualified:
case Elaborated:
- case DependentName:
- case DependentTemplateSpecialization:
+ LeftMost = Cur;
break;
+ case FunctionProto:
+ if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
+ LeftMost = Cur;
+ break;
+ }
+ /* Fall through */
+ case FunctionNoProto:
+ case ConstantArray:
+ case DependentSizedArray:
+ case IncompleteArray:
+ case VariableArray:
+ // FIXME: Currently QualifiedTypeLoc does not have a source range
+ case Qualified:
+ Cur = Cur.getNextTypeLoc();
+ continue;
default:
- TypeLoc Next = Cur.getNextTypeLoc();
- if (Next.isNull()) break;
- Cur = Next;
+ if (!Cur.getLocalSourceRange().getBegin().isInvalid())
+ LeftMost = Cur;
+ Cur = Cur.getNextTypeLoc();
+ if (Cur.isNull())
+ break;
continue;
- }
+ } // switch
break;
- }
- return Cur.getLocalSourceRange().getBegin();
+ } // while
+ return LeftMost.getLocalSourceRange().getBegin();
}
SourceLocation TypeLoc::getEndLoc() const {
@@ -131,10 +146,15 @@ SourceLocation TypeLoc::getEndLoc() const {
case DependentSizedArray:
case IncompleteArray:
case VariableArray:
- case FunctionProto:
case FunctionNoProto:
Last = Cur;
break;
+ case FunctionProto:
+ if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
+ Last = TypeLoc();
+ else
+ Last = Cur;
+ break;
case Pointer:
case BlockPointer:
case MemberPointer:
@@ -241,6 +261,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
+ case BuiltinType::BuiltinFn:
return TST_unspecified;
}
@@ -300,7 +321,9 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
- case TemplateArgument::Pack:
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Impossible TemplateArgument");
+
case TemplateArgument::Expression:
ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
break;
@@ -310,7 +333,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
Context.getTrivialTypeSourceInfo(Args[i].getAsType(),
Loc));
break;
-
+
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
@@ -327,7 +350,11 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
? SourceLocation()
: Loc);
break;
- }
+ }
+
+ case TemplateArgument::Pack:
+ ArgInfos[i] = TemplateArgumentLocInfo();
+ break;
}
}
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index c42117c82bf5..90b2ca9cce15 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -141,9 +141,6 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS,
OS << "NULL TYPE";
return;
}
-
- if (Policy.SuppressSpecifiers && T->isSpecifierType())
- return;
SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
@@ -556,7 +553,8 @@ void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) {
void
FunctionProtoType::printExceptionSpecification(raw_ostream &OS,
- PrintingPolicy Policy) const {
+ const PrintingPolicy &Policy)
+ const {
if (hasDynamicExceptionSpec()) {
OS << " throw(";
@@ -646,6 +644,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_AAPCS_VFP:
OS << " __attribute__((pcs(\"aapcs-vfp\")))";
break;
+ case CC_PnaclCall:
+ OS << " __attribute__((pnaclcall))";
+ break;
}
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
@@ -798,6 +799,7 @@ void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { }
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
if (DC->isTranslationUnit()) return;
+ if (DC->isFunctionOrMethod()) return;
AppendScope(DC->getParent(), OS);
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
@@ -1165,6 +1167,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
}
+ case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
}
OS << "))";
}
@@ -1343,7 +1346,8 @@ PrintTemplateArgumentList(raw_ostream &OS,
void
FunctionProtoType::printExceptionSpecification(std::string &S,
- PrintingPolicy Policy) const {
+ const PrintingPolicy &Policy)
+ const {
if (hasDynamicExceptionSpec()) {
S += " throw(";
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 104530fc1305..33dad40c0c50 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -1891,6 +1891,9 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
if (MD->isPure())
Out << " [pure]";
+ if (MD->isDeleted())
+ Out << " [deleted]";
+
ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty()) {
// If this function pointer has a return adjustment, dump it.
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 085049debdbe..8ecb26e8c19d 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -27,10 +27,75 @@ namespace ast_matchers {
namespace internal {
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
// identifying the matcher) and a pointer to the AST node.
+//
+// We currently only memoize on nodes whose pointers identify the
+// nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
+// For \c QualType and \c TypeLoc it is possible to implement
+// generation of keys for each type.
+// FIXME: Benchmark whether memoization of non-pointer typed nodes
+// provides enough benefit for the additional amount of code.
typedef std::pair<uint64_t, const void*> UntypedMatchInput;
// Used to store the result of a match and possibly bound nodes.
@@ -50,16 +115,16 @@ public:
// descendants of a traversed node. max_depth is the maximum depth
// to traverse: use 1 for matching the children and INT_MAX for
// matching the descendants.
- MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher,
+ MatchChildASTVisitor(const DynTypedMatcher *Matcher,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
int MaxDepth,
ASTMatchFinder::TraversalKind Traversal,
ASTMatchFinder::BindKind Bind)
- : BaseMatcher(BaseMatcher),
+ : Matcher(Matcher),
Finder(Finder),
Builder(Builder),
- CurrentDepth(-1),
+ CurrentDepth(0),
MaxDepth(MaxDepth),
Traversal(Traversal),
Bind(Bind),
@@ -76,10 +141,23 @@ public:
// Traverse*(c) for each child c of 'node'.
// - Traverse*(c) in turn calls Traverse(c), completing the
// recursion.
- template <typename T>
- bool findMatch(const T &Node) {
+ bool findMatch(const ast_type_traits::DynTypedNode &DynNode) {
reset();
- traverse(Node);
+ if (const Decl *D = DynNode.get<Decl>())
+ traverse(*D);
+ else if (const Stmt *S = DynNode.get<Stmt>())
+ traverse(*S);
+ else if (const NestedNameSpecifier *NNS =
+ DynNode.get<NestedNameSpecifier>())
+ traverse(*NNS);
+ else if (const NestedNameSpecifierLoc *NNSLoc =
+ DynNode.get<NestedNameSpecifierLoc>())
+ traverse(*NNSLoc);
+ else if (const QualType *Q = DynNode.get<QualType>())
+ traverse(*Q);
+ else if (const TypeLoc *T = DynNode.get<TypeLoc>())
+ traverse(*T);
+ // FIXME: Add other base types after adding tests.
return Matches;
}
@@ -87,9 +165,11 @@ public:
// They are public only to allow CRTP to work. They are *not *part
// of the public API of this class.
bool TraverseDecl(Decl *DeclNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
return (DeclNode == NULL) || traverse(*DeclNode);
}
bool TraverseStmt(Stmt *StmtNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
const Stmt *StmtToTraverse = StmtNode;
if (Traversal ==
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
@@ -100,9 +180,39 @@ public:
}
return (StmtToTraverse == NULL) || traverse(*StmtToTraverse);
}
+ // We assume that the QualType and the contained type are on the same
+ // hierarchy level. Thus, we try to match either of them.
bool TraverseType(QualType TypeNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ // Match the Type.
+ if (!match(*TypeNode))
+ return false;
+ // The QualType is matched inside traverse.
return traverse(TypeNode);
}
+ // 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) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ // Match the Type.
+ if (!match(*TypeLocNode.getType()))
+ return false;
+ // Match the QualType.
+ if (!match(TypeLocNode.getType()))
+ return false;
+ // The TypeLoc is matched inside traverse.
+ return traverse(TypeLocNode);
+ }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ return (NNS == NULL) || traverse(*NNS);
+ }
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ if (!match(*NNS.getNestedNameSpecifier()))
+ return false;
+ return !NNS || traverse(NNS);
+ }
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
@@ -120,7 +230,7 @@ private:
// Resets the state of this object.
void reset() {
Matches = false;
- CurrentDepth = -1;
+ CurrentDepth = 0;
}
// Forwards the call to the corresponding Traverse*() method in the
@@ -134,49 +244,57 @@ private:
bool baseTraverse(QualType TypeNode) {
return VisitorBase::TraverseType(TypeNode);
}
+ bool baseTraverse(TypeLoc TypeLocNode) {
+ return VisitorBase::TraverseTypeLoc(TypeLocNode);
+ }
+ bool baseTraverse(const NestedNameSpecifier &NNS) {
+ return VisitorBase::TraverseNestedNameSpecifier(
+ const_cast<NestedNameSpecifier*>(&NNS));
+ }
+ bool baseTraverse(NestedNameSpecifierLoc NNS) {
+ return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
+ }
- // Traverses the subtree rooted at 'node'; returns true if the
- // traversal should continue after this function returns; also sets
- // matched_ to true if a match is found during the traversal.
+ // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
+ // 0 < CurrentDepth <= MaxDepth.
+ //
+ // Returns 'true' if traversal should continue after this function
+ // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
template <typename T>
- bool traverse(const T &Node) {
- TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
- traverse_can_only_be_instantiated_with_base_type);
- ScopedIncrement ScopedDepth(&CurrentDepth);
- if (CurrentDepth == 0) {
- // We don't want to match the root node, so just recurse.
- return baseTraverse(Node);
+ bool match(const T &Node) {
+ if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
+ return true;
}
if (Bind != ASTMatchFinder::BK_All) {
- if (BaseMatcher->matches(Node, Finder, Builder)) {
+ if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node),
+ Finder, Builder)) {
Matches = true;
return false; // Abort as soon as a match is found.
}
- if (CurrentDepth < MaxDepth) {
- // The current node doesn't match, and we haven't reached the
- // maximum depth yet, so recurse.
- return baseTraverse(Node);
- }
- // The current node doesn't match, and we have reached the
- // maximum depth, so don't recurse (but continue the traversal
- // such that other nodes at the current level can be visited).
- return true;
} else {
BoundNodesTreeBuilder RecursiveBuilder;
- if (BaseMatcher->matches(Node, Finder, &RecursiveBuilder)) {
+ if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node),
+ Finder, &RecursiveBuilder)) {
// After the first match the matcher succeeds.
Matches = true;
Builder->addMatch(RecursiveBuilder.build());
}
- if (CurrentDepth < MaxDepth) {
- baseTraverse(Node);
- }
- // In kBindAll mode we always search for more matches.
- return true;
}
+ return true;
}
- const UntypedBaseMatcher *const BaseMatcher;
+ // Traverses the subtree rooted at 'Node'; returns true if the
+ // traversal should continue after this function returns.
+ template <typename T>
+ bool traverse(const T &Node) {
+ TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
+ traverse_can_only_be_instantiated_with_base_type);
+ if (!match(Node))
+ return false;
+ return baseTraverse(Node);
+ }
+
+ const DynTypedMatcher *const Matcher;
ASTMatchFinder *const Finder;
BoundNodesTreeBuilder *const Builder;
int CurrentDepth;
@@ -191,12 +309,21 @@ private:
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
public ASTMatchFinder {
public:
- MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers)
- : Triggers(Triggers),
+ MatchASTVisitor(std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> > *MatcherCallbackPairs)
+ : MatcherCallbackPairs(MatcherCallbackPairs),
ActiveASTContext(NULL) {
}
+ void onStartOfTranslationUnit() {
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ I != E; ++I) {
+ I->second->onStartOfTranslationUnit();
+ }
+ }
+
void set_active_ast_context(ASTContext *NewActiveASTContext) {
ActiveASTContext = NewActiveASTContext;
}
@@ -207,7 +334,7 @@ public:
bool VisitTypedefDecl(TypedefDecl *DeclNode) {
// When we see 'typedef A B', we add name 'B' to the set of names
// A's canonical type maps to. This is necessary for implementing
- // IsDerivedFrom(x) properly, where x can be the name of the base
+ // isDerivedFrom(x) properly, where x can be the name of the base
// class or any of its aliases.
//
// In general, the is-alias-of (as defined by typedefs) relation
@@ -228,7 +355,7 @@ public:
// `- E
//
// It is wrong to assume that the relation is a chain. A correct
- // implementation of IsDerivedFrom() needs to recognize that B and
+ // implementation of isDerivedFrom() needs to recognize that B and
// E are aliases, even though neither is a typedef of the other.
// Therefore, we cannot simply walk through one typedef chain to
// find out whether the type name matches.
@@ -243,23 +370,27 @@ public:
bool TraverseStmt(Stmt *StmtNode);
bool TraverseType(QualType TypeNode);
bool TraverseTypeLoc(TypeLoc TypeNode);
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
// Matches children or descendants of 'Node' with 'BaseMatcher'.
- template <typename T>
- bool memoizedMatchesRecursively(const T &Node,
- const UntypedBaseMatcher &BaseMatcher,
+ bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
TraversalKind Traversal, BindKind Bind) {
- TOOLING_COMPILE_ASSERT((llvm::is_same<T, Decl>::value) ||
- (llvm::is_same<T, Stmt>::value),
- type_does_not_support_memoization);
- const UntypedMatchInput input(BaseMatcher.getID(), &Node);
+ const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
+
+ // For AST-nodes that don't have an identity, we can't memoize.
+ if (!input.second)
+ return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
+ Bind);
+
std::pair<MemoizationMap::iterator, bool> InsertResult
= ResultCache.insert(std::make_pair(input, MemoizedMatchResult()));
if (InsertResult.second) {
BoundNodesTreeBuilder DescendantBoundNodesBuilder;
InsertResult.first->second.ResultOfMatch =
- matchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder,
+ matchesRecursively(Node, Matcher, &DescendantBoundNodesBuilder,
MaxDepth, Traversal, Bind);
InsertResult.first->second.Nodes =
DescendantBoundNodesBuilder.build();
@@ -269,12 +400,12 @@ public:
}
// Matches children or descendants of 'Node' with 'BaseMatcher'.
- template <typename T>
- bool matchesRecursively(const T &Node, const UntypedBaseMatcher &BaseMatcher,
+ bool matchesRecursively(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
TraversalKind Traversal, BindKind Bind) {
MatchChildASTVisitor Visitor(
- &BaseMatcher, this, Builder, MaxDepth, Traversal, Bind);
+ &Matcher, this, Builder, MaxDepth, Traversal, Bind);
return Visitor.findMatch(Node);
}
@@ -282,38 +413,54 @@ public:
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder);
- // Implements ASTMatchFinder::MatchesChildOf.
- virtual bool matchesChildOf(const Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
+ // Implements ASTMatchFinder::matchesChildOf.
+ virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
TraversalKind Traversal,
BindKind Bind) {
- return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal,
+ return matchesRecursively(Node, Matcher, Builder, 1, Traversal,
Bind);
}
- virtual bool matchesChildOf(const Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesTreeBuilder *Builder,
- TraversalKind Traversal,
- BindKind Bind) {
- return matchesRecursively(StmtNode, BaseMatcher, Builder, 1, Traversal,
- Bind);
- }
-
- // Implements ASTMatchFinder::MatchesDescendantOf.
- virtual bool matchesDescendantOf(const Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
+ // Implements ASTMatchFinder::matchesDescendantOf.
+ virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) {
- return memoizedMatchesRecursively(DeclNode, BaseMatcher, Builder, INT_MAX,
+ return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX,
TK_AsIs, Bind);
}
- virtual bool matchesDescendantOf(const Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesTreeBuilder *Builder,
- BindKind Bind) {
- return memoizedMatchesRecursively(StmtNode, BaseMatcher, Builder, INT_MAX,
- TK_AsIs, Bind);
+ // Implements ASTMatchFinder::matchesAncestorOf.
+ virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) {
+ 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;
+ }
+ Ancestor = I->second;
+ if (Matcher.matches(Ancestor, this, Builder))
+ return true;
+ if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
+ return false;
+ }
+ return false;
}
bool shouldVisitTemplateInstantiations() const { return true; }
@@ -358,21 +505,22 @@ private:
// result callback for every node that matches.
template <typename T>
void match(const T &node) {
- for (std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> >::const_iterator
- It = Triggers->begin(), End = Triggers->end();
- It != End; ++It) {
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ I != E; ++I) {
BoundNodesTreeBuilder Builder;
- if (It->first->matches(node, this, &Builder)) {
+ if (I->first->matches(ast_type_traits::DynTypedNode::create(node),
+ this, &Builder)) {
BoundNodesTree BoundNodes = Builder.build();
- MatchVisitor Visitor(ActiveASTContext, It->second);
+ MatchVisitor Visitor(ActiveASTContext, I->second);
BoundNodes.visitMatches(&Visitor);
}
}
}
- std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *const Triggers;
+ std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> > *const MatcherCallbackPairs;
ASTContext *ActiveASTContext;
// Maps a canonical type to its TypedefDecls.
@@ -381,16 +529,16 @@ 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
-// from a base type with the given name. A class is considered to be
-// also derived from itself.
+// from a base type with the given name. A class is not considered to be
+// derived from itself.
bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder) {
- if (Base.matches(*Declaration, this, Builder))
- return true;
if (!Declaration->hasDefinition())
return false;
typedef CXXRecordDecl::base_class_const_iterator BaseIterator;
@@ -403,6 +551,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
// Type::getAs<...>() drills through typedefs.
if (TypeNode->getAs<DependentNameType>() != NULL ||
+ TypeNode->getAs<DependentTemplateSpecializationType>() != NULL ||
TypeNode->getAs<TemplateTypeParmType>() != NULL)
// Dependent names and template TypeNode parameters will be matched when
// the template is instantiated.
@@ -439,6 +588,8 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
}
assert(ClassDecl != NULL);
assert(ClassDecl != Declaration);
+ if (Base.matches(*ClassDecl, this, Builder))
+ return true;
if (classIsDerivedFrom(ClassDecl, Base, Builder))
return true;
}
@@ -466,19 +617,40 @@ bool MatchASTVisitor::TraverseType(QualType TypeNode) {
return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
}
-bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLoc) {
- match(TypeLoc.getType());
- return RecursiveASTVisitor<MatchASTVisitor>::
- TraverseTypeLoc(TypeLoc);
+bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
+ // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
+ // We still want to find those types via matchers, so we match them here. Note
+ // that the TypeLocs are structurally a shadow-hierarchy to the expressed
+ // type, so we visit all involved parts of a compound type when matching on
+ // each TypeLoc.
+ match(TypeLocNode);
+ match(TypeLocNode.getType());
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
+}
+
+bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ match(*NNS);
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
+}
+
+bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
+ NestedNameSpecifierLoc NNS) {
+ match(NNS);
+ // We only match the nested name specifier here (as opposed to traversing it)
+ // because the traversal is already done in the parallel "Loc"-hierarchy.
+ match(*NNS.getNestedNameSpecifier());
+ return
+ RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
}
class MatchASTConsumer : public ASTConsumer {
public:
- MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers,
- MatchFinder::ParsingDoneTestCallback *ParsingDone)
- : Visitor(Triggers),
- ParsingDone(ParsingDone) {}
+ MatchASTConsumer(
+ std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> > *MatcherCallbackPairs,
+ MatchFinder::ParsingDoneTestCallback *ParsingDone)
+ : Visitor(MatcherCallbackPairs),
+ ParsingDone(ParsingDone) {}
private:
virtual void HandleTranslationUnit(ASTContext &Context) {
@@ -486,6 +658,7 @@ private:
ParsingDone->run();
}
Visitor.set_active_ast_context(&Context);
+ Visitor.onStartOfTranslationUnit();
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
Visitor.set_active_ast_context(NULL);
}
@@ -508,9 +681,9 @@ MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
MatchFinder::MatchFinder() : ParsingDone(NULL) {}
MatchFinder::~MatchFinder() {
- for (std::vector< std::pair<const internal::UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> >::const_iterator
- It = Triggers.begin(), End = Triggers.end();
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ It = MatcherCallbackPairs.begin(), End = MatcherCallbackPairs.end();
It != End; ++It) {
delete It->first;
}
@@ -518,24 +691,54 @@ MatchFinder::~MatchFinder() {
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new internal::TypedBaseMatcher<Decl>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new internal::Matcher<Decl>(NodeMatch), Action));
}
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new internal::TypedBaseMatcher<QualType>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new internal::Matcher<QualType>(NodeMatch), Action));
}
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new internal::TypedBaseMatcher<Stmt>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new internal::Matcher<Stmt>(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new NestedNameSpecifierMatcher(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new NestedNameSpecifierLocMatcher(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new TypeLocMatcher(NodeMatch), Action));
}
ASTConsumer *MatchFinder::newASTConsumer() {
- return new internal::MatchASTConsumer(&Triggers, ParsingDone);
+ 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) {
+ internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ Visitor.set_active_ast_context(&Context);
+ Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
}
void MatchFinder::registerTestCallbackAfterParsing(
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 69c51905fe8f..408195d36902 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -18,18 +18,29 @@ namespace clang {
namespace ast_matchers {
namespace internal {
+void BoundNodesMap::copyTo(BoundNodesTreeBuilder *Builder) const {
+ for (IDToNodeMap::const_iterator It = NodeMap.begin();
+ It != NodeMap.end();
+ ++It) {
+ Builder->setBinding(It->first, It->second);
+ }
+}
+
+void BoundNodesMap::copyTo(BoundNodesMap *Other) const {
+ copy(NodeMap.begin(), NodeMap.end(),
+ inserter(Other->NodeMap, Other->NodeMap.begin()));
+}
+
BoundNodesTree::BoundNodesTree() {}
BoundNodesTree::BoundNodesTree(
- const std::map<std::string, const Decl*>& DeclBindings,
- const std::map<std::string, const Stmt*>& StmtBindings,
+ const BoundNodesMap& Bindings,
const std::vector<BoundNodesTree> RecursiveBindings)
- : DeclBindings(DeclBindings), StmtBindings(StmtBindings),
+ : Bindings(Bindings),
RecursiveBindings(RecursiveBindings) {}
void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
- copyBindingsTo(DeclBindings, Builder);
- copyBindingsTo(StmtBindings, Builder);
+ Bindings.copyTo(Builder);
for (std::vector<BoundNodesTree>::const_iterator
I = RecursiveBindings.begin(),
E = RecursiveBindings.end();
@@ -38,63 +49,34 @@ void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
}
}
-template <typename T>
-void BoundNodesTree::copyBindingsTo(
- const T& Bindings, BoundNodesTreeBuilder* Builder) const {
- for (typename T::const_iterator I = Bindings.begin(),
- E = Bindings.end();
- I != E; ++I) {
- Builder->setBinding(I->first, I->second);
- }
-}
-
void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
- std::map<std::string, const Decl*> AggregatedDeclBindings;
- std::map<std::string, const Stmt*> AggregatedStmtBindings;
- visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings,
- AggregatedStmtBindings);
+ BoundNodesMap AggregatedBindings;
+ visitMatchesRecursively(ResultVisitor, AggregatedBindings);
}
void BoundNodesTree::
visitMatchesRecursively(Visitor* ResultVisitor,
- std::map<std::string, const Decl*>
- AggregatedDeclBindings,
- std::map<std::string, const Stmt*>
- AggregatedStmtBindings) {
- copy(DeclBindings.begin(), DeclBindings.end(),
- inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin()));
- copy(StmtBindings.begin(), StmtBindings.end(),
- inserter(AggregatedStmtBindings, AggregatedStmtBindings.begin()));
+ const BoundNodesMap& AggregatedBindings) {
+ BoundNodesMap CombinedBindings(AggregatedBindings);
+ Bindings.copyTo(&CombinedBindings);
if (RecursiveBindings.empty()) {
- ResultVisitor->visitMatch(BoundNodes(AggregatedDeclBindings,
- AggregatedStmtBindings));
+ ResultVisitor->visitMatch(BoundNodes(CombinedBindings));
} else {
for (unsigned I = 0; I < RecursiveBindings.size(); ++I) {
RecursiveBindings[I].visitMatchesRecursively(ResultVisitor,
- AggregatedDeclBindings,
- AggregatedStmtBindings);
+ CombinedBindings);
}
}
}
BoundNodesTreeBuilder::BoundNodesTreeBuilder() {}
-void BoundNodesTreeBuilder::setBinding(const std::string &Id,
- const Decl *Node) {
- DeclBindings[Id] = Node;
-}
-
-void BoundNodesTreeBuilder::setBinding(const std::string &Id,
- const Stmt *Node) {
- StmtBindings[Id] = Node;
-}
-
void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) {
RecursiveBindings.push_back(Bindings);
}
BoundNodesTree BoundNodesTreeBuilder::build() const {
- return BoundNodesTree(DeclBindings, StmtBindings, RecursiveBindings);
+ return BoundNodesTree(Bindings, RecursiveBindings);
}
} // end namespace internal
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 7de7f395e8a7..e7df0a813b37 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -29,13 +29,15 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
+#include "BodyFarm.h"
+
using namespace clang;
typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap;
AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d,
- const CFG::BuildOptions &buildOptions)
+ const Decl *d,
+ const CFG::BuildOptions &buildOptions)
: Manager(Mgr),
D(d),
cfgBuildOptions(buildOptions),
@@ -49,7 +51,7 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
}
AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d)
+ const Decl *d)
: Manager(Mgr),
D(d),
forcedBlkExprs(0),
@@ -62,11 +64,16 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
}
AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool addInitializers) {
+ bool addImplicitDtors,
+ bool addInitializers,
+ bool addTemporaryDtors,
+ bool synthesizeBodies)
+ : SynthesizeBodies(synthesizeBodies)
+{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
+ cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
}
void AnalysisDeclContextManager::clear() {
@@ -75,9 +82,18 @@ void AnalysisDeclContextManager::clear() {
Contexts.clear();
}
+static BodyFarm &getBodyFarm(ASTContext &C) {
+ static BodyFarm *BF = new BodyFarm(C);
+ return *BF;
+}
+
Stmt *AnalysisDeclContext::getBody() const {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->getBody();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Stmt *Body = FD->getBody();
+ if (!Body && Manager && Manager->synthesizeBodies())
+ return getBodyFarm(getASTContext()).getBody(FD);
+ return Body;
+ }
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
@@ -201,6 +217,13 @@ PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() {
}
AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl
+ // that has the body.
+ FD->hasBody(FD);
+ D = FD;
+ }
+
AnalysisDeclContext *&AC = Contexts[D];
if (!AC)
AC = new AnalysisDeclContext(this, D, cfgBuildOptions);
@@ -332,6 +355,10 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const {
return NULL;
}
+bool LocationContext::inTopFrame() const {
+ return getCurrentStackFrame()->inTopFrame();
+}
+
bool LocationContext::isParentOf(const LocationContext *LC) const {
do {
const LocationContext *Parent = LC->getParent();
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
new file mode 100644
index 000000000000..794ff9cc2bb1
--- /dev/null
+++ b/lib/Analysis/BodyFarm.cpp
@@ -0,0 +1,374 @@
+//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringSwitch.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprObjC.h"
+#include "BodyFarm.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Helper creation functions for constructing faux ASTs.
+//===----------------------------------------------------------------------===//
+
+static bool isDispatchBlock(QualType Ty) {
+ // Is it a block pointer?
+ const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
+ if (!BPT)
+ return false;
+
+ // Check if the block pointer type takes no arguments and
+ // returns void.
+ const FunctionProtoType *FT =
+ BPT->getPointeeType()->getAs<FunctionProtoType>();
+ if (!FT || !FT->getResultType()->isVoidType() ||
+ FT->getNumArgs() != 0)
+ return false;
+
+ return true;
+}
+
+namespace {
+class ASTMaker {
+public:
+ ASTMaker(ASTContext &C) : C(C) {}
+
+ /// Create a new BinaryOperator representing a simple assignment.
+ BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
+
+ /// Create a new BinaryOperator representing a comparison.
+ BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
+ BinaryOperator::Opcode Op);
+
+ /// Create a new compound stmt using the provided statements.
+ CompoundStmt *makeCompound(ArrayRef<Stmt*>);
+
+ /// Create a new DeclRefExpr for the referenced variable.
+ DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
+
+ /// Create a new UnaryOperator representing a dereference.
+ UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
+
+ /// Create an implicit cast for an integer conversion.
+ Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
+
+ /// Create an implicit cast to a builtin boolean type.
+ ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
+
+ // Create an implicit cast for lvalue-to-rvaluate conversions.
+ ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
+
+ /// Create an Objective-C bool literal.
+ ObjCBoolLiteralExpr *makeObjCBool(bool Val);
+
+ /// Create a Return statement.
+ ReturnStmt *makeReturn(const Expr *RetVal);
+
+private:
+ ASTContext &C;
+};
+}
+
+BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
+ QualType Ty) {
+ return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
+ BO_Assign, Ty, VK_RValue,
+ OK_Ordinary, SourceLocation(), false);
+}
+
+BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
+ BinaryOperator::Opcode Op) {
+ assert(BinaryOperator::isLogicalOp(Op) ||
+ BinaryOperator::isComparisonOp(Op));
+ return new (C) BinaryOperator(const_cast<Expr*>(LHS),
+ const_cast<Expr*>(RHS),
+ Op,
+ C.getLogicalOperationType(),
+ VK_RValue,
+ OK_Ordinary, SourceLocation(), false);
+}
+
+CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
+ return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
+ Stmts.size(),
+ SourceLocation(), SourceLocation());
+}
+
+DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
+ DeclRefExpr *DR =
+ DeclRefExpr::Create(/* Ctx = */ C,
+ /* QualifierLoc = */ NestedNameSpecifierLoc(),
+ /* TemplateKWLoc = */ SourceLocation(),
+ /* D = */ const_cast<VarDecl*>(D),
+ /* isEnclosingLocal = */ false,
+ /* NameLoc = */ SourceLocation(),
+ /* T = */ D->getType(),
+ /* VK = */ VK_LValue);
+ return DR;
+}
+
+UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
+ return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
+ VK_LValue, OK_Ordinary, SourceLocation());
+}
+
+ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
+ return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
+ if (Arg->getType() == Ty)
+ return const_cast<Expr*>(Arg);
+
+ return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
+ return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
+ QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
+ return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
+}
+
+ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
+ return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
+}
+
+//===----------------------------------------------------------------------===//
+// Creation functions for faux ASTs.
+//===----------------------------------------------------------------------===//
+
+typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
+
+/// Create a fake body for dispatch_once.
+static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the first parameter is a pointer to integer type.
+ const ParmVarDecl *Predicate = D->getParamDecl(0);
+ QualType PredicateQPtrTy = Predicate->getType();
+ const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
+ if (!PredicatePtrTy)
+ return 0;
+ QualType PredicateTy = PredicatePtrTy->getPointeeType();
+ if (!PredicateTy->isIntegerType())
+ return 0;
+
+ // Check if the second parameter is the proper block type.
+ const ParmVarDecl *Block = D->getParamDecl(1);
+ QualType Ty = Block->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fakse body that checks the predicate,
+ // sets it, and calls the block. Basically, an AST dump of:
+ //
+ // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
+ // if (!*predicate) {
+ // *predicate = 1;
+ // block();
+ // }
+ // }
+
+ ASTMaker M(C);
+
+ // (1) Create the call.
+ DeclRefExpr *DR = M.makeDeclRefExpr(Block);
+ ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+
+ // (2) Create the assignment to the predicate.
+ IntegerLiteral *IL =
+ IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
+ C.IntTy, SourceLocation());
+ BinaryOperator *B =
+ M.makeAssignment(
+ M.makeDereference(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
+ PredicateTy),
+ M.makeIntegralCast(IL, PredicateTy),
+ PredicateTy);
+
+ // (3) Create the compound statement.
+ Stmt *Stmts[2];
+ Stmts[0] = B;
+ Stmts[1] = CE;
+ CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+
+ // (4) Create the 'if' condition.
+ ImplicitCastExpr *LValToRval =
+ M.makeLvalueToRvalue(
+ M.makeDereference(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(Predicate),
+ PredicateQPtrTy),
+ PredicateTy),
+ PredicateTy);
+
+ UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+
+ // (5) Create the 'if' statement.
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+ return If;
+}
+
+/// Create a fake body for dispatch_sync.
+static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the second parameter is a block.
+ const ParmVarDecl *PV = D->getParamDecl(1);
+ QualType Ty = PV->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fake body that just calls the block.
+ // This is basically just an AST dump of:
+ //
+ // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
+ // block();
+ // }
+ //
+ ASTMaker M(C);
+ DeclRefExpr *DR = M.makeDeclRefExpr(PV);
+ ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+ return CE;
+}
+
+static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
+{
+ // There are exactly 3 arguments.
+ if (D->param_size() != 3)
+ return 0;
+
+ // Body for:
+ // if (oldValue == *theValue) {
+ // *theValue = newValue;
+ // return YES;
+ // }
+ // else return NO;
+
+ QualType ResultTy = D->getResultType();
+ bool isBoolean = ResultTy->isBooleanType();
+ if (!isBoolean && !ResultTy->isIntegralType(C))
+ return 0;
+
+ const ParmVarDecl *OldValue = D->getParamDecl(0);
+ QualType OldValueTy = OldValue->getType();
+
+ const ParmVarDecl *NewValue = D->getParamDecl(1);
+ QualType NewValueTy = NewValue->getType();
+
+ assert(OldValueTy == NewValueTy);
+
+ const ParmVarDecl *TheValue = D->getParamDecl(2);
+ QualType TheValueTy = TheValue->getType();
+ const PointerType *PT = TheValueTy->getAs<PointerType>();
+ if (!PT)
+ return 0;
+ QualType PointeeTy = PT->getPointeeType();
+
+ ASTMaker M(C);
+ // Construct the comparison.
+ Expr *Comparison =
+ M.makeComparison(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
+ M.makeLvalueToRvalue(
+ M.makeDereference(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+ PointeeTy),
+ PointeeTy),
+ BO_EQ);
+
+ // Construct the body of the IfStmt.
+ Stmt *Stmts[2];
+ Stmts[0] =
+ M.makeAssignment(
+ M.makeDereference(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+ PointeeTy),
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
+ NewValueTy);
+
+ Expr *BoolVal = M.makeObjCBool(true);
+ Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
+ : M.makeIntegralCast(BoolVal, ResultTy);
+ Stmts[1] = M.makeReturn(RetVal);
+ CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+
+ // Construct the else clause.
+ BoolVal = M.makeObjCBool(false);
+ RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
+ : M.makeIntegralCast(BoolVal, ResultTy);
+ Stmt *Else = M.makeReturn(RetVal);
+
+ /// Construct the If.
+ Stmt *If =
+ new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
+ SourceLocation(), Else);
+
+ return If;
+}
+
+Stmt *BodyFarm::getBody(const FunctionDecl *D) {
+ D = D->getCanonicalDecl();
+
+ llvm::Optional<Stmt *> &Val = Bodies[D];
+ if (Val.hasValue())
+ return Val.getValue();
+
+ Val = 0;
+
+ if (D->getIdentifier() == 0)
+ return 0;
+
+ StringRef Name = D->getName();
+ if (Name.empty())
+ return 0;
+
+ FunctionFarmer FF;
+
+ if (Name.startswith("OSAtomicCompareAndSwap") ||
+ Name.startswith("objc_atomicCompareAndSwap")) {
+ FF = create_OSAtomicCompareAndSwap;
+ }
+ else {
+ FF = llvm::StringSwitch<FunctionFarmer>(Name)
+ .Case("dispatch_sync", create_dispatch_sync)
+ .Case("dispatch_once", create_dispatch_once)
+ .Default(NULL);
+ }
+
+ if (FF) { Val = FF(C, D); }
+ return Val.getValue();
+}
+
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
new file mode 100644
index 000000000000..d503cc1bcd07
--- /dev/null
+++ b/lib/Analysis/BodyFarm.h
@@ -0,0 +1,43 @@
+//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H
+#define LLVM_CLANG_ANALYSIS_BODYFARM_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class FunctionDecl;
+class Stmt;
+
+class BodyFarm {
+public:
+ BodyFarm(ASTContext &C) : C(C) {}
+
+ /// Factory method for creating bodies for ordinary functions.
+ Stmt *getBody(const FunctionDecl *D);
+
+private:
+ typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap;
+
+ ASTContext &C;
+ BodyMap Bodies;
+};
+}
+
+#endif
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 05c53850f568..315e54380b2f 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -467,6 +467,30 @@ private:
CachedBoolEvals[S] = Result; // update or insert
return Result;
}
+ else {
+ switch (Bop->getOpcode()) {
+ default: break;
+ // For 'x & 0' and 'x * 0', we can determine that
+ // the value is always false.
+ case BO_Mul:
+ case BO_And: {
+ // If either operand is zero, we know the value
+ // must be false.
+ llvm::APSInt IntVal;
+ if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) {
+ if (IntVal.getBoolValue() == false) {
+ return TryResult(false);
+ }
+ }
+ if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) {
+ if (IntVal.getBoolValue() == false) {
+ return TryResult(false);
+ }
+ }
+ }
+ break;
+ }
+ }
}
return evaluateAsBooleanConditionNoCache(S);
@@ -682,7 +706,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
IsReference = FD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
- if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+ if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
IsReference);
@@ -1022,6 +1046,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::ExprWithCleanupsClass:
return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc);
+ case Stmt::CXXDefaultArgExprClass:
+ // FIXME: The expression inside a CXXDefaultArgExpr is owned by the
+ // called function's declaration, not by the caller. If we simply add
+ // this expression to the CFG, we could end up with the same Expr
+ // appearing multiple times.
+ // PR13385 / <rdar://problem/12156507>
+ return VisitStmt(S, asc);
+
case Stmt::CXXBindTemporaryExprClass:
return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
@@ -1585,7 +1617,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
IsReference = VD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
- if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+ if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
IsReference);
@@ -1616,8 +1648,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// If the type of VD is a VLA, then we must process its size expressions.
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- Block = addStmt(VA->getSizeExpr());
+ VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) {
+ if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
+ LastBlock = newBlock;
+ }
// Remove variable from local scope.
if (ScopePos && VD == *ScopePos)
@@ -1735,7 +1769,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// Add the condition as the last statement in the new block. This may create
// new blocks as the condition may contain control-flow. Any newly created
// blocks will be pointed to be "Block".
- Block = addStmt(I->getCond());
+ CFGBlock *LastBlock = addStmt(I->getCond());
// Finally, if the IfStmt contains a condition variable, add both the IfStmt
// and the condition variable initialization to the CFG.
@@ -1743,11 +1777,11 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
appendStmt(Block, I->getConditionVariableDeclStmt());
- addStmt(Init);
+ LastBlock = addStmt(Init);
}
}
- return Block;
+ return LastBlock;
}
@@ -2254,7 +2288,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
}
// The default case when not handling logical operators.
- EntryConditionBlock = ExitConditionBlock = createBlock(false);
+ ExitConditionBlock = createBlock(false);
ExitConditionBlock->setTerminator(W);
// Now add the actual condition to the condition block.
@@ -2579,7 +2613,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
Block = SwitchTerminatedBlock;
- Block = addStmt(Terminator->getCond());
+ CFGBlock *LastBlock = addStmt(Terminator->getCond());
// Finally, if the SwitchStmt contains a condition variable, add both the
// SwitchStmt and the condition variable initialization to the CFG.
@@ -2587,11 +2621,11 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
appendStmt(Block, Terminator->getConditionVariableDeclStmt());
- addStmt(Init);
+ LastBlock = addStmt(Init);
}
}
- return Block;
+ return LastBlock;
}
static bool shouldAddCase(bool &switchExclusivelyCovered,
@@ -2775,8 +2809,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
Block = NULL;
- Block = addStmt(Terminator->getTryBlock());
- return Block;
+ return addStmt(Terminator->getTryBlock());
}
CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
@@ -2917,15 +2950,15 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
addLocalScopeAndDtors(S->getLoopVarStmt());
// Populate a new block to contain the loop body and loop variable.
- Block = addStmt(S->getBody());
+ addStmt(S->getBody());
if (badCFG)
return 0;
- Block = addStmt(S->getLoopVarStmt());
+ CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
if (badCFG)
return 0;
// This new body block is a successor to our condition block.
- addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
+ addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : LoopVarStmtBlock);
}
// Link up the condition block with the code that follows the loop (the
@@ -2940,7 +2973,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
AddStmtChoice asc) {
- if (BuildOpts.AddImplicitDtors) {
+ if (BuildOpts.AddTemporaryDtors) {
// If adding implicit destructors visit the full expression for adding
// destructors of temporaries.
VisitForTemporaryDtors(E->getSubExpr());
@@ -3020,6 +3053,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
}
CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
+ assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
+
tryAgain:
if (!E) {
badCFG = true;
@@ -3449,12 +3484,12 @@ class StmtPrinterHelper : public PrinterHelper {
StmtMapTy StmtMap;
DeclMapTy DeclMap;
signed currentBlock;
- unsigned currentStmt;
+ unsigned currStmt;
const LangOptions &LangOpts;
public:
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : currentBlock(0), currentStmt(0), LangOpts(LO)
+ : currentBlock(0), currStmt(0), LangOpts(LO)
{
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
@@ -3515,7 +3550,7 @@ public:
const LangOptions &getLangOpts() const { return LangOpts; }
void setBlockID(signed i) { currentBlock = i; }
- void setStmtID(unsigned i) { currentStmt = i; }
+ void setStmtID(unsigned i) { currStmt = i; }
virtual bool handledStmt(Stmt *S, raw_ostream &OS) {
StmtMapTy::iterator I = StmtMap.find(S);
@@ -3524,7 +3559,7 @@ public:
return false;
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
- && I->second.second == currentStmt) {
+ && I->second.second == currStmt) {
return false;
}
@@ -3539,7 +3574,7 @@ public:
return false;
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
- && I->second.second == currentStmt) {
+ && I->second.second == currStmt) {
return false;
}
@@ -3831,8 +3866,8 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
if (Helper) Helper->setBlockID(-1);
- CFGBlockTerminatorPrint TPrinter(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
+ PrintingPolicy PP(Helper ? Helper->getLangOpts() : LangOptions());
+ CFGBlockTerminatorPrint TPrinter(OS, Helper, PP);
TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
OS << '\n';
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index d57e4813ca02..ca166669fc89 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -1,13 +1,15 @@
add_clang_library(clangAnalysis
AnalysisDeclContext.cpp
- CallGraph.cpp
+ BodyFarm.cpp
CFG.cpp
CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
+ CallGraph.cpp
CocoaConventions.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
+ ObjCNoReturn.cpp
PostOrderCFGView.cpp
PrintfFormatString.cpp
ProgramPoint.cpp
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index e7ea48688dae..73063b5132c8 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -14,6 +14,7 @@
#include "FormatStringParsing.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -489,9 +490,12 @@ analyze_format_string::LengthModifier::toString() const {
const char *ConversionSpecifier::toString() const {
switch (kind) {
case dArg: return "d";
+ case DArg: return "D";
case iArg: return "i";
case oArg: return "o";
+ case OArg: return "O";
case uArg: return "u";
+ case UArg: return "U";
case xArg: return "x";
case XArg: return "X";
case fArg: return "f";
@@ -523,6 +527,29 @@ const char *ConversionSpecifier::toString() const {
return NULL;
}
+llvm::Optional<ConversionSpecifier>
+ConversionSpecifier::getStandardSpecifier() const {
+ ConversionSpecifier::Kind NewKind;
+
+ switch (getKind()) {
+ default:
+ return llvm::Optional<ConversionSpecifier>();
+ case DArg:
+ NewKind = dArg;
+ break;
+ case UArg:
+ NewKind = uArg;
+ break;
+ case OArg:
+ NewKind = oArg;
+ break;
+ }
+
+ ConversionSpecifier FixedCS(*this);
+ FixedCS.setKind(NewKind);
+ return FixedCS;
+}
+
//===----------------------------------------------------------------------===//
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
@@ -548,7 +575,7 @@ void OptionalAmount::toString(raw_ostream &os) const {
}
}
-bool FormatSpecifier::hasValidLengthModifier() const {
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
switch (LM.getKind()) {
case LengthModifier::None:
return true;
@@ -563,9 +590,12 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case LengthModifier::AsPtrDiff:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::nArg:
@@ -578,9 +608,12 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case LengthModifier::AsLong:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -611,14 +644,15 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case ConversionSpecifier::gArg:
case ConversionSpecifier::GArg:
return true;
- // GNU extension.
+ // GNU libc extension.
case ConversionSpecifier::dArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::uArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
- return true;
+ return !Target.getTriple().isOSDarwin() &&
+ !Target.getTriple().isOSWindows();
default:
return false;
}
@@ -697,6 +731,9 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt)
return LangOpt.ObjC1 || LangOpt.ObjC2;
case ConversionSpecifier::InvalidSpecifier:
case ConversionSpecifier::PrintErrno:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::OArg:
+ case ConversionSpecifier::UArg:
return false;
}
llvm_unreachable("Invalid ConversionSpecifier Kind!");
@@ -719,6 +756,20 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
+llvm::Optional<LengthModifier>
+FormatSpecifier::getCorrectedLengthModifier() const {
+ if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
+ if (LM.getKind() == LengthModifier::AsLongDouble ||
+ LM.getKind() == LengthModifier::AsQuad) {
+ LengthModifier FixedLM(LM);
+ FixedLM.setKind(LengthModifier::AsLongLong);
+ return FixedLM;
+ }
+ }
+
+ return llvm::Optional<LengthModifier>();
+}
+
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LengthModifier &LM) {
assert(isa<TypedefType>(QT) && "Expected a TypedefType");
diff --git a/lib/Analysis/ObjCNoReturn.cpp b/lib/Analysis/ObjCNoReturn.cpp
new file mode 100644
index 000000000000..52d844bf9dd8
--- /dev/null
+++ b/lib/Analysis/ObjCNoReturn.cpp
@@ -0,0 +1,67 @@
+//= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- 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 special handling of recognizing ObjC API hooks that
+// do not return but aren't marked as such in API headers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+
+using namespace clang;
+
+static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
+ if (!Class)
+ return false;
+ if (Class->getIdentifier() == II)
+ return true;
+ return isSubclass(Class->getSuperClass(), II);
+}
+
+ObjCNoReturn::ObjCNoReturn(ASTContext &C)
+ : RaiseSel(GetNullarySelector("raise", C)),
+ NSExceptionII(&C.Idents.get("NSException"))
+{
+ // Generate selectors.
+ SmallVector<IdentifierInfo*, 3> II;
+
+ // raise:format:
+ II.push_back(&C.Idents.get("raise"));
+ II.push_back(&C.Idents.get("format"));
+ NSExceptionInstanceRaiseSelectors[0] =
+ C.Selectors.getSelector(II.size(), &II[0]);
+
+ // raise:format:arguments:
+ II.push_back(&C.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[1] =
+ C.Selectors.getSelector(II.size(), &II[0]);
+}
+
+
+bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) {
+ Selector S = ME->getSelector();
+
+ if (ME->isInstanceMessage()) {
+ // Check for the "raise" message.
+ return S == RaiseSel;
+ }
+
+ if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) {
+ if (isSubclass(ID, NSExceptionII)) {
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
+ if (S == NSExceptionInstanceRaiseSelectors[i])
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 9e4c0fec4c04..2fa5a88f2c71 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
using clang::analyze_format_string::ArgType;
@@ -52,7 +53,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -196,6 +198,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
+ // Apple-specific
+ case 'D':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::DArg;
+ break;
+ case 'O':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::OArg;
+ break;
+ case 'U':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::UArg;
+ break;
}
PrintfConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
@@ -212,18 +227,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
const char *I,
const char *E,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
- LO);
+ LO, Target);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
- return true;;
+ return true;
// Did we exhaust the string or encounter an error that
// we can recover from?
if (!FSR.hasValue())
@@ -482,9 +498,11 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
- if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
- return true;
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
+ if (ATR.isValid() && ATR.matchesType(Ctx, QT))
+ return true;
+ }
// 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.
@@ -549,6 +567,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
// The plus prefix only makes sense for signed conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
@@ -572,6 +591,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
// Alternate form flag only valid with the oxXaAeEfFgG conversions
switch (CS.getKind()) {
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -596,9 +616,12 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
// Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -623,6 +646,7 @@ bool PrintfSpecifier::hasValidSpacePrefix() const {
// The space prefix only makes sense for signed conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
@@ -659,8 +683,10 @@ bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
case ConversionSpecifier::gArg:
@@ -678,9 +704,12 @@ bool PrintfSpecifier::hasValidPrecision() const {
// Precision is only valid with the diouxXaAeEfFgGs conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index bb63e2c18490..11f2ebe9ad2d 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -112,8 +112,8 @@ const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
static int SrcCmp(const void *p1, const void *p2) {
return
- ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
- ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
+ ((const std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
+ ((const std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
}
unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 2942400621d1..574e56a5e068 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
using clang::analyze_format_string::ArgType;
@@ -67,7 +68,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
using namespace clang::analyze_scanf;
const char *I = Beg;
@@ -172,6 +174,20 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
case 'o': k = ConversionSpecifier::oArg; break;
case 's': k = ConversionSpecifier::sArg; break;
case 'p': k = ConversionSpecifier::pArg; break;
+ // Apple extensions
+ // Apple-specific
+ case 'D':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::DArg;
+ break;
+ case 'O':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::OArg;
+ break;
+ case 'U':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::UArg;
+ break;
}
ScanfConversionSpecifier CS(conversionPosition, k);
if (k == ScanfConversionSpecifier::ScanListArg) {
@@ -202,6 +218,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
switch(CS.getKind()) {
// Signed int.
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
switch (LM.getKind()) {
case LengthModifier::None:
@@ -233,7 +250,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// Unsigned int.
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
switch (LM.getKind()) {
@@ -430,9 +449,11 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_scanf::ArgType &AT = getArgType(Ctx);
- if (hasValidLengthModifier() && AT.isValid() && AT.matchesType(Ctx, QT))
- return true;
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ const analyze_scanf::ArgType &AT = getArgType(Ctx);
+ if (AT.isValid() && AT.matchesType(Ctx, QT))
+ return true;
+ }
// Figure out the conversion specifier.
if (PT->isRealFloatingType())
@@ -463,18 +484,19 @@ void ScanfSpecifier::toString(raw_ostream &os) const {
bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
const char *I,
const char *E,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
- LO);
+ LO, Target);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
- return true;;
+ return true;
// Did we exhaust the string or encounter an error that
// we can recover from?
if (!FSR.hasValue())
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 5954682579d8..c7f1f62cb57d 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -70,27 +70,28 @@ namespace {
class SExpr {
private:
enum ExprOp {
- EOP_Nop, //< No-op
- EOP_Wildcard, //< Matches anything.
- EOP_This, //< This keyword.
- EOP_NVar, //< Named variable.
- EOP_LVar, //< Local variable.
- EOP_Dot, //< Field access
- EOP_Call, //< Function call
- EOP_MCall, //< Method call
- EOP_Index, //< Array index
- EOP_Unary, //< Unary operation
- EOP_Binary, //< Binary operation
- EOP_Unknown //< Catchall for everything else
+ EOP_Nop, ///< No-op
+ EOP_Wildcard, ///< Matches anything.
+ EOP_Universal, ///< Universal lock.
+ EOP_This, ///< This keyword.
+ EOP_NVar, ///< Named variable.
+ EOP_LVar, ///< Local variable.
+ EOP_Dot, ///< Field access
+ EOP_Call, ///< Function call
+ EOP_MCall, ///< Method call
+ EOP_Index, ///< Array index
+ EOP_Unary, ///< Unary operation
+ EOP_Binary, ///< Binary operation
+ EOP_Unknown ///< Catchall for everything else
};
class SExprNode {
private:
- unsigned char Op; //< Opcode of the root node
- unsigned char Flags; //< Additional opcode-specific data
- unsigned short Sz; //< Number of child nodes
- const void* Data; //< Additional opcode-specific data
+ unsigned char Op; ///< Opcode of the root node
+ unsigned char Flags; ///< Additional opcode-specific data
+ unsigned short Sz; ///< Number of child nodes
+ const void* Data; ///< Additional opcode-specific data
public:
SExprNode(ExprOp O, unsigned F, const void* D)
@@ -118,18 +119,19 @@ private:
unsigned arity() const {
switch (Op) {
- case EOP_Nop: return 0;
- case EOP_Wildcard: return 0;
- case EOP_NVar: return 0;
- case EOP_LVar: return 0;
- case EOP_This: return 0;
- case EOP_Dot: return 1;
- case EOP_Call: return Flags+1; // First arg is function.
- case EOP_MCall: return Flags+1; // First arg is implicit obj.
- case EOP_Index: return 2;
- case EOP_Unary: return 1;
- case EOP_Binary: return 2;
- case EOP_Unknown: return Flags;
+ case EOP_Nop: return 0;
+ case EOP_Wildcard: return 0;
+ case EOP_Universal: return 0;
+ case EOP_NVar: return 0;
+ case EOP_LVar: return 0;
+ case EOP_This: return 0;
+ case EOP_Dot: return 1;
+ case EOP_Call: return Flags+1; // First arg is function.
+ case EOP_MCall: return Flags+1; // First arg is implicit obj.
+ case EOP_Index: return 2;
+ case EOP_Unary: return 1;
+ case EOP_Binary: return 2;
+ case EOP_Unknown: return Flags;
}
return 0;
}
@@ -194,6 +196,11 @@ private:
return NodeVec.size()-1;
}
+ unsigned makeUniversal() {
+ NodeVec.push_back(SExprNode(EOP_Universal, 0, 0));
+ return NodeVec.size()-1;
+ }
+
unsigned makeNamedVar(const NamedDecl *D) {
NodeVec.push_back(SExprNode(EOP_NVar, 0, D));
return NodeVec.size()-1;
@@ -219,8 +226,21 @@ private:
return NodeVec.size()-1;
}
- unsigned makeMCall(unsigned NumArgs, const NamedDecl *D) {
- NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, D));
+ // Grab the very first declaration of virtual method D
+ const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
+ while (true) {
+ D = D->getCanonicalDecl();
+ CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
+ E = D->end_overridden_methods();
+ if (I == E)
+ return D; // Method does not override anything
+ D = *I; // FIXME: this does not work with multiple inheritance.
+ }
+ return 0;
+ }
+
+ unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) {
+ NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, getFirstVirtualDecl(D)));
return NodeVec.size()-1;
}
@@ -300,8 +320,9 @@ private:
} else if (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.
- if (LockReturnedAttr* At =
- CMCE->getMethodDecl()->getAttr<LockReturnedAttr>()) {
+ CXXMethodDecl* MD =
+ cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl());
+ if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CMCE->getMethodDecl());
LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
LRCallCtx.SelfArrow =
@@ -320,8 +341,7 @@ private:
return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref);
}
unsigned NumCallArgs = CMCE->getNumArgs();
- unsigned Root =
- makeMCall(NumCallArgs, CMCE->getMethodDecl()->getCanonicalDecl());
+ unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl());
unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx);
Expr** CallArgs = CMCE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
@@ -330,8 +350,9 @@ private:
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
} else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- if (LockReturnedAttr* At =
- CE->getDirectCallee()->getAttr<LockReturnedAttr>()) {
+ FunctionDecl* FD =
+ cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl());
+ if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CE->getDirectCallee());
LRCallCtx.NumArgs = CE->getNumArgs();
LRCallCtx.FunArgs = CE->getArgs();
@@ -442,9 +463,23 @@ 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) {
+ void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D,
+ VarDecl *SelfDecl = 0) {
CallingContext CallCtx(D);
+ if (MutexExp) {
+ if (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.
+ makeUniversal();
+ else
+ // Ignore other string literals for now.
+ makeNop();
+ return;
+ }
+ }
+
// If we are processing a raw attribute expression, with no substitutions.
if (DeclExp == 0) {
buildSExpr(MutexExp, 0);
@@ -465,7 +500,7 @@ private:
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
- CallCtx.SelfArg = 0; // FIXME -- get the parent from DeclStmt
+ CallCtx.SelfArg = 0; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (D && isa<CXXDestructorDecl>(D)) {
@@ -473,14 +508,26 @@ private:
CallCtx.SelfArg = DeclExp;
}
- // If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0) {
- buildSExpr(CallCtx.SelfArg, 0);
+ // Hack to handle constructors, where self cannot be recovered from
+ // the expression.
+ if (SelfDecl && !CallCtx.SelfArg) {
+ DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
+ SelfDecl->getLocation());
+ CallCtx.SelfArg = &SelfDRE;
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0)
+ buildSExpr(CallCtx.SelfArg, 0);
+ else // For most attributes.
+ buildSExpr(MutexExp, &CallCtx);
return;
}
- // For most attributes.
- buildSExpr(MutexExp, &CallCtx);
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0)
+ buildSExpr(CallCtx.SelfArg, 0);
+ else // For most attributes.
+ buildSExpr(MutexExp, &CallCtx);
}
/// \brief Get index of next sibling of node i.
@@ -496,8 +543,9 @@ 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) {
- buildSExprFromExpr(MutexExp, DeclExp, D);
+ SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D,
+ VarDecl *SelfDecl=0) {
+ buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
/// Return true if this is a valid decl sequence.
@@ -506,6 +554,17 @@ public:
return !NodeVec.empty();
}
+ bool shouldIgnore() const {
+ // Nop is a mutex that we have decided to deliberately ignore.
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Nop;
+ }
+
+ bool isUniversal() const {
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Universal;
+ }
+
/// Issue a warning about an invalid lock expression
static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
Expr *DeclExp, const NamedDecl* D) {
@@ -528,7 +587,9 @@ public:
bool matches(const SExpr &Other, unsigned i = 0, unsigned j = 0) const {
if (NodeVec[i].matches(Other.NodeVec[j])) {
- unsigned n = NodeVec[i].arity();
+ unsigned ni = NodeVec[i].arity();
+ unsigned nj = Other.NodeVec[j].arity();
+ unsigned n = (ni < nj) ? ni : nj;
bool Result = true;
unsigned ci = i+1; // first child of i
unsigned cj = j+1; // first child of j
@@ -541,6 +602,15 @@ public:
return false;
}
+ // A partial match between a.mu and b.mu returns true a and b have the same
+ // type (and thus mu refers to the same mutex declaration), regardless of
+ // whether a and b are different objects or not.
+ bool partiallyMatches(const SExpr &Other) const {
+ if (NodeVec[0].kind() == EOP_Dot)
+ return NodeVec[0].matches(Other.NodeVec[0]);
+ return false;
+ }
+
/// \brief Pretty print a lock expression for use in error messages.
std::string toString(unsigned i = 0) const {
assert(isValid());
@@ -553,6 +623,8 @@ public:
return "_";
case EOP_Wildcard:
return "(?)";
+ case EOP_Universal:
+ return "*";
case EOP_This:
return "this";
case EOP_NVar:
@@ -695,6 +767,10 @@ struct LockData {
ID.AddInteger(AcquireLoc.getRawEncoding());
ID.AddInteger(LKind);
}
+
+ bool isAtLeast(LockKind LK) {
+ return (LK == LK_Shared) || (LKind == LK_Exclusive);
+ }
};
@@ -780,9 +856,28 @@ public:
return false;
}
- LockData* findLock(FactManager& FM, const SExpr& M) const {
+ LockData* findLock(FactManager &FM, const SExpr &M) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M))
+ return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ LockData* findLockUniv(FactManager &FM, const SExpr &M) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M) || Exp.isUniversal())
+ return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ FactEntry* findPartialMatch(FactManager &FM, const SExpr &M) const {
for (const_iterator I=begin(), E=end(); I != E; ++I) {
- if (FM[*I].MutID.matches(M)) return &FM[*I].LDat;
+ const SExpr& Exp = FM[*I].MutID;
+ if (Exp.partiallyMatches(M)) return &FM[*I];
}
return 0;
}
@@ -811,6 +906,7 @@ struct CFGBlockInfo {
SourceLocation EntryLoc; // Location of first statement in block
SourceLocation ExitLoc; // Location of last statement in block.
unsigned EntryIndex; // Used to replay contexts later
+ bool Reachable; // Is this block reachable?
const FactSet &getSet(CFGBlockSide Side) const {
return Side == CBS_Entry ? EntrySet : ExitSet;
@@ -821,7 +917,7 @@ struct CFGBlockInfo {
private:
CFGBlockInfo(LocalVarContext EmptyCtx)
- : EntryContext(EmptyCtx), ExitContext(EmptyCtx)
+ : EntryContext(EmptyCtx), ExitContext(EmptyCtx), Reachable(false)
{ }
public:
@@ -939,7 +1035,7 @@ public:
return;
}
Dec->printName(llvm::errs());
- llvm::errs() << "." << i << " " << ((void*) Dec);
+ llvm::errs() << "." << i << " " << ((const void*) Dec);
}
/// Dumps an ASCII representation of the variable map to llvm::errs()
@@ -1339,7 +1435,7 @@ public:
template <typename AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
- const NamedDecl *D);
+ const NamedDecl *D, VarDecl *SelfDecl=0);
template <class AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
@@ -1376,6 +1472,9 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
const LockData &LDat) {
// FIXME: deal with acquired before/after annotations.
// FIXME: Don't always warn when we have support for reentrant locks.
+ if (Mutex.shouldIgnore())
+ return;
+
if (FSet.findLock(FactMan, Mutex)) {
Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
} else {
@@ -1385,12 +1484,15 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
/// \brief Remove a lock from the lockset, warning if the lock is not there.
-/// \param LockExp The lock expression corresponding to the lock to be removed
+/// \param Mutex The lock expression corresponding to the lock to be removed
/// \param UnlockLoc The source location of the unlock (only used in error msg)
void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const SExpr &Mutex,
SourceLocation UnlockLoc,
bool FullyRemove) {
+ if (Mutex.shouldIgnore())
+ return;
+
const LockData *LDat = FSet.findLock(FactMan, Mutex);
if (!LDat) {
Handler.handleUnmatchedUnlock(Mutex.toString(), UnlockLoc);
@@ -1423,12 +1525,13 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
/// and push them onto Mtxs, discarding any duplicates.
template <typename AttrType>
void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
- Expr *Exp, const NamedDecl *D) {
+ Expr *Exp, const NamedDecl *D,
+ VarDecl *SelfDecl) {
typedef typename AttrType::args_iterator iterator_type;
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- SExpr Mu(0, Exp, D);
+ SExpr Mu(0, Exp, D, SelfDecl);
if (!Mu.isValid())
SExpr::warnInvalidLock(Handler, 0, Exp, D);
else
@@ -1437,7 +1540,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
}
for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
- SExpr Mu(*I, Exp, D);
+ SExpr Mu(*I, Exp, D, SelfDecl);
if (!Mu.isValid())
SExpr::warnInvalidLock(Handler, *I, Exp, D);
else
@@ -1512,6 +1615,9 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) {
return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
}
+ else if (const ExprWithCleanups* EWC = dyn_cast<ExprWithCleanups>(Cond)) {
+ return getTrylockCallExpr(EWC->getSubExpr(), C, Negate);
+ }
else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
return getTrylockCallExpr(E, C, Negate);
@@ -1591,7 +1697,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
case attr::SharedTrylockFunction: {
SharedTrylockFunctionAttr *A =
cast<SharedTrylockFunctionAttr>(Attr);
- getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
+ getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
PredBlock, CurrBlock, A->getSuccessValue(), Negate);
break;
}
@@ -1631,39 +1737,12 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
+ void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);
void checkAccess(Expr *Exp, AccessKind AK);
void checkDereference(Expr *Exp, AccessKind AK);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
- /// \brief Returns true if the lockset contains a lock, regardless of whether
- /// the lock is held exclusively or shared.
- bool locksetContains(const SExpr &Mu) const {
- return FSet.findLock(Analyzer->FactMan, Mu);
- }
-
- /// \brief Returns true if the lockset contains a lock with the passed in
- /// locktype.
- bool locksetContains(const SExpr &Mu, LockKind KindRequested) const {
- const LockData *LockHeld = FSet.findLock(Analyzer->FactMan, Mu);
- return (LockHeld && KindRequested == LockHeld->LKind);
- }
-
- /// \brief Returns true if the lockset contains a lock with at least the
- /// passed in locktype. So for example, if we pass in LK_Shared, this function
- /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
- /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
- bool locksetContainsAtLeast(const SExpr &Lock,
- LockKind KindRequested) const {
- switch (KindRequested) {
- case LK_Shared:
- return locksetContains(Lock);
- case LK_Exclusive:
- return locksetContains(Lock, KindRequested);
- }
- llvm_unreachable("Unknown LockKind");
- }
-
public:
BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
: StmtVisitor<BuildLockset>(),
@@ -1701,13 +1780,57 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
LockKind LK = getLockKindFromAccessKind(AK);
SExpr Mutex(MutexExp, Exp, D);
- if (!Mutex.isValid())
+ if (!Mutex.isValid()) {
SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
- else if (!locksetContainsAtLeast(Mutex, LK))
+ return;
+ } else if (Mutex.shouldIgnore()) {
+ return;
+ }
+
+ LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex);
+ bool NoError = true;
+ if (!LDat) {
+ // No exact match found. Look for a partial match.
+ FactEntry* FEntry = FSet.findPartialMatch(Analyzer->FactMan, Mutex);
+ if (FEntry) {
+ // Warn that there's no precise match.
+ LDat = &FEntry->LDat;
+ std::string PartMatchStr = FEntry->MutID.toString();
+ StringRef PartMatchName(PartMatchStr);
+ Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Exp->getExprLoc(), &PartMatchName);
+ } else {
+ // Warn that there's no match at all.
+ Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Exp->getExprLoc());
+ }
+ NoError = false;
+ }
+ // Make sure the mutex we found is the right kind.
+ if (NoError && LDat && !LDat->isAtLeast(LK))
Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
Exp->getExprLoc());
}
+/// \brief Warn if the LSet contains the given lock.
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
+ Expr *MutexExp) {
+ SExpr Mutex(MutexExp, Exp, D);
+ if (!Mutex.isValid()) {
+ SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
+ return;
+ }
+
+ LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);
+ if (LDat) {
+ std::string DeclName = D->getNameAsString();
+ StringRef DeclNameSR (DeclName);
+ Analyzer->Handler.handleFunExcludesLock(DeclNameSR, Mutex.toString(),
+ Exp->getExprLoc());
+ }
+}
+
+
/// \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.
@@ -1776,7 +1899,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// to our lockset with kind exclusive.
case attr::ExclusiveLockFunction: {
ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(At);
- Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D);
+ Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D, VD);
break;
}
@@ -1784,7 +1907,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// to our lockset with kind shared.
case attr::SharedLockFunction: {
SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(At);
- Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D);
+ Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D, VD);
break;
}
@@ -1792,7 +1915,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// mutexes from the lockset, and flag a warning if they are not there.
case attr::UnlockFunction: {
UnlockFunctionAttr *A = cast<UnlockFunctionAttr>(At);
- Analyzer->getMutexIDs(LocksToRemove, A, Exp, D);
+ Analyzer->getMutexIDs(LocksToRemove, A, Exp, D, VD);
break;
}
@@ -1816,15 +1939,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
case attr::LocksExcluded: {
LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
+
for (LocksExcludedAttr::args_iterator I = A->args_begin(),
E = A->args_end(); I != E; ++I) {
- SExpr Mutex(*I, Exp, D);
- if (!Mutex.isValid())
- SExpr::warnInvalidLock(Analyzer->Handler, *I, Exp, D);
- else if (locksetContains(Mutex))
- Analyzer->Handler.handleFunExcludesLock(D->getName(),
- Mutex.toString(),
- Exp->getExprLoc());
+ warnIfMutexHeld(D, Exp, *I);
}
break;
}
@@ -1973,8 +2091,8 @@ void BuildLockset::VisitDeclStmt(DeclStmt *S) {
/// are the same. In the event of a difference, we use the intersection of these
/// two locksets at the start of D.
///
-/// \param LSet1 The first lockset.
-/// \param LSet2 The second lockset.
+/// \param FSet1 The first lockset.
+/// \param FSet2 The second lockset.
/// \param JoinLoc The location of the join point for error reporting
/// \param LEK1 The error message to report if a mutex is missing from LSet1
/// \param LEK2 The error message to report if a mutex is missing from Lset2
@@ -2012,7 +2130,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat2.Managed)
+ else if (!LDat2.Managed && !FSet2Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
LDat2.AcquireLoc,
JoinLoc, LEK1);
@@ -2035,7 +2153,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat1.Managed)
+ else if (!LDat1.Managed && !FSet1Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
LDat1.AcquireLoc,
JoinLoc, LEK2);
@@ -2081,6 +2199,9 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+ // Mark entry block as reachable
+ BlockInfo[CFGraph->getEntry().getBlockID()].Reachable = true;
+
// Compute SSA names for local variables
LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
@@ -2168,10 +2289,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
continue;
+ int PrevBlockID = (*PI)->getBlockID();
+ CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
// Ignore edges from blocks that can't return.
- if ((*PI)->hasNoReturnElement())
+ if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable)
continue;
+ // Okay, we can reach this block from the entry.
+ CurrBlockInfo->Reachable = true;
+
// If the previous block ended in a 'continue' or 'break' statement, then
// a difference in locksets is probably due to a bug in that block, rather
// than in some other predecessor. In that case, keep the other
@@ -2183,8 +2310,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
- int PrevBlockID = (*PI)->getBlockID();
- CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
FactSet PrevLockset;
getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
@@ -2198,6 +2324,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
+ // Skip rest of block if it's not reachable.
+ if (!CurrBlockInfo->Reachable)
+ continue;
+
// Process continue and break blocks. Assume that the lockset for the
// resulting block is unaffected by any discrepancies in them.
for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
@@ -2287,6 +2417,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFGBlockInfo *Initial = &BlockInfo[CFGraph->getEntry().getBlockID()];
CFGBlockInfo *Final = &BlockInfo[CFGraph->getExit().getBlockID()];
+ // Skip the final check if the exit block is unreachable.
+ if (!Final->Reachable)
+ return;
+
// FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(Initial->EntrySet, Final->ExitSet,
Final->ExitLoc,
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 858be4561caf..b2e27cad1f39 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -13,6 +13,7 @@
#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"
@@ -22,6 +23,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -97,22 +99,21 @@ static bool isAlwaysUninit(const Value v) {
namespace {
-typedef llvm::PackedVector<Value, 2> ValueVector;
+typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
class CFGBlockValues {
const CFG &cfg;
- std::vector<ValueVector*> vals;
+ SmallVector<ValueVector, 8> vals;
ValueVector scratch;
DeclToIndex declToIndex;
public:
CFGBlockValues(const CFG &cfg);
- ~CFGBlockValues();
unsigned getNumEntries() const { return declToIndex.size(); }
void computeSetOfDeclarations(const DeclContext &dc);
ValueVector &getValueVector(const CFGBlock *block) {
- return *vals[block->getBlockID()];
+ return vals[block->getBlockID()];
}
void setAllScratchValues(Value V);
@@ -138,12 +139,6 @@ public:
CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
-CFGBlockValues::~CFGBlockValues() {
- for (std::vector<ValueVector*>::iterator I = vals.begin(), E = vals.end();
- I != E; ++I)
- delete *I;
-}
-
void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
declToIndex.computeMap(dc);
unsigned decls = declToIndex.size();
@@ -153,7 +148,7 @@ void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
return;
vals.resize(n);
for (unsigned i = 0; i < n; ++i)
- vals[i] = new ValueVector(decls);
+ vals[i].resize(decls);
}
#if DEBUG_LOGGING
@@ -412,6 +407,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
const CFGBlock *block;
AnalysisDeclContext &ac;
const ClassifyRefs &classification;
+ ObjCNoReturn objCNoRet;
UninitVariablesHandler *handler;
public:
@@ -420,16 +416,18 @@ public:
const ClassifyRefs &classification,
UninitVariablesHandler *handler)
: vals(vals), cfg(cfg), block(block), ac(ac),
- classification(classification), handler(handler) {}
+ classification(classification), objCNoRet(ac.getASTContext()),
+ handler(handler) {}
void reportUse(const Expr *ex, const VarDecl *vd);
- void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
+ void VisitBinaryOperator(BinaryOperator *bo);
void VisitBlockExpr(BlockExpr *be);
void VisitCallExpr(CallExpr *ce);
- void VisitDeclStmt(DeclStmt *ds);
void VisitDeclRefExpr(DeclRefExpr *dr);
- void VisitBinaryOperator(BinaryOperator *bo);
+ void VisitDeclStmt(DeclStmt *ds);
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
+ void VisitObjCMessageExpr(ObjCMessageExpr *ME);
bool isTrackedVar(const VarDecl *vd) {
return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
@@ -605,14 +603,26 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
}
void TransferFunctions::VisitCallExpr(CallExpr *ce) {
- // After a call to a function like setjmp or vfork, any variable which is
- // initialized anywhere within this function may now be initialized. For now,
- // just assume such a call initializes all variables.
- // FIXME: Only mark variables as initialized if they have an initializer which
- // is reachable from here.
- Decl *Callee = ce->getCalleeDecl();
- if (Callee && Callee->hasAttr<ReturnsTwiceAttr>())
- vals.setAllScratchValues(Initialized);
+ if (Decl *Callee = ce->getCalleeDecl()) {
+ if (Callee->hasAttr<ReturnsTwiceAttr>()) {
+ // After a call to a function like setjmp or vfork, any variable which is
+ // initialized anywhere within this function may now be initialized. For
+ // now, just assume such a call initializes all variables. FIXME: Only
+ // mark variables as initialized if they have an initializer which is
+ // reachable from here.
+ vals.setAllScratchValues(Initialized);
+ }
+ else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
+ // Functions labeled like "analyzer_noreturn" are often used to denote
+ // "panic" functions that in special debug situations can still return,
+ // but for the most part should not be treated as returning. This is a
+ // useful annotation borrowed from the static analyzer that is useful for
+ // suppressing branch-specific false positives when we call one of these
+ // functions but keep pretending the path continues (when in reality the
+ // user doesn't care).
+ vals.setAllScratchValues(Unknown);
+ }
+ }
}
void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
@@ -677,6 +687,14 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
}
}
+void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ // If the Objective-C message expression is an implicit no-return that
+ // is not modeled in the CFG, set the tracked dataflow values to Unknown.
+ if (objCNoRet.isImplicitNoReturn(ME)) {
+ vals.setAllScratchValues(Unknown);
+ }
+}
+
//------------------------------------------------------------------------====//
// High-level "driver" logic for uninitialized values analysis.
//====------------------------------------------------------------------------//
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
index 4793b251f603..d16965ddd872 100644
--- a/lib/Basic/ConvertUTF.c
+++ b/lib/Basic/ConvertUTF.c
@@ -111,7 +111,6 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
* into an inline function.
*/
-#ifdef CLANG_NEEDS_THESE_ONE_DAY
/* --------------------------------------------------------------------- */
@@ -285,7 +284,6 @@ ConversionResult ConvertUTF16toUTF8 (
*targetStart = target;
return result;
}
-#endif
/* --------------------------------------------------------------------- */
@@ -361,7 +359,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
@@ -395,15 +393,25 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
/* --------------------------------------------------------------------- */
/*
+ * 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))
+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;
+ *source += length;
}
return true;
}
diff --git a/lib/Basic/ConvertUTFWrapper.cpp b/lib/Basic/ConvertUTFWrapper.cpp
index a1b3f7fd9da3..6be3828d2868 100644
--- a/lib/Basic/ConvertUTFWrapper.cpp
+++ b/lib/Basic/ConvertUTFWrapper.cpp
@@ -13,16 +13,19 @@
namespace clang {
bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
- char *&ResultPtr) {
+ char *&ResultPtr, const UTF8 *&ErrorPtr) {
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
ConversionResult result = conversionOK;
// Copy the character span over.
if (WideCharWidth == 1) {
- if (!isLegalUTF8String(reinterpret_cast<const UTF8*>(Source.begin()),
- reinterpret_cast<const UTF8*>(Source.end())))
+ const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.begin());
+ if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.end()))) {
result = sourceIllegal;
- memcpy(ResultPtr, Source.data(), Source.size());
- ResultPtr += Source.size();
+ 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
@@ -34,6 +37,8 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
&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
@@ -45,6 +50,8 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
&targetStart, targetStart + 4*Source.size(), flags);
if (result == conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
+ else
+ ErrorPtr = sourceStart;
}
assert((result != targetExhausted)
&& "ConvertUTF8toUTFXX exhausted target buffer");
@@ -67,4 +74,3 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
}
} // end namespace clang
-
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 8065b2d98f32..854c4c56bb7f 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -12,9 +12,11 @@
//===----------------------------------------------------------------------===//
#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>
@@ -36,9 +38,10 @@ static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
DiagnosticsEngine::DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &diags,
+ DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client, bool ShouldOwnClient)
- : Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient),
- SourceMgr(0) {
+ : Diags(diags), DiagOpts(DiagOpts), Client(client),
+ OwnsDiagClient(ShouldOwnClient), SourceMgr(0) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
@@ -515,23 +518,7 @@ static void HandleOrdinalModifier(unsigned ValNo,
// We could use text forms for the first N ordinals, but the numeric
// forms are actually nicer in diagnostics because they stand out.
- Out << ValNo;
-
- // It is critically important that we do this perfectly for
- // user-written sequences with over 100 elements.
- switch (ValNo % 100) {
- case 11:
- case 12:
- case 13:
- Out << "th"; return;
- default:
- switch (ValNo % 10) {
- case 1: Out << "st"; return;
- case 2: Out << "nd"; return;
- case 3: Out << "rd"; return;
- default: Out << "th"; return;
- }
- }
+ Out << ValNo << llvm::getOrdinalSuffix(ValNo);
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index ca96fd2b9b24..ed976436e284 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -628,9 +628,9 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
if (DiagLevel >= DiagnosticIDs::Error) {
if (isUnrecoverable(DiagID))
Diag.UnrecoverableErrorOccurred = true;
-
+
+ Diag.ErrorOccurred = true;
if (Diag.Client->IncludeInDiagnosticCounts()) {
- Diag.ErrorOccurred = true;
++Diag.NumErrors;
}
@@ -686,4 +686,3 @@ bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
unsigned cat = getCategoryNumberForDiag(DiagID);
return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
}
-
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index c6b894c7e2fe..a816969b9144 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -36,6 +36,9 @@
#include <sys/uio.h>
#else
#include <io.h>
+#ifndef S_ISFIFO
+#define S_ISFIFO(x) (0)
+#endif
#endif
using namespace clang;
@@ -57,6 +60,10 @@ FileEntry::~FileEntry() {
if (FD != -1) ::close(FD);
}
+bool FileEntry::isNamedPipe() const {
+ return S_ISFIFO(FileMode);
+}
+
//===----------------------------------------------------------------------===//
// Windows.
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 4869ae1056be..1965bf99338b 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -17,7 +17,6 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <cctype>
@@ -33,6 +32,7 @@ IdentifierInfo::IdentifierInfo() {
TokenID = tok::identifier;
ObjCOrBuiltinID = 0;
HasMacro = false;
+ HadMacro = false;
IsExtension = false;
IsCXX11CompatKeyword = false;
IsPoisoned = false;
@@ -105,6 +105,7 @@ namespace {
KEYC11 = 0x400,
KEYARC = 0x800,
KEYNOMS = 0x01000,
+ WCHARSUPPORT = 0x02000,
KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude.
};
}
@@ -129,6 +130,7 @@ static void AddKeyword(StringRef Keyword,
else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
+ else if (LangOpts.WChar && (Flags & WCHARSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 634884074e14..76c7f8b364eb 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -23,8 +23,8 @@ using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
bool IsFramework, bool IsExplicit)
- : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
- Umbrella(), IsAvailable(true), IsFromModuleFile(false),
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
+ Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), NameVisibility(Hidden)
@@ -219,6 +219,13 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(Headers[I]->getName());
OS << "\"\n";
}
+
+ for (unsigned I = 0, N = ExcludedHeaders.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "exclude header \"";
+ OS.write_escaped(ExcludedHeaders[I]->getName());
+ OS << "\"\n";
+ }
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index bb5a10a9c7e4..0d62f7bb4b8c 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -61,6 +61,13 @@ void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{
OS << '>';
}
+std::string SourceLocation::printToString(const SourceManager &SM) const {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ print(OS, SM);
+ return S;
+}
+
void SourceLocation::dump(const SourceManager &SM) const {
print(llvm::errs(), SM);
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 9ec247429945..cd0284a18e5d 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -1029,6 +1029,17 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
return 1;
}
+ // 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) {
+ unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
+ unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
+ unsigned LineEnd = SourceLineCache[LastLineNoResult];
+ if (FilePos >= LineStart && FilePos < LineEnd)
+ return FilePos - LineStart + 1;
+ }
+
const char *Buf = MemBuf->getBufferStart();
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
@@ -1112,7 +1123,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
// Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'.
while (NextBuf+16 <= End) {
- __m128i Chunk = *(__m128i*)NextBuf;
+ const __m128i Chunk = *(const __m128i*)NextBuf;
__m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs),
_mm_cmpeq_epi8(Chunk, LFs));
unsigned Mask = _mm_movemask_epi8(Cmp);
@@ -1577,6 +1588,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
}
}
+ (void) SourceFile;
return FirstFID;
}
@@ -1693,46 +1705,91 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
if (!ExpInfo.isMacroArgExpansion())
continue;
- SourceLocation SpellLoc = ExpInfo.getSpellingLoc();
- while (!SpellLoc.isFileID()) {
- std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(SpellLoc);
- const ExpansionInfo &Info = getSLocEntry(LocInfo.first).getExpansion();
- if (!Info.isMacroArgExpansion())
- break;
- SpellLoc = Info.getSpellingLoc().getLocWithOffset(LocInfo.second);
+ associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
+ ExpInfo.getSpellingLoc(),
+ SourceLocation::getMacroLoc(Entry.getOffset()),
+ getFileIDSize(FileID::get(ID)));
+ }
+}
+
+void SourceManager::associateFileChunkWithMacroArgExp(
+ MacroArgsMap &MacroArgsCache,
+ FileID FID,
+ SourceLocation SpellLoc,
+ SourceLocation ExpansionLoc,
+ unsigned ExpansionLength) const {
+ if (!SpellLoc.isFileID()) {
+ unsigned SpellBeginOffs = SpellLoc.getOffset();
+ unsigned SpellEndOffs = SpellBeginOffs + ExpansionLength;
+
+ // The spelling range for this macro argument expansion can span multiple
+ // consecutive FileID entries. Go through each entry contained in the
+ // spelling range and if one is itself a macro argument expansion, recurse
+ // and associate the file chunk that it represents.
+
+ FileID SpellFID; // Current FileID in the spelling range.
+ unsigned SpellRelativeOffs;
+ llvm::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
+ while (1) {
+ const SLocEntry &Entry = getSLocEntry(SpellFID);
+ unsigned SpellFIDBeginOffs = Entry.getOffset();
+ unsigned SpellFIDSize = getFileIDSize(SpellFID);
+ unsigned SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize;
+ const ExpansionInfo &Info = Entry.getExpansion();
+ if (Info.isMacroArgExpansion()) {
+ unsigned CurrSpellLength;
+ if (SpellFIDEndOffs < SpellEndOffs)
+ CurrSpellLength = SpellFIDSize - SpellRelativeOffs;
+ else
+ CurrSpellLength = ExpansionLength;
+ associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
+ Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs),
+ ExpansionLoc, CurrSpellLength);
+ }
+
+ if (SpellFIDEndOffs >= SpellEndOffs)
+ return; // we covered all FileID entries in the spelling range.
+
+ // Move to the next FileID entry in the spelling range.
+ unsigned advance = SpellFIDSize - SpellRelativeOffs + 1;
+ ExpansionLoc = ExpansionLoc.getLocWithOffset(advance);
+ ExpansionLength -= advance;
+ ++SpellFID.ID;
+ SpellRelativeOffs = 0;
}
- if (!SpellLoc.isFileID())
- continue;
-
- unsigned BeginOffs;
- if (!isInFileID(SpellLoc, FID, &BeginOffs))
- continue;
- unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
-
- // Add a new chunk for this macro argument. A previous macro argument chunk
- // may have been lexed again, so e.g. if the map is
- // 0 -> SourceLocation()
- // 100 -> Expanded loc #1
- // 110 -> SourceLocation()
- // and we found a new macro FileID that lexed from offet 105 with length 3,
- // the new map will be:
- // 0 -> SourceLocation()
- // 100 -> Expanded loc #1
- // 105 -> Expanded loc #2
- // 108 -> Expanded loc #1
- // 110 -> SourceLocation()
- //
- // Since re-lexed macro chunks will always be the same size or less of
- // previous chunks, we only need to find where the ending of the new macro
- // chunk is mapped to and update the map with new begin/end mappings.
-
- MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
- --I;
- SourceLocation EndOffsMappedLoc = I->second;
- MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset());
- MacroArgsCache[EndOffs] = EndOffsMappedLoc;
}
+
+ assert(SpellLoc.isFileID());
+
+ unsigned BeginOffs;
+ if (!isInFileID(SpellLoc, FID, &BeginOffs))
+ return;
+
+ unsigned EndOffs = BeginOffs + ExpansionLength;
+
+ // Add a new chunk for this macro argument. A previous macro argument chunk
+ // may have been lexed again, so e.g. if the map is
+ // 0 -> SourceLocation()
+ // 100 -> Expanded loc #1
+ // 110 -> SourceLocation()
+ // and we found a new macro FileID that lexed from offet 105 with length 3,
+ // the new map will be:
+ // 0 -> SourceLocation()
+ // 100 -> Expanded loc #1
+ // 105 -> Expanded loc #2
+ // 108 -> Expanded loc #1
+ // 110 -> SourceLocation()
+ //
+ // Since re-lexed macro chunks will always be the same size or less of
+ // previous chunks, we only need to find where the ending of the new macro
+ // chunk is mapped to and update the map with new begin/end mappings.
+
+ MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
+ --I;
+ SourceLocation EndOffsMappedLoc = I->second;
+ MacroArgsCache[BeginOffs] = ExpansionLoc;
+ MacroArgsCache[EndOffs] = EndOffsMappedLoc;
}
/// \brief If \arg Loc points inside a function macro argument, the returned
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index db5941a5d921..83d4e2bf63c9 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -24,7 +24,8 @@ using namespace clang;
static const LangAS::Map DefaultAddrSpaceMap = { 0 };
// TargetInfo Constructor.
-TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
+TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T)
+{
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
// SPARC. These should be overridden by concrete targets as needed.
BigEndian = true;
@@ -59,6 +60,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
SigAtomicType = SignedInt;
+ ProcessIDType = SignedInt;
UseSignedCharForObjCBool = true;
UseBitFieldTypeAlignment = true;
UseZeroLengthBitfieldAlignment = false;
@@ -363,6 +365,8 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
break;
case '?': // Disparage slightly code.
case '!': // Disparage severely.
+ case '#': // Ignore as constraint.
+ case '*': // Ignore for choosing register preferences.
break; // Pass them.
}
@@ -482,6 +486,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
break;
case '?': // Disparage slightly code.
case '!': // Disparage severely.
+ case '#': // Ignore as constraint.
+ case '*': // Ignore for choosing register preferences.
break; // Pass them.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1d495f1f6412..f36ef826d0b2 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -92,6 +92,9 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
+ // AddressSanitizer doesn't play well with source fortification, which is on
+ // by default on Darwin.
+ if (Opts.SanitizeAddress) Builder.defineMacro("_FORTIFY_SOURCE", "0");
if (!Opts.ObjCAutoRefCount) {
// __weak is always defined, for use in blocks and with objc pointers.
@@ -316,7 +319,7 @@ protected:
DefineStd(Builder, "linux", Opts);
Builder.defineMacro("__gnu_linux__");
Builder.defineMacro("__ELF__");
- if (Triple.getEnvironment() == llvm::Triple::ANDROIDEABI)
+ if (Triple.getEnvironment() == llvm::Triple::Android)
Builder.defineMacro("__ANDROID__", "1");
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
@@ -587,6 +590,48 @@ public:
: OSTargetInfo<Target>(triple) {}
};
+template <typename Target>
+class NaClTargetInfo : public OSTargetInfo<Target> {
+ protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__native_client__");
+ }
+ public:
+ NaClTargetInfo(const std::string &triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ this->LongAlign = 32;
+ this->LongWidth = 32;
+ this->PointerAlign = 32;
+ this->PointerWidth = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->UIntMaxType = TargetInfo::UnsignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->DoubleAlign = 64;
+ this->LongDoubleWidth = 64;
+ this->LongDoubleAlign = 64;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->PtrDiffType = TargetInfo::SignedInt;
+ this->IntPtrType = TargetInfo::SignedInt;
+ this->RegParmMax = 2;
+ this->LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
+ }
+ virtual typename Target::CallingConvCheckResult checkCallingConvention(
+ CallingConv CC) const {
+ return CC == CC_PnaclCall ? Target::CCCR_OK :
+ Target::checkCallingConvention(CC);
+ }
+};
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -641,6 +686,8 @@ public:
.Case("970", true)
.Case("g5", true)
.Case("a2", true)
+ .Case("e500mc", true)
+ .Case("e5500", true)
.Case("pwr6", true)
.Case("pwr7", true)
.Case("ppc", true)
@@ -990,6 +1037,9 @@ public:
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
+
+ // PPC32 supports atomics up to 4 bytes.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
virtual BuiltinVaListKind getBuiltinVaListKind() const {
@@ -1007,13 +1057,20 @@ public:
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
Int64Type = 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-v128:128:128-n32:64";
if (getTriple().getOS() == llvm::Triple::FreeBSD) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
- }
+ DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-f128:64:64-"
+ "v128:128:128-n32:64";
+ } else
+ DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
+ "v128:128:128-n32:64";
+
+ // PPC64 supports atomics up to 8 bytes.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual BuiltinVaListKind getBuiltinVaListKind() const {
return TargetInfo::CharPtrBuiltinVaList;
@@ -1047,6 +1104,8 @@ public:
: DarwinTargetInfo<PPC64TargetInfo>(triple) {
HasAlignMac68kSupport = true;
SuitableAlign = 128;
+ DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
}
};
} // end anonymous namespace.
@@ -1172,6 +1231,71 @@ namespace {
}
namespace {
+
+static const unsigned R600AddrSpaceMap[] = {
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+
+class R600TargetInfo : public TargetInfo {
+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";
+ AddrSpaceMap = &R600AddrSpaceMap;
+ }
+
+ virtual const char * getClobbers() const {
+ return "";
+ }
+
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &numNames) const {
+ Names = NULL;
+ numNames = 0;
+ }
+
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = NULL;
+ NumAliases = 0;
+ }
+
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ return true;
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = NULL;
+ NumRecords = 0;
+ }
+
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__R600__");
+ }
+
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+};
+
+} // end anonymous namespace
+
+namespace {
// MBlaze abstract base class
class MBlazeTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
@@ -1351,10 +1475,12 @@ class X86TargetInfo : public TargetInfo {
bool HasBMI;
bool HasBMI2;
bool HasPOPCNT;
+ bool HasRTM;
bool HasSSE4a;
bool HasFMA4;
bool HasFMA;
bool HasXOP;
+ bool HasF16C;
/// \brief Enumeration of all of the X86 CPUs supported by Clang.
///
@@ -1500,8 +1626,9 @@ public:
X86TargetInfo(const std::string& triple)
: TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
HasAES(false), HasPCLMUL(false), HasLZCNT(false), HasRDRND(false),
- HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasSSE4a(false),
- HasFMA4(false), HasFMA(false), HasXOP(false), CPU(CK_Generic) {
+ HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false),
+ HasSSE4a(false), HasFMA4(false), HasFMA(false), HasXOP(false),
+ HasF16C(false), CPU(CK_Generic) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1544,9 +1671,10 @@ public:
virtual bool hasFeature(StringRef Feature) const;
virtual void HandleTargetFeatures(std::vector<std::string> &Features);
virtual const char* getABI() const {
- if (PointerWidth == 64 && SSELevel >= AVX)
+ if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
return "avx";
- else if (PointerWidth == 32 && MMX3DNowLevel == NoMMX3DNow)
+ else if (getTriple().getArch() == llvm::Triple::x86 &&
+ MMX3DNowLevel == NoMMX3DNow)
return "no-mmx";
return "";
}
@@ -1640,7 +1768,7 @@ public:
case CK_AthlonMP:
case CK_Geode:
// Only accept certain architectures when compiling in 32-bit mode.
- if (PointerWidth != 32)
+ if (getTriple().getArch() != llvm::Triple::x86)
return false;
// Fallthrough
@@ -1668,6 +1796,19 @@ public:
}
llvm_unreachable("Unhandled CPU kind");
}
+
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ // We accept all non-ARM calling conventions
+ return (CC == CC_X86ThisCall ||
+ CC == CC_X86FastCall ||
+ CC == CC_X86StdCall ||
+ CC == CC_C ||
+ CC == CC_X86Pascal) ? CCCR_OK : CCCR_Warning;
+ }
+
+ virtual CallingConv getDefaultCallingConv() const {
+ return CC_C;
+ }
};
void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
@@ -1691,14 +1832,16 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features["bmi"] = false;
Features["bmi2"] = false;
Features["popcnt"] = false;
+ Features["rtm"] = false;
Features["fma4"] = false;
Features["fma"] = false;
Features["xop"] = false;
+ Features["f16c"] = false;
// FIXME: This *really* should not be here.
// X86_64 always has SSE2.
- if (PointerWidth == 64)
+ if (getTriple().getArch() == llvm::Triple::x86_64)
Features["sse2"] = Features["sse"] = Features["mmx"] = true;
switch (CPU) {
@@ -1770,6 +1913,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabled(Features, "rdrnd", true);
setFeatureEnabled(Features, "bmi", true);
setFeatureEnabled(Features, "bmi2", true);
+ setFeatureEnabled(Features, "rtm", true);
setFeatureEnabled(Features, "fma", true);
break;
case CK_K6:
@@ -1904,6 +2048,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["bmi2"] = true;
else if (Name == "popcnt")
Features["popcnt"] = true;
+ else if (Name == "f16c")
+ Features["f16c"] = true;
+ else if (Name == "rtm")
+ Features["rtm"] = true;
} else {
if (Name == "mmx")
Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
@@ -1964,6 +2112,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["fma4"] = Features["xop"] = false;
else if (Name == "xop")
Features["xop"] = false;
+ else if (Name == "f16c")
+ Features["f16c"] = false;
+ else if (Name == "rtm")
+ Features["rtm"] = false;
}
return true;
@@ -2015,6 +2167,11 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
+ if (Feature == "rtm") {
+ HasRTM = true;
+ continue;
+ }
+
if (Feature == "sse4a") {
HasSSE4a = true;
continue;
@@ -2035,6 +2192,11 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
+ if (Feature == "f16c") {
+ HasF16C = true;
+ continue;
+ }
+
assert(Features[i][0] == '+' && "Invalid target feature!");
X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
.Case("avx2", AVX2)
@@ -2071,7 +2233,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
- if (PointerWidth == 64) {
+ if (getTriple().getArch() == llvm::Triple::x86_64) {
Builder.defineMacro("__amd64__");
Builder.defineMacro("__amd64");
Builder.defineMacro("__x86_64");
@@ -2231,6 +2393,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasPOPCNT)
Builder.defineMacro("__POPCNT__");
+ if (HasRTM)
+ Builder.defineMacro("__RTM__");
+
if (HasSSE4a)
Builder.defineMacro("__SSE4A__");
@@ -2243,6 +2408,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasXOP)
Builder.defineMacro("__XOP__");
+ if (HasF16C)
+ Builder.defineMacro("__F16C__");
+
// Each case falls through to the previous one here.
switch (SSELevel) {
case AVX2:
@@ -2267,7 +2435,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
break;
}
- if (Opts.MicrosoftExt && PointerWidth == 32) {
+ if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) {
switch (SSELevel) {
case AVX2:
case AVX:
@@ -2315,6 +2483,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("mmx", MMX3DNowLevel >= MMX)
.Case("pclmul", HasPCLMUL)
.Case("popcnt", HasPOPCNT)
+ .Case("rtm", HasRTM)
.Case("sse", SSELevel >= SSE1)
.Case("sse2", SSELevel >= SSE2)
.Case("sse3", SSELevel >= SSE3)
@@ -2323,9 +2492,10 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("sse42", SSELevel >= SSE42)
.Case("sse4a", HasSSE4a)
.Case("x86", true)
- .Case("x86_32", PointerWidth == 32)
- .Case("x86_64", PointerWidth == 64)
+ .Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
+ .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
.Case("xop", HasXOP)
+ .Case("f16c", HasF16C)
.Default(false);
}
@@ -2595,7 +2765,9 @@ public:
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
+ ProcessIDType = SignedLong;
this->UserLabelPrefix = "";
+ this->TLSSupported = false;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -2703,6 +2875,15 @@ public:
if (RegNo == 1) return 1;
return -1;
}
+
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ return TargetInfo::checkCallingConvention(CC);
+ }
+
+ virtual CallingConv getDefaultCallingConv() const {
+ return CC_Default;
+ }
+
};
} // end anonymous namespace
@@ -2820,14 +3001,14 @@ namespace {
class ARMTargetInfo : public TargetInfo {
// Possible FPU choices.
enum FPUMode {
- NoFPU,
- VFP2FPU,
- VFP3FPU,
- NeonFPU
+ VFP2FPU = (1 << 0),
+ VFP3FPU = (1 << 1),
+ VFP4FPU = (1 << 2),
+ NeonFPU = (1 << 3)
};
static bool FPUModeIsVFP(FPUMode Mode) {
- return Mode >= VFP2FPU && Mode <= NeonFPU;
+ return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU);
}
static const TargetInfo::GCCRegAlias GCCRegAliases[];
@@ -2835,8 +3016,9 @@ class ARMTargetInfo : public TargetInfo {
std::string ABI, CPU;
- unsigned FPU : 3;
+ unsigned FPU : 4;
+ unsigned IsAAPCS : 1;
unsigned IsThumb : 1;
// Initialized via features.
@@ -2847,7 +3029,7 @@ class ARMTargetInfo : public TargetInfo {
public:
ARMTargetInfo(const std::string &TripleStr)
- : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s")
+ : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true)
{
BigEndian = false;
SizeType = UnsignedInt;
@@ -2910,6 +3092,8 @@ public:
/// gcc.
ZeroLengthBitfieldBoundary = 32;
+ IsAAPCS = false;
+
if (IsThumb) {
// Thumb1 add sp, #imm requires the immediate value be multiple of 4,
// so set preferred for small types to 32.
@@ -2923,10 +3107,11 @@ public:
}
// FIXME: Override "preferred align" for double and long long.
- } else if (Name == "aapcs") {
+ } else if (Name == "aapcs" || Name == "aapcs-vfp") {
+ IsAAPCS = true;
// FIXME: Enumerated types are variable width in straight AAPCS.
} else if (Name == "aapcs-linux") {
- ;
+ IsAAPCS = true;
} else
return false;
@@ -2936,16 +3121,21 @@ public:
void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
- else if (CPU == "cortex-a8" || CPU == "cortex-a9")
+ else if (CPU == "cortex-a8" || CPU == "cortex-a15" ||
+ CPU == "cortex-a9" || CPU == "cortex-a9-mp")
+ Features["neon"] = true;
+ else if (CPU == "swift") {
+ Features["vfp4"] = true;
Features["neon"] = true;
+ }
}
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
StringRef Name,
bool Enabled) const {
if (Name == "soft-float" || Name == "soft-float-abi" ||
- Name == "vfp2" || Name == "vfp3" || Name == "neon" || Name == "d16" ||
- Name == "neonfp") {
+ Name == "vfp2" || Name == "vfp3" || Name == "vfp4" || Name == "neon" ||
+ Name == "d16" || Name == "neonfp") {
Features[Name] = Enabled;
} else
return false;
@@ -2954,7 +3144,7 @@ public:
}
virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
- FPU = NoFPU;
+ FPU = 0;
SoftFloat = SoftFloatABI = false;
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
if (Features[i] == "+soft-float")
@@ -2962,11 +3152,13 @@ public:
else if (Features[i] == "+soft-float-abi")
SoftFloatABI = true;
else if (Features[i] == "+vfp2")
- FPU = VFP2FPU;
+ FPU |= VFP2FPU;
else if (Features[i] == "+vfp3")
- FPU = VFP3FPU;
+ FPU |= VFP3FPU;
+ else if (Features[i] == "+vfp4")
+ FPU |= VFP4FPU;
else if (Features[i] == "+neon")
- FPU = NeonFPU;
+ FPU |= NeonFPU;
}
// Remove front-end specific options which the backend handles differently.
@@ -2988,6 +3180,7 @@ public:
StringRef(getCPUDefineSuffix(CPU)).startswith("7"))
.Default(false);
}
+ // FIXME: Should we actually have some table instead of these switches?
static const char *getCPUDefineSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
.Cases("arm8", "arm810", "4")
@@ -3004,12 +3197,19 @@ public:
.Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a8", "cortex-a9", "7A")
- .Case("cortex-m3", "7M")
- .Case("cortex-m4", "7M")
+ .Cases("cortex-a8", "cortex-a9", "cortex-a15", "7A")
+ .Case("cortex-a9-mp", "7F")
+ .Case("swift", "7S")
+ .Cases("cortex-m3", "cortex-m4", "7M")
.Case("cortex-m0", "6M")
.Default(0);
}
+ static const char *getCPUProfile(StringRef Name) {
+ return llvm::StringSwitch<const char*>(Name)
+ .Cases("cortex-a8", "cortex-a9", "A")
+ .Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
+ .Default("");
+ }
virtual bool setCPU(const std::string &Name) {
if (!getCPUDefineSuffix(Name))
return false;
@@ -3030,7 +3230,11 @@ public:
StringRef CPUArch = getCPUDefineSuffix(CPU);
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
-
+ Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
+ StringRef CPUProfile = getCPUProfile(CPU);
+ if (!CPUProfile.empty())
+ Builder.defineMacro("__ARM_ARCH_PROFILE", CPUProfile);
+
// Subtarget options.
// FIXME: It's more complicated than this and we don't really support
@@ -3038,8 +3242,15 @@ public:
if ('5' <= CPUArch[0] && CPUArch[0] <= '7')
Builder.defineMacro("__THUMB_INTERWORK__");
- if (ABI == "aapcs" || ABI == "aapcs-linux")
- Builder.defineMacro("__ARM_EABI__");
+ if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
+ // M-class CPUs on Darwin follow AAPCS, but not EABI.
+ if (!(getTriple().isOSDarwin() && CPUProfile == "M"))
+ Builder.defineMacro("__ARM_EABI__");
+ Builder.defineMacro("__ARM_PCS", "1");
+
+ if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp")
+ Builder.defineMacro("__ARM_PCS_VFP", "1");
+ }
if (SoftFloat)
Builder.defineMacro("__SOFTFP__");
@@ -3058,14 +3269,21 @@ public:
// Note, this is always on in gcc, even though it doesn't make sense.
Builder.defineMacro("__APCS_32__");
- if (FPUModeIsVFP((FPUMode) FPU))
+ if (FPUModeIsVFP((FPUMode) FPU)) {
Builder.defineMacro("__VFP_FP__");
-
+ if (FPU & VFP2FPU)
+ Builder.defineMacro("__ARM_VFPV2__");
+ if (FPU & VFP3FPU)
+ Builder.defineMacro("__ARM_VFPV3__");
+ if (FPU & VFP4FPU)
+ Builder.defineMacro("__ARM_VFPV4__");
+ }
+
// This only gets set when Neon instructions are actually available, unlike
// the VFP define, hence the soft float and arch check. This is subtly
// different from gcc, we follow the intent which was that it should be set
// when Neon instructions are actually available.
- if (FPU == NeonFPU && !SoftFloat && IsARMv7)
+ if ((FPU & NeonFPU) && !SoftFloat && IsARMv7)
Builder.defineMacro("__ARM_NEON__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -3075,7 +3293,7 @@ public:
}
virtual bool isCLZForZeroUndef() const { return false; }
virtual BuiltinVaListKind getBuiltinVaListKind() const {
- return TargetInfo::VoidPtrBuiltinVaList;
+ return IsAAPCS ? AAPCSABIBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList;
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
@@ -3127,10 +3345,38 @@ public:
}
return R;
}
+ virtual bool validateConstraintModifier(StringRef Constraint,
+ const char Modifier,
+ unsigned Size) const {
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' ||
+ Constraint[0] == '+' ||
+ Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ switch (Constraint[0]) {
+ default: break;
+ case 'r': {
+ switch (Modifier) {
+ default:
+ return Size == 32;
+ case 'q':
+ // A register of size 32 cannot fit a vector type.
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
virtual const char *getClobbers() const {
// FIXME: Is this really right?
return "";
}
+
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning;
+ }
};
const char * const ARMTargetInfo::GCCRegNames[] = {
@@ -3701,8 +3947,12 @@ public:
Features[CPU] = true;
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+
switch (FloatABI) {
case HardFloat:
Builder.defineMacro("__mips_hard_float", Twine(1));
@@ -3736,10 +3986,11 @@ public:
Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
+
+ Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\"");
+ Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const = 0;
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
Records = BuiltinInfo;
@@ -3859,9 +4110,9 @@ public:
} else
return false;
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- MipsTargetInfoBase::getArchDefines(Opts, Builder);
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ MipsTargetInfoBase::getTargetDefines(Opts, Builder);
if (ABI == "o32") {
Builder.defineMacro("__mips_o32");
@@ -3921,12 +4172,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips32TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
@@ -3939,12 +4187,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips32TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
@@ -3974,9 +4219,12 @@ public:
return true;
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- MipsTargetInfoBase::getArchDefines(Opts, Builder);
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ MipsTargetInfoBase::getTargetDefines(Opts, Builder);
+
+ Builder.defineMacro("__mips64");
+ Builder.defineMacro("__mips64__");
if (ABI == "n32") {
Builder.defineMacro("__mips_n32");
@@ -4048,12 +4296,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
@@ -4075,12 +4320,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
} // end anonymous namespace.
@@ -4118,15 +4360,7 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
-
Builder.defineMacro("__LITTLE_ENDIAN__");
- Builder.defineMacro("__native_client__");
getArchDefines(Opts, Builder);
}
virtual bool hasFeature(StringRef Feature) const {
@@ -4199,6 +4433,8 @@ 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:
+ return new NaClTargetInfo<ARMTargetInfo>(T);
default:
return new ARMTargetInfo(T);
}
@@ -4269,7 +4505,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::le32:
switch (os) {
case llvm::Triple::NativeClient:
- return new PNaClTargetInfo(T);
+ return new NaClTargetInfo<PNaClTargetInfo>(T);
default:
return NULL;
}
@@ -4316,6 +4552,9 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::mblaze:
return new MBlazeTargetInfo(T);
+ case llvm::Triple::r600:
+ return new R600TargetInfo(T);
+
case llvm::Triple::sparc:
switch (os) {
case llvm::Triple::Linux:
@@ -4374,6 +4613,8 @@ 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:
+ return new NaClTargetInfo<X86_32TargetInfo>(T);
default:
return new X86_32TargetInfo(T);
}
@@ -4403,6 +4644,8 @@ 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:
+ return new NaClTargetInfo<X86_64TargetInfo>(T);
default:
return new X86_64TargetInfo(T);
}
@@ -4421,6 +4664,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Diags.Report(diag::err_target_unknown_triple) << Triple.str();
return 0;
}
+ Target->setTargetOpts(Opts);
// Set the target CPU if specified.
if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) {
@@ -4447,8 +4691,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Apply the user specified deltas.
// First the enables.
- for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
- ie = Opts.Features.end(); it != ie; ++it) {
+ for (std::vector<std::string>::const_iterator
+ it = Opts.FeaturesAsWritten.begin(),
+ ie = Opts.FeaturesAsWritten.end();
+ it != ie; ++it) {
const char *Name = it->c_str();
if (Name[0] != '+')
@@ -4462,8 +4708,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
}
// Then the disables.
- for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
- ie = Opts.Features.end(); it != ie; ++it) {
+ for (std::vector<std::string>::const_iterator
+ it = Opts.FeaturesAsWritten.begin(),
+ ie = Opts.FeaturesAsWritten.end();
+ it != ie; ++it) {
const char *Name = it->c_str();
if (Name[0] == '+')
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 9daa30a4cad0..286e96e0f376 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -32,7 +32,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/trunk/lib/Basic/Version.cpp $");
+ static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_32/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 86f53803d527..da6d035dfaf0 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -16,7 +16,7 @@
namespace llvm {
class Value;
class LLVMContext;
- class TargetData;
+ class DataLayout;
}
namespace clang {
@@ -70,46 +70,52 @@ namespace clang {
private:
Kind TheKind;
llvm::Type *TypeData;
- llvm::Type *PaddingType; // Currently allowed only for Direct.
+ llvm::Type *PaddingType;
unsigned UIntData;
bool BoolData0;
bool BoolData1;
bool InReg;
+ bool PaddingInReg;
ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR,
- llvm::Type* P)
+ bool PIR, llvm::Type* P)
: TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
- BoolData1(B1), InReg(IR) {}
+ BoolData1(B1), InReg(IR), PaddingInReg(PIR) {}
public:
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
llvm::Type *Padding = 0) {
- return ABIArgInfo(Direct, T, Offset, false, false, false, Padding);
+ return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding);
}
- static ABIArgInfo getDirectInReg(llvm::Type *T) {
- return ABIArgInfo(Direct, T, 0, false, false, true, 0);
+ static ABIArgInfo getDirectInReg(llvm::Type *T = 0) {
+ return ABIArgInfo(Direct, T, 0, false, false, true, false, 0);
}
static ABIArgInfo getExtend(llvm::Type *T = 0) {
- return ABIArgInfo(Extend, T, 0, false, false, false, 0);
+ return ABIArgInfo(Extend, T, 0, false, false, false, false, 0);
}
static ABIArgInfo getExtendInReg(llvm::Type *T = 0) {
- return ABIArgInfo(Extend, T, 0, false, false, true, 0);
+ return ABIArgInfo(Extend, T, 0, false, false, true, false, 0);
}
static ABIArgInfo getIgnore() {
- return ABIArgInfo(Ignore, 0, 0, false, false, false, 0);
+ 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, 0);
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0);
}
static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, 0);
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0);
}
static ABIArgInfo getExpand() {
- return ABIArgInfo(Expand, 0, 0, false, false, false, 0);
+ return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0);
+ }
+ static ABIArgInfo getExpandWithPadding(bool PaddingInReg,
+ llvm::Type *Padding) {
+ return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg,
+ Padding);
}
Kind getKind() const { return TheKind; }
@@ -133,6 +139,10 @@ namespace clang {
return PaddingType;
}
+ bool getPaddingInReg() const {
+ return PaddingInReg;
+ }
+
llvm::Type *getCoerceToType() const {
assert(canHaveCoerceToType() && "Invalid kind!");
return TypeData;
@@ -178,7 +188,7 @@ namespace clang {
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
- const llvm::TargetData &getTargetData() const;
+ const llvm::DataLayout &getDataLayout() const;
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 0a1915b485d7..62f87c983bfa 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -27,7 +27,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@@ -54,36 +54,67 @@ class EmitAssemblyHelper {
mutable FunctionPassManager *PerFunctionPasses;
private:
- PassManager *getCodeGenPasses() const {
+ PassManager *getCodeGenPasses(TargetMachine *TM) const {
if (!CodeGenPasses) {
CodeGenPasses = new PassManager();
- CodeGenPasses->add(new TargetData(TheModule));
+ CodeGenPasses->add(new DataLayout(TheModule));
+ // Add TargetTransformInfo.
+ if (TM) {
+ TargetTransformInfo *TTI =
+ new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo());
+ CodeGenPasses->add(TTI);
+ }
}
return CodeGenPasses;
}
- PassManager *getPerModulePasses() const {
+ PassManager *getPerModulePasses(TargetMachine *TM) const {
if (!PerModulePasses) {
PerModulePasses = new PassManager();
- PerModulePasses->add(new TargetData(TheModule));
+ PerModulePasses->add(new DataLayout(TheModule));
+ if (TM) {
+ TargetTransformInfo *TTI =
+ new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo());
+ PerModulePasses->add(TTI);
+ }
}
return PerModulePasses;
}
- FunctionPassManager *getPerFunctionPasses() const {
+ FunctionPassManager *getPerFunctionPasses(TargetMachine *TM) const {
if (!PerFunctionPasses) {
PerFunctionPasses = new FunctionPassManager(TheModule);
- PerFunctionPasses->add(new TargetData(TheModule));
+ PerFunctionPasses->add(new DataLayout(TheModule));
+ if (TM) {
+ TargetTransformInfo *TTI =
+ new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo());
+ PerFunctionPasses->add(TTI);
+ }
}
return PerFunctionPasses;
}
- void CreatePasses();
+
+ void CreatePasses(TargetMachine *TM);
+
+ /// CreateTargetMachine - Generates the TargetMachine.
+ /// Returns Null if it is unable to create the target machine.
+ /// Some of our clang tests specify triples which are not built
+ /// into clang. This is okay because these tests check the generated
+ /// IR, and they require DataLayout which depends on the triple.
+ /// In this case, we allow this method to fail and not report an error.
+ /// When MustCreateTM is used, we print an error if we are unable to load
+ /// the requested target.
+ TargetMachine *CreateTargetMachine(bool MustCreateTM);
/// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
///
/// \return True on success.
- bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS);
+ bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS,
+ TargetMachine *TM);
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags,
@@ -137,9 +168,9 @@ static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PM.add(createThreadSanitizerPass());
}
-void EmitAssemblyHelper::CreatePasses() {
+void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
- CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;
+ CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining();
// Handle disabling of LLVM optimization, where we want to preserve the
// internal module before any optimization.
@@ -174,14 +205,14 @@ void EmitAssemblyHelper::CreatePasses() {
addBoundsCheckingPass);
}
- if (LangOpts.AddressSanitizer) {
- PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
+ if (LangOpts.SanitizeAddress) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addAddressSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addAddressSanitizerPass);
}
- if (LangOpts.ThreadSanitizer) {
+ if (LangOpts.SanitizeThread) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addThreadSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
@@ -218,38 +249,36 @@ void EmitAssemblyHelper::CreatePasses() {
break;
}
-
// Set up the per-function pass manager.
- FunctionPassManager *FPM = getPerFunctionPasses();
+ FunctionPassManager *FPM = getPerFunctionPasses(TM);
if (CodeGenOpts.VerifyModule)
FPM->add(createVerifierPass());
PMBuilder.populateFunctionPassManager(*FPM);
// Set up the per-module pass manager.
- PassManager *MPM = getPerModulePasses();
+ PassManager *MPM = getPerModulePasses(TM);
if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
CodeGenOpts.EmitGcovArcs,
TargetTriple.isMacOSX()));
- if (CodeGenOpts.DebugInfo == CodeGenOptions::NoDebugInfo)
+ if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
MPM->add(createStripSymbolsPass(true));
}
-
-
+
PMBuilder.populateModulePassManager(*MPM);
}
-bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
- formatted_raw_ostream &OS) {
+TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
// Create the TargetMachine for generating code.
std::string Error;
std::string Triple = TheModule->getTargetTriple();
const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
if (!TheTarget) {
- Diags.Report(diag::err_fe_unable_to_create_target) << Error;
- return false;
+ if (MustCreateTM)
+ Diags.Report(diag::err_fe_unable_to_create_target) << Error;
+ return 0;
}
// FIXME: Expose these capabilities via actual APIs!!!! Aside from just
@@ -361,7 +390,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
break;
case LangOptions::FPC_Fast:
Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
- break;
+ break;
}
Options.LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD;
@@ -375,6 +404,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
Options.DisableTailCalls = CodeGenOpts.DisableTailCalls;
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
+ Options.SSPBufferSize = CodeGenOpts.SSPBufferSize;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
@@ -391,15 +421,27 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
if (CodeGenOpts.NoExecStack)
TM->setMCNoExecStack(true);
+ return TM;
+}
+
+bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
+ formatted_raw_ostream &OS,
+ TargetMachine *TM) {
+
// Create the code generator passes.
- PassManager *PM = getCodeGenPasses();
+ PassManager *PM = getCodeGenPasses(TM);
// Add LibraryInfo.
- TargetLibraryInfo *TLI = new TargetLibraryInfo();
+ llvm::Triple TargetTriple(TheModule->getTargetTriple());
+ TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
TLI->disableAllFunctions();
PM->add(TLI);
+ // Add TargetTransformInfo.
+ PM->add(new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo()));
+
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
@@ -430,23 +472,28 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);
llvm::formatted_raw_ostream FormattedOS;
- CreatePasses();
+ bool UsesCodeGen = (Action != Backend_EmitNothing &&
+ Action != Backend_EmitBC &&
+ Action != Backend_EmitLL);
+ TargetMachine *TM = CreateTargetMachine(UsesCodeGen);
+ CreatePasses(TM);
+
switch (Action) {
case Backend_EmitNothing:
break;
case Backend_EmitBC:
- getPerModulePasses()->add(createBitcodeWriterPass(*OS));
+ getPerModulePasses(TM)->add(createBitcodeWriterPass(*OS));
break;
case Backend_EmitLL:
FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- getPerModulePasses()->add(createPrintModulePass(&FormattedOS));
+ getPerModulePasses(TM)->add(createPrintModulePass(&FormattedOS));
break;
default:
FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- if (!AddEmitPasses(Action, FormattedOS))
+ if (!AddEmitPasses(Action, FormattedOS, TM))
return;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 37ef4af24690..6742f36cf80f 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <algorithm>
using namespace clang;
@@ -27,7 +27,8 @@ using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), UsesStret(false), StructureType(0), Block(block),
+ HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
+ StructureType(0), Block(block),
DominatingIP(0) {
// Skip asm prefix, if any. 'name' is usually taken directly from
@@ -56,7 +57,18 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
}
-/// Build the block descriptor constant for a block.
+/// buildBlockDescriptor - Build the block descriptor meta-data for a block.
+/// buildBlockDescriptor is accessed from 5th field of the Block_literal
+/// meta-data and contains stationary information about the block literal.
+/// Its definition will have 4 (or optinally 6) words.
+/// struct Block_descriptor {
+/// unsigned long reserved;
+/// unsigned long size; // size of Block_literal metadata in bytes.
+/// void *copy_func_helper_decl; // optional copy helper.
+/// void *destroy_func_decl; // optioanl destructor helper.
+/// void *block_method_encoding_address;//@encode for block literal signature.
+/// void *block_layout_info; // encoding of captured block variables.
+/// };
static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
ASTContext &C = CGM.getContext();
@@ -92,8 +104,12 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
CGM.GetAddrOfConstantCString(typeAtEncoding), i8p));
// GC layout.
- if (C.getLangOpts().ObjC1)
- elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
+ if (C.getLangOpts().ObjC1) {
+ if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
+ elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
+ else
+ elements.push_back(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo));
+ }
else
elements.push_back(llvm::Constant::getNullValue(i8p));
@@ -293,7 +309,10 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
info.CanBeGlobal = true;
return;
}
-
+ else if (C.getLangOpts().ObjC1 &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC)
+ info.HasCapturedVariableLayout = true;
+
// Collect the layout chunks.
SmallVector<BlockLayoutChunk, 16> layout;
layout.reserve(block->capturesCXXThis() +
@@ -652,6 +671,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// Compute the initial on-stack block flags.
BlockFlags flags = BLOCK_HAS_SIGNATURE;
+ if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT;
if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ;
if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
@@ -1001,8 +1021,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
// Check if we should generate debug info for this block function.
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
+ maybeInitializeDebugInfo();
CurGD = GD;
BlockInfo = &blockInfo;
@@ -1135,7 +1154,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const VarDecl *variable = ci->getVariable();
DI->EmitLocation(Builder, variable->getLocation());
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) {
DI->EmitDeclareOfAutoVariable(variable, LocalDeclMap[variable],
@@ -1207,8 +1227,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
= &CGM.getContext().Idents.get("__copy_helper_block_");
// Check if we should generate debug info for this block helper function.
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
+ maybeInitializeDebugInfo();
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
@@ -1243,7 +1262,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
const Expr *copyExpr = ci->getCopyExpr();
BlockFieldFlags flags;
- bool isARCWeakCapture = false;
+ bool useARCWeakCopy = false;
+ bool useARCStrongCopy = false;
if (copyExpr) {
assert(!ci->isByRef());
@@ -1256,21 +1276,35 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
} else if (type->isObjCRetainableType()) {
flags = BLOCK_FIELD_IS_OBJECT;
- if (type->isBlockPointerType())
+ bool isBlockPointer = type->isBlockPointerType();
+ if (isBlockPointer)
flags = BLOCK_FIELD_IS_BLOCK;
// Special rules for ARC captures:
if (getLangOpts().ObjCAutoRefCount) {
Qualifiers qs = type.getQualifiers();
- // Don't generate special copy logic for a captured object
- // unless it's __strong or __weak.
- if (!qs.hasStrongOrWeakObjCLifetime())
+ // We need to register __weak direct captures with the runtime.
+ if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) {
+ useARCWeakCopy = true;
+
+ // We need to retain the copied value for __strong direct captures.
+ } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // If it's a block pointer, we have to copy the block and
+ // assign that to the destination pointer, so we might as
+ // well use _Block_object_assign. Otherwise we can avoid that.
+ if (!isBlockPointer)
+ useARCStrongCopy = true;
+
+ // Otherwise the memcpy is fine.
+ } else {
continue;
+ }
- // Support __weak direct captures.
- if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
- isARCWeakCapture = true;
+ // Non-ARC captures of retainable pointers are strong and
+ // therefore require a call to _Block_object_assign.
+ } else {
+ // fall through
}
} else {
continue;
@@ -1283,14 +1317,36 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// If there's an explicit copy expression, we do that.
if (copyExpr) {
EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
- } else if (isARCWeakCapture) {
+ } else if (useARCWeakCopy) {
EmitARCCopyWeak(dstField, srcField);
} else {
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
- srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
- llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
- Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
- llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
+ if (useARCStrongCopy) {
+ // At -O0, store null into the destination field (so that the
+ // storeStrong doesn't over-release) and then call storeStrong.
+ // This is a workaround to not having an initStrong call.
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::PointerType *ty = cast<llvm::PointerType>(srcValue->getType());
+ llvm::Value *null = llvm::ConstantPointerNull::get(ty);
+ Builder.CreateStore(null, dstField);
+ EmitARCStoreStrongCall(dstField, srcValue, true);
+
+ // With optimization enabled, take advantage of the fact that
+ // the blocks runtime guarantees a memcpy of the block data, and
+ // just emit a retain of the src field.
+ } else {
+ EmitARCRetainNonBlock(srcValue);
+
+ // We don't need this anymore, so kill it. It's not quite
+ // worth the annoyance to avoid creating it in the first place.
+ cast<llvm::Instruction>(dstField)->eraseFromParent();
+ }
+ } 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()));
+ }
}
}
@@ -1321,8 +1377,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
"__destroy_helper_block_", &CGM.getModule());
// Check if we should generate debug info for this block destroy function.
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
+ maybeInitializeDebugInfo();
IdentifierInfo *II
= &CGM.getContext().Idents.get("__destroy_helper_block_");
@@ -1356,7 +1411,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
BlockFieldFlags flags;
const CXXDestructorDecl *dtor = 0;
- bool isARCWeakCapture = false;
+ bool useARCWeakDestroy = false;
+ bool useARCStrongDestroy = false;
if (ci->isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
@@ -1382,7 +1438,11 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
// Support __weak direct captures.
if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
- isARCWeakCapture = true;
+ useARCWeakDestroy = true;
+
+ // Tools really want us to use objc_storeStrong here.
+ else
+ useARCStrongDestroy = true;
}
} else {
continue;
@@ -1396,9 +1456,13 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
PushDestructorCleanup(dtor, srcField);
// If this is a __weak capture, emit the release directly.
- } else if (isARCWeakCapture) {
+ } else if (useARCWeakDestroy) {
EmitARCDestroyWeak(srcField);
+ // Destroy strong objects with a call if requested.
+ } else if (useARCStrongDestroy) {
+ EmitARCDestroyStrong(srcField, /*precise*/ false);
+
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
// that things were done in reverse.
@@ -1497,10 +1561,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- llvm::LoadInst *value = CGF.Builder.CreateLoad(field);
- value->setAlignment(Alignment.getQuantity());
-
- CGF.EmitARCRelease(value, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, /*precise*/ false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1530,10 +1591,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- llvm::LoadInst *value = CGF.Builder.CreateLoad(field);
- value->setAlignment(Alignment.getQuantity());
-
- CGF.EmitARCRelease(value, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, /*precise*/ false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1612,6 +1670,8 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_None,
false, false);
+ // Initialize debug info if necessary.
+ CGF.maybeInitializeDebugInfo();
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
@@ -1682,6 +1742,8 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SC_Static,
SC_None,
false, false);
+ // Initialize debug info if necessary.
+ CGF.maybeInitializeDebugInfo();
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsDispose()) {
@@ -1879,7 +1941,7 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// And either 2 or 4 pointers.
CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
- CGM.getTargetData().getTypeAllocSize(Int8PtrTy);
+ CGM.getDataLayout().getTypeAllocSize(Int8PtrTy);
// Align the offset.
unsigned AlignedOffsetInBytes =
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 095cfdb259c3..f85701af781a 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -33,7 +33,7 @@ namespace llvm {
class Constant;
class Function;
class GlobalValue;
- class TargetData;
+ class DataLayout;
class FunctionType;
class PointerType;
class Value;
@@ -47,12 +47,24 @@ namespace CodeGen {
class CodeGenModule;
class CGBlockInfo;
-enum BlockFlag_t {
+// Flags stored in __block variables.
+enum BlockByrefFlags {
+ BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler
+ BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler
+ BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),
+ BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28),
+ BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),
+ BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),
+ BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28)
+};
+
+enum BlockLiteralFlags {
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_USE_STRET = (1 << 29),
- BLOCK_HAS_SIGNATURE = (1 << 30)
+ BLOCK_HAS_SIGNATURE = (1 << 30),
+ BLOCK_HAS_EXTENDED_LAYOUT = (1 << 31)
};
class BlockFlags {
uint32_t flags;
@@ -60,7 +72,7 @@ class BlockFlags {
BlockFlags(uint32_t flags) : flags(flags) {}
public:
BlockFlags() : flags(0) {}
- BlockFlags(BlockFlag_t flag) : flags(flag) {}
+ BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
uint32_t getBitMask() const { return flags; }
bool empty() const { return flags == 0; }
@@ -76,7 +88,7 @@ public:
return (l.flags & r.flags);
}
};
-inline BlockFlags operator|(BlockFlag_t l, BlockFlag_t r) {
+inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
return BlockFlags(l) | BlockFlags(r);
}
@@ -182,6 +194,10 @@ public:
/// UsesStret : True if the block uses an stret return. Mutable
/// because it gets set later in the block-creation process.
mutable bool UsesStret : 1;
+
+ /// HasCapturedVariableLayout : True if block has captured variables
+ /// and their layout meta-data has been generated.
+ bool HasCapturedVariableLayout : 1;
/// The mapping of allocated indexes within the block.
llvm::DenseMap<const VarDecl*, Capture> Captures;
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 59ed31361616..e8c05d3a46d0 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -20,7 +20,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/Intrinsics.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -86,8 +86,7 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
llvm::IntegerType *IntType =
llvm::IntegerType::get(CGF.getLLVMContext(),
@@ -121,8 +120,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
llvm::IntegerType *IntType =
llvm::IntegerType::get(CGF.getLLVMContext(),
@@ -148,7 +146,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>();
assert(ValTyP && "isn't scalar fp type!");
-
+
StringRef FnName;
switch (ValTyP->getKind()) {
default: llvm_unreachable("Isn't a scalar fp type!");
@@ -156,7 +154,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
case BuiltinType::Double: FnName = "fabs"; break;
case BuiltinType::LongDouble: FnName = "fabsl"; break;
}
-
+
// The prototype is something that takes and returns whatever V's type is.
llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
false);
@@ -214,7 +212,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
DstPtr, SrcPtr));
}
- case Builtin::BI__builtin_abs:
+ case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
case Builtin::BI__builtin_llabs: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
@@ -229,18 +227,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
-
+
case Builtin::BI__builtin_conj:
case Builtin::BI__builtin_conjf:
case Builtin::BI__builtin_conjl: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
Value *Real = ComplexVal.first;
Value *Imag = ComplexVal.second;
- Value *Zero =
- Imag->getType()->isFPOrFPVectorTy()
+ Value *Zero =
+ Imag->getType()->isFPOrFPVectorTy()
? llvm::ConstantFP::getZeroValueForNegation(Imag->getType())
: llvm::Constant::getNullValue(Imag->getType());
-
+
Imag = Builder.CreateFSub(Zero, Imag, "sub");
return RValue::getComplex(std::make_pair(Real, Imag));
}
@@ -250,14 +248,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.second);
}
-
+
case Builtin::BI__builtin_ctzs:
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
@@ -356,6 +354,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
"expval");
return RValue::get(Result);
}
+ case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
@@ -371,15 +370,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
llvm::Type *ResType = ConvertType(E->getType());
-
+
// LLVM only supports 0 and 2, make sure that we pass along that
// as a boolean.
Value *Ty = EmitScalarExpr(E->getArg(1));
ConstantInt *CI = dyn_cast<ConstantInt>(Ty);
assert(CI);
uint64_t val = CI->getZExtValue();
- CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
-
+ CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
+
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType);
return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)),CI));
}
@@ -402,9 +401,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::trap);
return RValue::get(Builder.CreateCall(F));
}
+ case Builtin::BI__debugbreak: {
+ Value *F = CGM.getIntrinsic(Intrinsic::debugtrap);
+ return RValue::get(Builder.CreateCall(F));
+ }
case Builtin::BI__builtin_unreachable: {
- if (CatchUndefined)
- EmitBranch(getTrapBB());
+ if (getLangOpts().SanitizeUnreachable)
+ EmitCheck(Builder.getFalse(), "builtin_unreachable",
+ EmitCheckSourceLocation(E->getExprLoc()),
+ llvm::ArrayRef<llvm::Value *>());
else
Builder.CreateUnreachable();
@@ -413,7 +418,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(0);
}
-
+
case Builtin::BI__builtin_powi:
case Builtin::BI__builtin_powif:
case Builtin::BI__builtin_powil: {
@@ -464,16 +469,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
V = Builder.CreateFCmpUNO(V, V, "cmp");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
-
+
case Builtin::BI__builtin_isinf: {
// isinf(x) --> fabs(x) == infinity
Value *V = EmitScalarExpr(E->getArg(0));
V = EmitFAbs(*this, V, E->getArg(0)->getType());
-
+
V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
-
+
// TODO: BI__builtin_isinf_sign
// isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0
@@ -499,11 +504,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// isfinite(x) --> x == x && fabs(x) != infinity;
Value *V = EmitScalarExpr(E->getArg(0));
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
-
+
Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
Value *IsNotInf =
Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
-
+
V = Builder.CreateAnd(Eq, IsNotInf, "and");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
@@ -565,7 +570,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.SetInsertPoint(End);
return RValue::get(Result);
}
-
+
case Builtin::BIalloca:
case Builtin::BI__builtin_alloca: {
Value *Size = EmitScalarExpr(E->getArg(0));
@@ -573,85 +578,90 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BIbzero:
case Builtin::BI__builtin_bzero: {
- Value *Address = EmitScalarExpr(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
Value *SizeVal = EmitScalarExpr(E->getArg(1));
- unsigned Align = GetPointeeAlignment(E->getArg(0));
- Builder.CreateMemSet(Address, Builder.getInt8(0), SizeVal, Align, false);
- return RValue::get(Address);
+ Builder.CreateMemSet(Dest.first, Builder.getInt8(0), SizeVal,
+ Dest.second, false);
+ return RValue::get(Dest.first);
}
case Builtin::BImemcpy:
case Builtin::BI__builtin_memcpy: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *SrcAddr = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemCpy(Address, SrcAddr, SizeVal, Align, false);
- return RValue::get(Address);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
-
+
case Builtin::BI__builtin___memcpy_chk: {
- // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
+ // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memcpy iff cst1<=cst2.
llvm::APSInt Size, DstSize;
if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
!E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
if (Size.ugt(DstSize))
break;
- Value *Dest = EmitScalarExpr(E->getArg(0));
- Value *Src = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemCpy(Dest, Src, SizeVal, Align, false);
- return RValue::get(Dest);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
-
+
case Builtin::BI__builtin_objc_memmove_collectable: {
Value *Address = EmitScalarExpr(E->getArg(0));
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this,
+ CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this,
Address, SrcAddr, SizeVal);
return RValue::get(Address);
}
case Builtin::BI__builtin___memmove_chk: {
- // fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
+ // fold __builtin_memmove_chk(x, y, cst1, cst2) to memmove iff cst1<=cst2.
llvm::APSInt Size, DstSize;
if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
!E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
if (Size.ugt(DstSize))
break;
- Value *Dest = EmitScalarExpr(E->getArg(0));
- Value *Src = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemMove(Dest, Src, SizeVal, Align, false);
- return RValue::get(Dest);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
case Builtin::BImemmove:
case Builtin::BI__builtin_memmove: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *SrcAddr = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemMove(Address, SrcAddr, SizeVal, Align, false);
- return RValue::get(Address);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
case Builtin::BImemset:
case Builtin::BI__builtin_memset: {
- Value *Address = EmitScalarExpr(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
Builder.getInt8Ty());
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- unsigned Align = GetPointeeAlignment(E->getArg(0));
- Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false);
- return RValue::get(Address);
+ Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false);
+ return RValue::get(Dest.first);
}
case Builtin::BI__builtin___memset_chk: {
// fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
@@ -661,14 +671,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
if (Size.ugt(DstSize))
break;
- Value *Address = EmitScalarExpr(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
Builder.getInt8Ty());
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- unsigned Align = GetPointeeAlignment(E->getArg(0));
- Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false);
-
- return RValue::get(Address);
+ Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false);
+ return RValue::get(Dest.first);
}
case Builtin::BI__builtin_dwarf_cfa: {
// The offset in bytes from the first argument to the CFA.
@@ -682,7 +691,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
int32_t Offset = 0;
Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa);
- return RValue::get(Builder.CreateCall(F,
+ return RValue::get(Builder.CreateCall(F,
llvm::ConstantInt::get(Int32Ty, Offset)));
}
case Builtin::BI__builtin_return_address: {
@@ -907,9 +916,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_val_compare_and_swap_16: {
QualType T = E->getType();
llvm::Value *DestPtr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
-
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
+
llvm::IntegerType *IntType =
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
@@ -935,9 +943,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_bool_compare_and_swap_16: {
QualType T = E->getArg(1)->getType();
llvm::Value *DestPtr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
-
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
+
llvm::IntegerType *IntType =
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
@@ -982,7 +989,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
StoreSize.getQuantity() * 8);
Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo());
- llvm::StoreInst *Store =
+ llvm::StoreInst *Store =
Builder.CreateStore(llvm::Constant::getNullValue(ITy), Ptr);
Store->setAlignment(StoreSize.getQuantity());
Store->setAtomic(llvm::Release);
@@ -993,7 +1000,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We assume this is supposed to correspond to a C++0x-style
// sequentially-consistent fence (i.e. this is only usable for
// synchonization, not device I/O or anything like that). This intrinsic
- // is really badly designed in the sense that in theory, there isn't
+ // is really badly designed in the sense that in theory, there isn't
// any way to safely use it... but in practice, it mostly works
// to use it with non-atomic loads and stores to get acquire/release
// semantics.
@@ -1033,8 +1040,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
Value *Ptr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
+ unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace();
Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
Value *NewVal = Builder.getInt8(1);
Value *Order = EmitScalarExpr(E->getArg(1));
@@ -1120,8 +1126,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
Value *Ptr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
+ unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace();
Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
Value *NewVal = Builder.getInt8(0);
Value *Order = EmitScalarExpr(E->getArg(1));
@@ -1310,6 +1315,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
}
+ case Builtin::BI__noop:
+ return RValue::get(0);
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
@@ -1318,7 +1325,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
return emitLibraryCall(*this, FD, E,
CGM.getBuiltinLibFunction(FD, BuiltinID));
-
+
// If this is a predefined lib function (e.g. malloc), emit the call
// using exactly the normal call path.
if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
@@ -1350,7 +1357,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
if ((ICEArguments & (1 << i)) == 0) {
ArgValue = EmitScalarExpr(E->getArg(i));
} else {
- // If this is required to be a constant, constant fold it so that we
+ // If this is required to be a constant, constant fold it so that we
// know that the generated intrinsic gets a ConstantInt.
llvm::APSInt Result;
bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result,getContext());
@@ -1375,7 +1382,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
QualType BuiltinRetType = E->getType();
llvm::Type *RetTy = VoidTy;
- if (!BuiltinRetType->isVoidType())
+ if (!BuiltinRetType->isVoidType())
RetTy = ConvertType(BuiltinRetType);
if (RetTy != V->getType()) {
@@ -1457,10 +1464,10 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
return Builder.CreateCall(F, Ops, name);
}
-Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
+Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
bool neg) {
int SV = cast<ConstantInt>(V)->getSExtValue();
-
+
llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
llvm::Constant *C = ConstantInt::get(VTy->getElementType(), neg ? -SV : SV);
return llvm::ConstantVector::getSplat(VTy->getNumElements(), C);
@@ -1469,34 +1476,56 @@ Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
/// GetPointeeAlignment - Given an expression with a pointer type, find the
/// alignment of the type referenced by the pointer. Skip over implicit
/// casts.
-unsigned CodeGenFunction::GetPointeeAlignment(const Expr *Addr) {
- unsigned Align = 1;
- // Check if the type is a pointer. The implicit cast operand might not be.
- while (Addr->getType()->isPointerType()) {
- QualType PtTy = Addr->getType()->getPointeeType();
-
- // Can't get alignment of incomplete types.
- if (!PtTy->isIncompleteType()) {
- unsigned NewA = getContext().getTypeAlignInChars(PtTy).getQuantity();
- if (NewA > Align)
- Align = NewA;
+std::pair<llvm::Value*, unsigned>
+CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) {
+ assert(Addr->getType()->isPointerType());
+ Addr = Addr->IgnoreParens();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Addr)) {
+ if ((ICE->getCastKind() == CK_BitCast || ICE->getCastKind() == CK_NoOp) &&
+ ICE->getSubExpr()->getType()->isPointerType()) {
+ std::pair<llvm::Value*, unsigned> Ptr =
+ EmitPointerWithAlignment(ICE->getSubExpr());
+ Ptr.first = Builder.CreateBitCast(Ptr.first,
+ ConvertType(Addr->getType()));
+ return Ptr;
+ } else if (ICE->getCastKind() == CK_ArrayToPointerDecay) {
+ LValue LV = EmitLValue(ICE->getSubExpr());
+ unsigned Align = LV.getAlignment().getQuantity();
+ if (!Align) {
+ // FIXME: Once LValues are fixed to always set alignment,
+ // zap this code.
+ QualType PtTy = ICE->getSubExpr()->getType();
+ if (!PtTy->isIncompleteType())
+ Align = getContext().getTypeAlignInChars(PtTy).getQuantity();
+ else
+ Align = 1;
+ }
+ return std::make_pair(LV.getAddress(), Align);
}
-
- // If the address is an implicit cast, repeat with the cast operand.
- if (const ImplicitCastExpr *CastAddr = dyn_cast<ImplicitCastExpr>(Addr)) {
- Addr = CastAddr->getSubExpr();
- continue;
+ }
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Addr)) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ LValue LV = EmitLValue(UO->getSubExpr());
+ unsigned Align = LV.getAlignment().getQuantity();
+ if (!Align) {
+ // FIXME: Once LValues are fixed to always set alignment,
+ // zap this code.
+ QualType PtTy = UO->getSubExpr()->getType();
+ if (!PtTy->isIncompleteType())
+ Align = getContext().getTypeAlignInChars(PtTy).getQuantity();
+ else
+ Align = 1;
+ }
+ return std::make_pair(LV.getAddress(), Align);
}
- break;
}
- return Align;
-}
-/// GetPointeeAlignmentValue - Given an expression with a pointer type, find
-/// the alignment of the type referenced by the pointer. Skip over implicit
-/// casts. Return the alignment as an llvm::Value.
-Value *CodeGenFunction::GetPointeeAlignmentValue(const Expr *Addr) {
- return llvm::ConstantInt::get(Int32Ty, GetPointeeAlignment(Addr));
+ unsigned Align = 1;
+ QualType PtTy = Addr->getType()->getPointeeType();
+ if (!PtTy->isIncompleteType())
+ Align = getContext().getTypeAlignInChars(PtTy).getQuantity();
+
+ return std::make_pair(EmitScalarExpr(Addr), Align);
}
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
@@ -1549,8 +1578,69 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
SmallVector<Value*, 4> Ops;
- for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
+ llvm::Value *Align = 0;
+ for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
+ if (i == 0) {
+ switch (BuiltinID) {
+ case ARM::BI__builtin_neon_vld1_v:
+ case ARM::BI__builtin_neon_vld1q_v:
+ case ARM::BI__builtin_neon_vld1q_lane_v:
+ case ARM::BI__builtin_neon_vld1_lane_v:
+ case ARM::BI__builtin_neon_vld1_dup_v:
+ case ARM::BI__builtin_neon_vld1q_dup_v:
+ case ARM::BI__builtin_neon_vst1_v:
+ case ARM::BI__builtin_neon_vst1q_v:
+ case ARM::BI__builtin_neon_vst1q_lane_v:
+ case ARM::BI__builtin_neon_vst1_lane_v:
+ case ARM::BI__builtin_neon_vst2_v:
+ case ARM::BI__builtin_neon_vst2q_v:
+ case ARM::BI__builtin_neon_vst2_lane_v:
+ case ARM::BI__builtin_neon_vst2q_lane_v:
+ case ARM::BI__builtin_neon_vst3_v:
+ case ARM::BI__builtin_neon_vst3q_v:
+ case ARM::BI__builtin_neon_vst3_lane_v:
+ case ARM::BI__builtin_neon_vst3q_lane_v:
+ case ARM::BI__builtin_neon_vst4_v:
+ case ARM::BI__builtin_neon_vst4q_v:
+ case ARM::BI__builtin_neon_vst4_lane_v:
+ case ARM::BI__builtin_neon_vst4q_lane_v:
+ // Get the alignment for the argument in addition to the value;
+ // we'll use it later.
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(0));
+ Ops.push_back(Src.first);
+ Align = Builder.getInt32(Src.second);
+ continue;
+ }
+ }
+ if (i == 1) {
+ switch (BuiltinID) {
+ case ARM::BI__builtin_neon_vld2_v:
+ case ARM::BI__builtin_neon_vld2q_v:
+ case ARM::BI__builtin_neon_vld3_v:
+ case ARM::BI__builtin_neon_vld3q_v:
+ case ARM::BI__builtin_neon_vld4_v:
+ case ARM::BI__builtin_neon_vld4q_v:
+ case ARM::BI__builtin_neon_vld2_lane_v:
+ case ARM::BI__builtin_neon_vld2q_lane_v:
+ case ARM::BI__builtin_neon_vld3_lane_v:
+ case ARM::BI__builtin_neon_vld3q_lane_v:
+ case ARM::BI__builtin_neon_vld4_lane_v:
+ case ARM::BI__builtin_neon_vld4q_lane_v:
+ case ARM::BI__builtin_neon_vld2_dup_v:
+ case ARM::BI__builtin_neon_vld3_dup_v:
+ case ARM::BI__builtin_neon_vld4_dup_v:
+ // Get the alignment for the argument in addition to the value;
+ // we'll use it later.
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
+ Ops.push_back(Src.first);
+ Align = Builder.getInt32(Src.second);
+ continue;
+ }
+ }
Ops.push_back(EmitScalarExpr(E->getArg(i)));
+ }
// vget_lane and vset_lane are not overloaded and do not have an extra
// argument that specifies the vector type.
@@ -1596,7 +1686,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = FloatTy;
else
Ty = DoubleTy;
-
+
// Determine whether this is an unsigned conversion or not.
bool usgn = Result.getZExtValue() == 1;
unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr;
@@ -1605,7 +1695,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Int, Ty);
return Builder.CreateCall(F, Ops, "vcvtr");
}
-
+
// Determine the type of this overloaded NEON intrinsic.
NeonTypeFlags Type(Result.getZExtValue());
bool usgn = Type.isUnsigned();
@@ -1620,6 +1710,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
unsigned Int;
switch (BuiltinID) {
default: return 0;
+ case ARM::BI__builtin_neon_vbsl_v:
+ case ARM::BI__builtin_neon_vbslq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty),
+ Ops, "vbsl");
case ARM::BI__builtin_neon_vabd_v:
case ARM::BI__builtin_neon_vabdq_v:
Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds;
@@ -1690,7 +1784,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vcvtq_f32_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
- return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
+ return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
case ARM::BI__builtin_neon_vcvt_s32_v:
case ARM::BI__builtin_neon_vcvt_u32_v:
@@ -1699,7 +1793,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Type *FloatTy =
GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
- return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
+ return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
: Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
}
case ARM::BI__builtin_neon_vcvt_n_f32_v:
@@ -1730,7 +1824,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
Indices.push_back(ConstantInt::get(Int32Ty, i+CV));
-
+
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Value *SV = llvm::ConstantVector::get(Indices);
@@ -1746,7 +1840,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vhsub");
case ARM::BI__builtin_neon_vld1_v:
case ARM::BI__builtin_neon_vld1q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty),
Ops, "vld1");
case ARM::BI__builtin_neon_vld1q_lane_v:
@@ -1761,8 +1855,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Load the value as a one-element vector.
Ty = llvm::VectorType::get(VTy->getElementType(), 1);
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty);
- Value *Ld = Builder.CreateCall2(F, Ops[0],
- GetPointeeAlignmentValue(E->getArg(0)));
+ Value *Ld = Builder.CreateCall2(F, Ops[0], Align);
// Combine them.
SmallVector<Constant*, 2> Indices;
Indices.push_back(ConstantInt::get(Int32Ty, 1-Lane));
@@ -1776,7 +1869,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
LoadInst *Ld = Builder.CreateLoad(Ops[0]);
- Value *Align = GetPointeeAlignmentValue(E->getArg(0));
Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
}
@@ -1786,7 +1878,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
LoadInst *Ld = Builder.CreateLoad(Ops[0]);
- Value *Align = GetPointeeAlignmentValue(E->getArg(0));
Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
Ops[0] = Builder.CreateInsertElement(V, Ld, CI);
@@ -1795,7 +1886,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld2_v:
case ARM::BI__builtin_neon_vld2q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1804,7 +1894,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld3_v:
case ARM::BI__builtin_neon_vld3q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1813,7 +1902,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld4_v:
case ARM::BI__builtin_neon_vld4q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1824,7 +1912,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
+ Ops.push_back(Align);
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1836,7 +1924,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
+ Ops.push_back(Align);
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1849,7 +1937,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateBitCast(Ops[5], Ty);
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
+ Ops.push_back(Align);
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1861,47 +1949,46 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Handle 64-bit elements as a special-case. There is no "dup" needed.
if (VTy->getElementType()->getPrimitiveSizeInBits() == 64) {
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld2_dup_v:
- Int = Intrinsic::arm_neon_vld2;
+ case ARM::BI__builtin_neon_vld2_dup_v:
+ Int = Intrinsic::arm_neon_vld2;
break;
case ARM::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld3;
+ Int = Intrinsic::arm_neon_vld3;
break;
case ARM::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld4;
+ Int = Intrinsic::arm_neon_vld4;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
}
Function *F = CGM.getIntrinsic(Int, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld_dup");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
}
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld2_dup_v:
- Int = Intrinsic::arm_neon_vld2lane;
+ case ARM::BI__builtin_neon_vld2_dup_v:
+ Int = Intrinsic::arm_neon_vld2lane;
break;
case ARM::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld3lane;
+ Int = Intrinsic::arm_neon_vld3lane;
break;
case ARM::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld4lane;
+ Int = Intrinsic::arm_neon_vld4lane;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
}
Function *F = CGM.getIntrinsic(Int, Ty);
llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType());
-
+
SmallVector<Value*, 6> Args;
Args.push_back(Ops[1]);
Args.append(STy->getNumElements(), UndefValue::get(Ty));
llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
Args.push_back(CI);
- Args.push_back(GetPointeeAlignmentValue(E->getArg(1)));
-
+ Args.push_back(Align);
+
Ops[1] = Builder.CreateCall(F, Args, "vld_dup");
// splat lane 0 to all elts in each vector of the result.
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
@@ -1944,6 +2031,14 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
+ case ARM::BI__builtin_neon_vfma_v:
+ case ARM::BI__builtin_neon_vfmaq_v: {
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ return Builder.CreateCall3(F, Ops[0], Ops[1], Ops[2]);
+ }
case ARM::BI__builtin_neon_vpadal_v:
case ARM::BI__builtin_neon_vpadalq_v: {
Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals;
@@ -2016,7 +2111,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = usgn ? Intrinsic::arm_neon_vqrshiftu : Intrinsic::arm_neon_vqrshifts;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshl");
case ARM::BI__builtin_neon_vqrshrn_n_v:
- Int = usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
+ Int =
+ usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n",
1, true);
case ARM::BI__builtin_neon_vqrshrun_n_v:
@@ -2086,7 +2182,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, true);
Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
+ Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n");
case ARM::BI__builtin_neon_vrsubhn_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, Ty),
@@ -2101,7 +2197,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vshl_n_v:
case ARM::BI__builtin_neon_vshlq_n_v:
Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false);
- return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1], "vshl_n");
+ return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1],
+ "vshl_n");
case ARM::BI__builtin_neon_vshrn_n_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftn, Ty),
Ops, "vshrn_n", 1, true);
@@ -2133,7 +2230,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateAdd(Ops[0], Ops[1]);
case ARM::BI__builtin_neon_vst1_v:
case ARM::BI__builtin_neon_vst1q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst1q_lane_v:
@@ -2143,7 +2240,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Value *SV = llvm::ConstantVector::get(cast<llvm::Constant>(Ops[2]));
Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV);
- Ops[2] = GetPointeeAlignmentValue(E->getArg(0));
+ Ops[2] = Align;
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1,
Ops[1]->getType()), Ops);
}
@@ -2154,38 +2251,37 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
StoreInst *St = Builder.CreateStore(Ops[1],
Builder.CreateBitCast(Ops[0], Ty));
- Value *Align = GetPointeeAlignmentValue(E->getArg(0));
St->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
return St;
}
case ARM::BI__builtin_neon_vst2_v:
case ARM::BI__builtin_neon_vst2q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst2_lane_v:
case ARM::BI__builtin_neon_vst2q_lane_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_v:
case ARM::BI__builtin_neon_vst3q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_lane_v:
case ARM::BI__builtin_neon_vst3q_lane_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_v:
case ARM::BI__builtin_neon_vst4q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_lane_v:
case ARM::BI__builtin_neon_vst4q_lane_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vsubhn_v:
@@ -2220,7 +2316,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]);
- Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
+ Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
ConstantAggregateZero::get(Ty));
return Builder.CreateSExt(Ops[0], Ty, "vtst");
}
@@ -2250,7 +2346,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Value *SV = 0;
-
+
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
@@ -2263,13 +2359,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
return SV;
}
- case ARM::BI__builtin_neon_vzip_v:
+ case ARM::BI__builtin_neon_vzip_v:
case ARM::BI__builtin_neon_vzipq_v: {
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Value *SV = 0;
-
+
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
@@ -2382,62 +2478,62 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_palignr: {
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
-
+
// If palignr is shifting the pair of input vectors less than 9 bytes,
// emit a shuffle instruction.
if (shiftVal <= 8) {
SmallVector<llvm::Constant*, 8> Indices;
for (unsigned i = 0; i != 8; ++i)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i));
-
+
Value* SV = llvm::ConstantVector::get(Indices);
return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
}
-
+
// If palignr is shifting the pair of input vectors more than 8 but less
// than 16 bytes, emit a logical right shift of the destination.
if (shiftVal < 16) {
// MMX has these as 1 x i64 vectors for some odd optimization reasons.
llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1);
-
+
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8);
-
+
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
}
-
+
// If palignr is shifting the pair of vectors more than 16 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
case X86::BI__builtin_ia32_palignr128: {
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
-
+
// If palignr is shifting the pair of input vectors less than 17 bytes,
// emit a shuffle instruction.
if (shiftVal <= 16) {
SmallVector<llvm::Constant*, 16> Indices;
for (unsigned i = 0; i != 16; ++i)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i));
-
+
Value* SV = llvm::ConstantVector::get(Indices);
return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
}
-
+
// If palignr is shifting the pair of input vectors more than 16 but less
// than 32 bytes, emit a logical right shift of the destination.
if (shiftVal < 32) {
llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2);
-
+
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Ops[1] = llvm::ConstantInt::get(Int32Ty, (shiftVal-16) * 8);
-
+
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
}
-
+
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index aba5d755d5c4..91795b9ded29 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -189,7 +189,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *ptr,
llvm::Value *&numElements,
llvm::Value *&allocPtr, CharUnits &cookieSize) {
// Derive a char* in the same address space as the pointer.
- unsigned AS = cast<llvm::PointerType>(ptr->getType())->getAddressSpace();
+ unsigned AS = ptr->getType()->getPointerAddressSpace();
llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
ptr = CGF.Builder.CreateBitCast(ptr, charPtrTy);
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index a0dcdfdcc686..570aeb040f55 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -154,6 +154,15 @@ protected:
llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
public:
+ /// Adjust the given non-null pointer to an object of polymorphic
+ /// type to point to the complete object.
+ ///
+ /// The IR type of the result should be a pointer but is otherwise
+ /// irrelevant.
+ virtual llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type) = 0;
+
/// Build the signature of the given constructor variant by adding
/// any required parameters. For convenience, ResTy has been
/// initialized to 'void', and ArgTys has been initialized with the
@@ -196,6 +205,9 @@ public:
/// Gets the pure virtual member call function.
virtual StringRef GetPureVirtualCallName() = 0;
+ /// Gets the deleted virtual member call name.
+ virtual StringRef GetDeletedVirtualCallName() = 0;
+
/**************************** Array cookies ******************************/
/// Returns the extra size required in order to store the array
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 7d2b9d355ec6..2d1d152894fd 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -25,7 +25,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Attributes.h"
#include "llvm/Support/CallSite.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/InlineAsm.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
@@ -148,6 +148,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (PcsAttr *PCS = D->getAttr<PcsAttr>())
return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP);
+ if (D->hasAttr<PnaclCallAttr>())
+ return CC_PnaclCall;
+
return CC_C;
}
@@ -588,9 +591,9 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
// If the first elt is at least as large as what we're looking for, or if the
// first element is the same size as the whole struct, we can enter it.
uint64_t FirstEltSize =
- CGF.CGM.getTargetData().getTypeAllocSize(FirstElt);
+ CGF.CGM.getDataLayout().getTypeAllocSize(FirstElt);
if (FirstEltSize < DstSize &&
- FirstEltSize < CGF.CGM.getTargetData().getTypeAllocSize(SrcSTy))
+ FirstEltSize < CGF.CGM.getDataLayout().getTypeAllocSize(SrcSTy))
return SrcPtr;
// GEP into the first element.
@@ -653,14 +656,14 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
if (SrcTy == Ty)
return CGF.Builder.CreateLoad(SrcPtr);
- uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty);
+ uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
SrcPtr = EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF);
SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
}
- uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
// If the source and destination are integer or pointer types, just do an
// extension or truncation to the desired type.
@@ -740,7 +743,7 @@ static void CreateCoercedStore(llvm::Value *Src,
return;
}
- uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) {
DstPtr = EnterStructPointerForCoercedAccess(DstPtr, DstSTy, SrcSize, CGF);
@@ -756,7 +759,7 @@ static void CreateCoercedStore(llvm::Value *Src,
return;
}
- uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy);
+ uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(DstTy);
// If store is legal, just bitcast the src pointer.
if (SrcSize <= DstSize) {
@@ -864,6 +867,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
ie = FI.arg_end(); it != ie; ++it) {
const ABIArgInfo &argAI = it->info;
+ // Insert a padding type to ensure proper alignment.
+ if (llvm::Type *PaddingType = argAI.getPaddingType())
+ argTypes.push_back(PaddingType);
+
switch (argAI.getKind()) {
case ABIArgInfo::Ignore:
break;
@@ -877,9 +884,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // Insert a padding type to ensure proper alignment.
- if (llvm::Type *PaddingType = argAI.getPaddingType())
- argTypes.push_back(PaddingType);
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
@@ -924,50 +928,52 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
unsigned &CallingConv) {
- llvm::Attributes FuncAttrs;
- llvm::Attributes RetAttrs;
+ llvm::AttrBuilder FuncAttrs;
+ llvm::AttrBuilder RetAttrs;
CallingConv = FI.getEffectiveCallingConvention();
if (FI.isNoReturn())
- FuncAttrs |= llvm::Attribute::NoReturn;
+ FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs |= llvm::Attribute::ReturnsTwice;
+ FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
if (TargetDecl->hasAttr<NoThrowAttr>())
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
if (FPT && FPT->isNothrow(getContext()))
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
}
if (TargetDecl->hasAttr<NoReturnAttr>())
- FuncAttrs |= llvm::Attribute::NoReturn;
+ FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs |= llvm::Attribute::ReturnsTwice;
+ FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
// 'const' and 'pure' attribute functions are also nounwind.
if (TargetDecl->hasAttr<ConstAttr>()) {
- FuncAttrs |= llvm::Attribute::ReadNone;
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::ReadNone);
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
} else if (TargetDecl->hasAttr<PureAttr>()) {
- FuncAttrs |= llvm::Attribute::ReadOnly;
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::ReadOnly);
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
}
if (TargetDecl->hasAttr<MallocAttr>())
- RetAttrs |= llvm::Attribute::NoAlias;
+ RetAttrs.addAttribute(llvm::Attributes::NoAlias);
}
if (CodeGenOpts.OptimizeSize)
- FuncAttrs |= llvm::Attribute::OptimizeForSize;
+ FuncAttrs.addAttribute(llvm::Attributes::OptimizeForSize);
+ if (CodeGenOpts.OptimizeSize == 2)
+ FuncAttrs.addAttribute(llvm::Attributes::MinSize);
if (CodeGenOpts.DisableRedZone)
- FuncAttrs |= llvm::Attribute::NoRedZone;
+ FuncAttrs.addAttribute(llvm::Attributes::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
- FuncAttrs |= llvm::Attribute::NoImplicitFloat;
+ FuncAttrs.addAttribute(llvm::Attributes::NoImplicitFloat);
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
@@ -975,24 +981,28 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
if (RetTy->hasSignedIntegerRepresentation())
- RetAttrs |= llvm::Attribute::SExt;
+ RetAttrs.addAttribute(llvm::Attributes::SExt);
else if (RetTy->hasUnsignedIntegerRepresentation())
- RetAttrs |= llvm::Attribute::ZExt;
+ RetAttrs.addAttribute(llvm::Attributes::ZExt);
break;
case ABIArgInfo::Direct:
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Indirect: {
- llvm::Attributes SRETAttrs = llvm::Attribute::StructRet;
+ llvm::AttrBuilder SRETAttrs;
+ SRETAttrs.addAttribute(llvm::Attributes::StructRet);
if (RetAI.getInReg())
- SRETAttrs |= llvm::Attribute::InReg;
- PAL.push_back(llvm::AttributeWithIndex::get(Index, SRETAttrs));
+ SRETAttrs.addAttribute(llvm::Attributes::InReg);
+ PAL.push_back(llvm::
+ AttributeWithIndex::get(Index,
+ llvm::Attributes::get(getLLVMContext(),
+ SRETAttrs)));
++Index;
// sret disables readnone and readonly
- FuncAttrs &= ~(llvm::Attribute::ReadOnly |
- llvm::Attribute::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
+ .removeAttribute(llvm::Attributes::ReadNone);
break;
}
@@ -1000,14 +1010,29 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm_unreachable("Invalid ABI kind for return argument");
}
- if (RetAttrs)
- PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
+ if (RetAttrs.hasAttributes())
+ PAL.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
+ llvm::Attributes::get(getLLVMContext(),
+ RetAttrs)));
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
QualType ParamType = it->type;
const ABIArgInfo &AI = it->info;
- llvm::Attributes Attrs;
+ 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));
+ }
+ // Increment Index if there is padding.
+ ++Index;
+ }
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
// have the corresponding parameter variable. It doesn't make
@@ -1015,38 +1040,40 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (AI.getKind()) {
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerOrEnumerationType())
- Attrs |= llvm::Attribute::SExt;
+ Attrs.addAttribute(llvm::Attributes::SExt);
else if (ParamType->isUnsignedIntegerOrEnumerationType())
- Attrs |= llvm::Attribute::ZExt;
+ Attrs.addAttribute(llvm::Attributes::ZExt);
// FALL THROUGH
case ABIArgInfo::Direct:
if (AI.getInReg())
- Attrs |= llvm::Attribute::InReg;
+ Attrs.addAttribute(llvm::Attributes::InReg);
// FIXME: handle sseregparm someday...
- // Increment Index if there is padding.
- Index += (AI.getPaddingType() != 0);
-
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(AI.getCoerceToType())) {
unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
- if (Attrs != llvm::Attribute::None)
+ if (Attrs.hasAttributes())
for (unsigned I = 0; I < Extra; ++I)
- PAL.push_back(llvm::AttributeWithIndex::get(Index + I, Attrs));
+ PAL.push_back(llvm::AttributeWithIndex::get(Index + I,
+ llvm::Attributes::get(getLLVMContext(),
+ Attrs)));
Index += Extra;
}
break;
case ABIArgInfo::Indirect:
+ if (AI.getInReg())
+ Attrs.addAttribute(llvm::Attributes::InReg);
+
if (AI.getIndirectByVal())
- Attrs |= llvm::Attribute::ByVal;
+ Attrs.addAttribute(llvm::Attributes::ByVal);
+
+ Attrs.addAlignmentAttr(AI.getIndirectAlign());
- Attrs |=
- llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign());
// byval disables readnone and readonly.
- FuncAttrs &= ~(llvm::Attribute::ReadOnly |
- llvm::Attribute::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
+ .removeAttribute(llvm::Attributes::ReadNone);
break;
case ABIArgInfo::Ignore:
@@ -1064,12 +1091,17 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
}
- if (Attrs)
- PAL.push_back(llvm::AttributeWithIndex::get(Index, Attrs));
+ if (Attrs.hasAttributes())
+ PAL.push_back(llvm::AttributeWithIndex::get(Index,
+ llvm::Attributes::get(getLLVMContext(),
+ Attrs)));
++Index;
}
- if (FuncAttrs)
- PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs));
+ if (FuncAttrs.hasAttributes())
+ PAL.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
+ llvm::Attributes::get(getLLVMContext(),
+ FuncAttrs)));
}
/// An argument came in as a promoted argument; demote it back to its
@@ -1117,7 +1149,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Name the struct return argument.
if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
- AI->addAttr(llvm::Attribute::NoAlias);
+ AI->addAttr(llvm::Attributes::get(getLLVMContext(),
+ llvm::Attributes::NoAlias));
++AI;
}
@@ -1134,6 +1167,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
bool isPromoted =
isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted();
+ // Skip the dummy padding argument.
+ if (ArgI.getPaddingType())
+ ++AI;
+
switch (ArgI.getKind()) {
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
@@ -1175,9 +1212,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // Skip the dummy padding argument.
- if (ArgI.getPaddingType())
- ++AI;
// If we have the trivial case, handle it with no muss and fuss.
if (!isa<llvm::StructType>(ArgI.getCoerceToType()) &&
@@ -1187,7 +1221,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *V = AI;
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::Attribute::NoAlias);
+ AI->addAttr(llvm::Attributes::get(getLLVMContext(),
+ llvm::Attributes::NoAlias));
// Ensure the argument is the correct type.
if (V->getType() != ArgI.getCoerceToType())
@@ -1205,7 +1240,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// The alignment we need to use is the max of the requested alignment for
// the argument plus the alignment required by our access code below.
unsigned AlignmentToUse =
- CGM.getTargetData().getABITypeAlignment(ArgI.getCoerceToType());
+ CGM.getDataLayout().getABITypeAlignment(ArgI.getCoerceToType());
AlignmentToUse = std::max(AlignmentToUse,
(unsigned)getContext().getDeclAlign(Arg).getQuantity());
@@ -1226,10 +1261,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// and the optimizer generally likes scalar values better than FCAs.
llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
if (STy && STy->getNumElements() > 1) {
- uint64_t SrcSize = CGM.getTargetData().getTypeAllocSize(STy);
+ uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(STy);
llvm::Type *DstTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
- uint64_t DstSize = CGM.getTargetData().getTypeAllocSize(DstTy);
+ uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(DstTy);
if (SrcSize <= DstSize) {
Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
@@ -1363,12 +1398,23 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
.objc_retainAutoreleasedReturnValue) {
doRetainAutorelease = false;
- // Look for an inline asm immediately preceding the call and kill it, too.
- llvm::Instruction *prev = call->getPrevNode();
- if (llvm::CallInst *asmCall = dyn_cast_or_null<llvm::CallInst>(prev))
- if (asmCall->getCalledValue()
- == CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker)
- insnsToKill.push_back(prev);
+ // If we emitted an assembly marker for this call (and the
+ // ARCEntrypoints field should have been set if so), go looking
+ // for that call. If we can't find it, we can't do this
+ // optimization. But it should always be the immediately previous
+ // instruction, unless we needed bitcasts around the call.
+ if (CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker) {
+ llvm::Instruction *prev = call->getPrevNode();
+ assert(prev);
+ if (isa<llvm::BitCastInst>(prev)) {
+ prev = prev->getPrevNode();
+ assert(prev);
+ }
+ assert(isa<llvm::CallInst>(prev));
+ assert(cast<llvm::CallInst>(prev)->getCalledValue() ==
+ CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker);
+ insnsToKill.push_back(prev);
+ }
} else {
return 0;
}
@@ -1755,7 +1801,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
= dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
- assert(getContext().getLangOpts().ObjCAutoRefCount);
+ assert(getLangOpts().ObjCAutoRefCount);
assert(getContext().hasSameType(E->getType(), type));
return emitWritebackArg(*this, args, CRE);
}
@@ -1943,6 +1989,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned TypeAlign =
getContext().getTypeAlignInChars(I->Ty).getQuantity();
+
+ // Insert a padding argument to ensure proper alignment.
+ if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
+ Args.push_back(llvm::UndefValue::get(PaddingType));
+ ++IRArgNo;
+ }
+
switch (ArgInfo.getKind()) {
case ABIArgInfo::Indirect: {
if (RV.isScalar() || RV.isComplex()) {
@@ -1969,7 +2022,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// we cannot force it to be sufficiently aligned.
llvm::Value *Addr = RV.getAggregateAddr();
unsigned Align = ArgInfo.getIndirectAlign();
- const llvm::TargetData *TD = &CGM.getTargetData();
+ const llvm::DataLayout *TD = &CGM.getDataLayout();
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
(ArgInfo.getIndirectByVal() && TypeAlign < Align &&
llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) {
@@ -1998,12 +2051,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // Insert a padding argument to ensure proper alignment.
- if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
- Args.push_back(llvm::UndefValue::get(PaddingType));
- ++IRArgNo;
- }
-
if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
ArgInfo.getDirectOffset() == 0) {
@@ -2049,8 +2096,25 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// and the optimizer generally likes scalar values better than FCAs.
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) {
- SrcPtr = Builder.CreateBitCast(SrcPtr,
- llvm::PointerType::getUnqual(STy));
+ llvm::Type *SrcTy =
+ cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
+ uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
+ uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
+
+ // If the source type is smaller than the destination type of the
+ // coerce-to logic, copy the source value into a temp alloca the size
+ // of the destination type to allow loading all of it. The bits past
+ // the source value are left undef.
+ if (SrcSize < DstSize) {
+ llvm::AllocaInst *TempAlloca
+ = CreateTempAlloca(STy, SrcPtr->getName() + ".coerce");
+ Builder.CreateMemCpy(TempAlloca, SrcPtr, SrcSize, 0);
+ SrcPtr = TempAlloca;
+ } else {
+ SrcPtr = Builder.CreateBitCast(SrcPtr,
+ llvm::PointerType::getUnqual(STy));
+ }
+
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i);
llvm::LoadInst *LI = Builder.CreateLoad(EltPtr);
@@ -2113,10 +2177,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
- llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(AttributeList);
+ llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(getLLVMContext(),
+ AttributeList);
llvm::BasicBlock *InvokeDest = 0;
- if (!(Attrs.getFnAttributes() & llvm::Attribute::NoUnwind))
+ if (!Attrs.getFnAttributes().hasAttribute(llvm::Attributes::NoUnwind))
InvokeDest = getInvokeDest();
llvm::CallSite CS;
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index e37fa3ab72b7..b2225e48e361 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -542,12 +542,6 @@ namespace {
};
}
-static bool hasTrivialCopyOrMoveConstructor(const CXXRecordDecl *Record,
- bool Moving) {
- return Moving ? Record->hasTrivialMoveConstructor() :
- Record->hasTrivialCopyConstructor();
-}
-
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *MemberInit,
@@ -588,12 +582,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
if (Array && Constructor->isImplicitlyDefined() &&
Constructor->isCopyOrMoveConstructor()) {
QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
- const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
+ CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
if (BaseElementTy.isPODType(CGF.getContext()) ||
- (Record && hasTrivialCopyOrMoveConstructor(Record,
- Constructor->isMoveConstructor()))) {
- // Find the source pointer. We knows it's the last argument because
- // we know we're in a copy constructor.
+ (CE && CE->getConstructor()->isTrivial())) {
+ // Find the source pointer. We know it's the last argument because
+ // we know we're in an implicit copy constructor.
unsigned SrcArgIndex = Args.size() - 1;
llvm::Value *SrcPtr
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
@@ -952,8 +945,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
}
// -fapple-kext must inline any call to this dtor into
// the caller's body.
- if (getContext().getLangOpts().AppleKext)
- CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
+ if (getLangOpts().AppleKext)
+ CurFn->addFnAttr(llvm::Attributes::AlwaysInline);
break;
}
@@ -1238,7 +1231,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CGDebugInfo *DI = getDebugInfo();
if (DI &&
- CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) {
+ CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo) {
// If debug info for this class has not been emitted then this is the
// right time to do so.
const CXXRecordDecl *Parent = D->getParent();
@@ -1268,7 +1261,9 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
- EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
+ // FIXME: Provide a source location here.
+ EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, ArgBeg, ArgEnd);
}
void
@@ -1413,14 +1408,16 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
ForVirtualBase);
llvm::Value *Callee = 0;
- if (getContext().getLangOpts().AppleKext)
+ if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
DD->getParent());
if (!Callee)
Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
- EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
+ // FIXME: Provide a source location here.
+ EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, 0, 0);
}
namespace {
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index fd1c7a339807..80fa09be7473 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGBlocks.h"
+#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
@@ -34,7 +35,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -157,7 +158,7 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
OS << OID->getName();
} else if (const ObjCCategoryImplDecl *OCD =
dyn_cast<const ObjCCategoryImplDecl>(DC)){
- OS << ((NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
+ OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
OCD->getIdentifier()->getNameStart() << ')';
}
OS << ' ' << OMD->getSelector().getAsString() << ']';
@@ -254,9 +255,13 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
return PLoc.isValid()? PLoc.getLine() : 0;
}
-/// getColumnNumber - Get column number for the location. If location is
-/// invalid then use current location.
+/// getColumnNumber - Get column number for the location.
unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
+ // We may not want column information at all.
+ if (!CGM.getCodeGenOpts().DebugColumnInfo)
+ return 0;
+
+ // If the location is invalid then use the current column.
if (Loc.isInvalid() && CurLoc.isInvalid())
return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
@@ -347,44 +352,60 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm_unreachable("Unexpected builtin type");
case BuiltinType::NullPtr:
return DBuilder.
- createNullPtrType(BT->getName(CGM.getContext().getLangOpts()));
+ createNullPtrType(BT->getName(CGM.getLangOpts()));
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
- return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU,
- getOrCreateMainFile(), 0);
+ if (ClassTy.Verify())
+ return ClassTy;
+ ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", TheCU,
+ getOrCreateMainFile(), 0);
+ return ClassTy;
case BuiltinType::ObjCId: {
// typedef struct objc_class *Class;
// typedef struct objc_object {
// Class isa;
// } *id;
- // TODO: Cache these two types to avoid duplicates.
- llvm::DIType OCTy =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU, getOrCreateMainFile(), 0);
+ if (ObjTy.Verify())
+ return ObjTy;
+
+ if (!ClassTy.Verify())
+ ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", TheCU,
+ getOrCreateMainFile(), 0);
+
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- llvm::DIType ISATy = DBuilder.createPointerType(OCTy, Size);
+ llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
+
+ llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object",
+ getOrCreateMainFile(),
+ 0, 0, 0, 0,
+ llvm::DIArray());
- SmallVector<llvm::Value *, 16> EltTys;
+ llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy);
+ SmallVector<llvm::Value *, 1> EltTys;
llvm::DIType FieldTy =
- DBuilder.createMemberType(getOrCreateMainFile(), "isa",
+ DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa",
getOrCreateMainFile(), 0, Size,
0, 0, 0, ISATy);
EltTys.push_back(FieldTy);
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
- return DBuilder.createStructType(TheCU, "objc_object",
- getOrCreateMainFile(),
- 0, 0, 0, 0, Elements);
+
+ ObjNode->replaceOperandWith(10, Elements);
+ ObjTy = llvm::DIType(ObjNode);
+ return ObjTy;
}
case BuiltinType::ObjCSel: {
- return
+ if (SelTy.Verify())
+ return SelTy;
+ SelTy =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_selector", TheCU, getOrCreateMainFile(),
0);
+ return SelTy;
}
case BuiltinType::UChar:
case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
@@ -417,7 +438,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::ULong: BTName = "long unsigned int"; break;
case BuiltinType::ULongLong: BTName = "long long unsigned int"; break;
default:
- BTName = BT->getName(CGM.getContext().getLangOpts());
+ BTName = BT->getName(CGM.getLangOpts());
break;
}
// Bit size, align and offset of the type.
@@ -498,21 +519,17 @@ llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
llvm::DIDescriptor Ctx) {
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = RD->getName();
+ StringRef RDName = getClassName(RD);
- // Get the tag.
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
unsigned Tag = 0;
- if (CXXDecl) {
- RDName = getClassName(RD);
- Tag = llvm::dwarf::DW_TAG_class_type;
- }
- else if (RD->isStruct())
+ if (RD->isStruct() || RD->isInterface())
Tag = llvm::dwarf::DW_TAG_structure_type;
else if (RD->isUnion())
Tag = llvm::dwarf::DW_TAG_union_type;
- else
- llvm_unreachable("Unknown RecordDecl type!");
+ else {
+ assert(RD->isClass());
+ Tag = llvm::dwarf::DW_TAG_class_type;
+ }
// Create the type.
return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line);
@@ -550,7 +567,7 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
/// then emit record's fwd if debug info size reduction is enabled.
llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
llvm::DIFile Unit) {
- if (CGM.getCodeGenOpts().DebugInfo != CodeGenOptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo)
return getOrCreateType(PointeeTy, Unit);
// Limit debug info for the pointee type.
@@ -777,8 +794,6 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
const LambdaExpr::Capture C = *I;
- // TODO: Need to handle 'this' in some way by probably renaming the
- // this of the lambda class and having a field member of 'this'.
if (C.capturesVariable()) {
VarDecl *V = C.getCapturedVar();
llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
@@ -793,10 +808,24 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
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 {
- bool IsMsStruct = record->hasAttr<MsStructAttr>();
+ bool IsMsStruct = record->isMsStruct(CGM.getContext());
const FieldDecl *LastFD = 0;
for (RecordDecl::field_iterator I = record->field_begin(),
E = record->field_end();
@@ -875,12 +904,12 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
// 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.createArtificialType(ThisPtrType);
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
} else {
llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- ThisPtrType = DBuilder.createArtificialType(ThisPtrType);
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
}
}
@@ -995,12 +1024,8 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
if (D->isImplicit() && !D->isUsed())
continue;
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- // Only emit debug information for user provided functions, we're
- // unlikely to want info for artificial functions.
- if (Method->isUserProvided())
- EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
- }
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
SE = FTD->spec_end(); SI != SE; ++SI)
@@ -1182,7 +1207,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
/// getOrCreateRecordType - Emit record type's standalone debug info.
llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
return T;
}
@@ -1191,7 +1216,7 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
/// debug info.
llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
DBuilder.retainType(T);
return T;
@@ -1388,12 +1413,21 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
FieldAlign = CGM.getContext().getTypeAlign(FType);
}
- // We can't know the offset of our ivar in the structure if we're using
- // the non-fragile abi and the debugger should ignore the value anyways.
- // Call it the FieldNo+1 due to how debuggers use the information,
- // e.g. negating the value when it needs a lookup in the dynamic table.
- uint64_t FieldOffset = CGM.getLangOpts().ObjCRuntime.isNonFragile()
- ? FieldNo+1 : RL.getFieldOffset(FieldNo);
+ uint64_t FieldOffset;
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
+ // We don't know the runtime offset of an ivar if we're using the
+ // non-fragile ABI. For bitfields, use the bit offset into the first
+ // byte of storage of the bitfield. For other fields, use zero.
+ if (Field->isBitField()) {
+ FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset(
+ CGM, ID, Field);
+ FieldOffset %= CGM.getContext().getCharWidth();
+ } else {
+ FieldOffset = 0;
+ }
+ } else {
+ FieldOffset = RL.getFieldOffset(FieldNo);
+ }
unsigned Flags = 0;
if (Field->getAccessControl() == ObjCIvarDecl::Protected)
@@ -1570,9 +1604,29 @@ llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
/// CreateEnumType - get enumeration type.
llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
- SmallVector<llvm::Value *, 16> Enumerators;
+ uint64_t Size = 0;
+ uint64_t Align = 0;
+ if (!ED->getTypeForDecl()->isIncompleteType()) {
+ Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
+ Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
+ }
+
+ // If this is just a forward declaration, construct an appropriately
+ // marked node and just return it.
+ if (!ED->getDefinition()) {
+ llvm::DIDescriptor EDContext;
+ EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext()));
+ llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
+ unsigned Line = getLineNumber(ED->getLocation());
+ StringRef EDName = ED->getName();
+ return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type,
+ EDName, EDContext, DefUnit, Line, 0,
+ Size, Align);
+ }
// Create DIEnumerator elements for each enumerator.
+ SmallVector<llvm::Value *, 16> Enumerators;
+ ED = ED->getDefinition();
for (EnumDecl::enumerator_iterator
Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
Enum != EnumEnd; ++Enum) {
@@ -1586,21 +1640,14 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
- uint64_t Size = 0;
- uint64_t Align = 0;
- if (!ED->getTypeForDecl()->isIncompleteType()) {
- Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
- Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
- }
llvm::DIDescriptor EnumContext =
getContextDescriptor(cast<Decl>(ED->getDeclContext()));
llvm::DIType ClassTy = ED->isScopedUsingClassTag() ?
getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType();
- unsigned Flags = !ED->isCompleteDefinition() ? llvm::DIDescriptor::FlagFwdDecl : 0;
llvm::DIType DbgTy =
DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
Size, Align, EltArray,
- ClassTy, Flags);
+ ClassTy);
return DbgTy;
}
@@ -1838,10 +1885,10 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = RD->getName();
+ StringRef RDName = getClassName(RD);
llvm::DIDescriptor RDContext;
- if (CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo)
RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
else
RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
@@ -1859,9 +1906,7 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, llvm::DIArray());
- else if (CXXDecl) {
- RDName = getClassName(RD);
-
+ 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,
@@ -1969,7 +2014,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
// implicit parameter "this".
-llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D,
+llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
QualType FnType,
llvm::DIFile F) {
@@ -1982,9 +2027,11 @@ 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.
- Elts.push_back(getOrCreateType(OMethod->getSelfDecl()->getType(), F));
- // "cmd" pointer is always second argument.
- Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F));
+ llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F);
+ Elts.push_back(DBuilder.createObjectPointerType(SelfTy));
+ // "_cmd" pointer is always second argument.
+ llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
+ Elts.push_back(DBuilder.createArtificialType(CmdTy));
// Get rest of the arguments.
for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
PE = OMethod->param_end(); PI != PE; ++PI)
@@ -2007,14 +2054,22 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
+ // Function may lack declaration in source code if it is created by Clang
+ // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
+ bool HasDecl = (D != 0);
// Use the location of the declaration.
- SourceLocation Loc = D->getLocation();
-
+ SourceLocation Loc;
+ if (HasDecl)
+ Loc = D->getLocation();
+
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(Loc);
llvm::DIDescriptor FDContext(Unit);
llvm::DIArray TParamsArray;
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (!HasDecl) {
+ // Use llvm function name.
+ Name = Fn->getName();
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// If there is a DISubprogram for this function available then use it.
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
FI = SPCache.find(FD->getCanonicalDecl());
@@ -2035,10 +2090,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
Flags |= llvm::DIDescriptor::FlagPrototyped;
}
if (LinkageName == Name ||
- CGM.getCodeGenOpts().DebugInfo <= CodeGenOptions::DebugLineTablesOnly)
+ CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)
LinkageName = StringRef();
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
@@ -2061,12 +2116,13 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
Name = Name.substr(1);
unsigned LineNo = getLineNumber(Loc);
- if (D->isImplicit())
+ if (!HasDecl || D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
llvm::DIType DIFnType;
llvm::DISubprogram SPDecl;
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (HasDecl &&
+ CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
DIFnType = getOrCreateFunctionType(D, FnType, Unit);
SPDecl = getFunctionDeclaration(D);
} else {
@@ -2089,7 +2145,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
// Push function on region stack.
llvm::MDNode *SPN = SP;
LexicalBlockStack.push_back(SPN);
- RegionMap[D] = llvm::WeakVH(SP);
+ if (HasDecl)
+ RegionMap[D] = llvm::WeakVH(SP);
}
/// EmitLocation - Emit metadata to indicate a change in line/column
@@ -2242,7 +2299,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::Value *Storage,
unsigned ArgNo, CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
@@ -2253,7 +2310,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
else
Ty = getOrCreateType(VD->getType(), Unit);
- // If there is not any debug info for type then do not emit debug info
+ // If there is no debug info for this type then do not emit debug info
// for this variable.
if (!Ty)
return;
@@ -2279,8 +2336,16 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
unsigned Flags = 0;
if (VD->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
+ // If this is the first argument and it is implicit then
+ // give it an object pointer flag.
+ // FIXME: There has to be a better way to do this, but for static
+ // functions there won't be an implicit param at arg1 and
+ // otherwise it is 'self' or 'this'.
+ if (isa<ImplicitParamDecl>(VD) && ArgNo == 1)
+ Flags |= llvm::DIDescriptor::FlagObjectPointer;
+
llvm::MDNode *Scope = LexicalBlockStack.back();
-
+
StringRef Name = VD->getName();
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
@@ -2376,14 +2441,15 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
}
-void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
- const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
+ llvm::Value *Storage,
+ CGBuilderTy &Builder,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (Builder.GetInsertBlock() == 0)
@@ -2399,11 +2465,16 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
else
Ty = getOrCreateType(VD->getType(), Unit);
+ // 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);
+
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
unsigned Column = getColumnNumber(VD->getLocation());
- const llvm::TargetData &target = CGM.getTargetData();
+ const llvm::DataLayout &target = CGM.getDataLayout();
CharUnits offset = CharUnits::fromQuantity(
target.getStructLayout(blockInfo.StructureType)
@@ -2418,7 +2489,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
offset = CGM.getContext()
- .toCharUnitsFromBits(target.getPointerSizeInBits());
+ .toCharUnitsFromBits(target.getPointerSizeInBits(0));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
@@ -2444,7 +2515,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
unsigned ArgNo,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder);
}
@@ -2461,7 +2532,7 @@ namespace {
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::Value *addr,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
const BlockDecl *blockDecl = block.getBlockDecl();
@@ -2475,7 +2546,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
const llvm::StructLayout *blockLayout =
- CGM.getTargetData().getStructLayout(block.StructureType);
+ CGM.getDataLayout().getStructLayout(block.StructureType);
SmallVector<llvm::Value*, 16> fields;
fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
@@ -2606,7 +2677,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(D->getLocation());
unsigned LineNo = getLineNumber(D->getLocation());
@@ -2640,7 +2711,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
/// EmitGlobalVariable - Emit information about an objective-c interface.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ObjCInterfaceDecl *ID) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
unsigned LineNo = getLineNumber(ID->getLocation());
@@ -2666,7 +2737,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
/// EmitGlobalVariable - Emit global variable's debug info.
void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
llvm::Constant *Init) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
// Create the descriptor for the variable.
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
StringRef Name = VD->getName();
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 44cc49ade123..2e88a7376a6c 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -50,6 +50,9 @@ class CGDebugInfo {
llvm::DICompileUnit TheCU;
SourceLocation CurLoc, PrevLoc;
llvm::DIType VTablePtrType;
+ llvm::DIType ClassTy;
+ llvm::DIType ObjTy;
+ llvm::DIType SelTy;
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index be6638e0e57b..887058753e14 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -24,7 +24,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/Type.h"
using namespace clang;
using namespace CodeGen;
@@ -121,7 +121,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
// uniqued. We can't do this in C, though, because there's no
// standard way to agree on which variables are the same (i.e.
// there's no mangling).
- if (getContext().getLangOpts().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
Linkage = CurFn->getLinkage();
@@ -141,7 +141,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
- if (CGF.getContext().getLangOpts().CPlusPlus) {
+ if (CGF.getLangOpts().CPlusPlus) {
StringRef Name = CGM.getMangledName(&D);
return Name.str();
}
@@ -184,12 +184,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
Name = GetStaticDeclName(*this, D, Separator);
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
+ unsigned AddrSpace =
+ CGM.GetGlobalVarAddressSpace(&D, CGM.getContext().getTargetAddressSpace(Ty));
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
CGM.EmitNullConstant(D.getType()), Name, 0,
llvm::GlobalVariable::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(Ty));
+ AddrSpace);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (Linkage != llvm::GlobalValue::InternalLinkage)
GV->setVisibility(CurFn->getVisibility());
@@ -220,7 +222,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
// If constant emission failed, then this should be a C++ static
// initializer.
if (!Init) {
- if (!getContext().getLangOpts().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else if (Builder.GetInsertBlock()) {
// Since we have a static initializer, this global variable can't
@@ -331,7 +333,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
if (DI &&
- CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
DI->EmitGlobalVariable(var, &D);
}
@@ -704,9 +706,8 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
/// stores that would be required.
static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
bool isVolatile, CGBuilderTy &Builder) {
- // Zero doesn't require a store.
- if (Init->isNullValue() || isa<llvm::UndefValue>(Init))
- return;
+ assert(!Init->isNullValue() && !isa<llvm::UndefValue>(Init) &&
+ "called emitStoresForInitAfterMemset for zero or undef value.");
if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
@@ -719,10 +720,11 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
dyn_cast<llvm::ConstantDataSequential>(Init)) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
llvm::Constant *Elt = CDS->getElementAsConstant(i);
-
- // Get a pointer to the element and emit it.
- emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- isVolatile, Builder);
+
+ // If necessary, get a pointer to the element and emit it.
+ if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
+ emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
+ isVolatile, Builder);
}
return;
}
@@ -732,9 +734,11 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
- // Get a pointer to the element and emit it.
- emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- isVolatile, Builder);
+
+ // If necessary, get a pointer to the element and emit it.
+ if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
+ emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
+ isVolatile, Builder);
}
}
@@ -791,7 +795,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
- bool NRVO = getContext().getLangOpts().ElideConstructors &&
+ bool NRVO = getLangOpts().ElideConstructors &&
D.isNRVOVariable();
// If this value is a POD array or struct with a statically
@@ -910,7 +914,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Emit debug info for local var declaration.
if (HaveInsertPoint())
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
if (Target.useGlobalsForAutomaticVariables()) {
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr),
@@ -1056,10 +1061,11 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
// If the initializer is all or mostly zeros, codegen with memset then do
// a few stores afterward.
if (shouldUseMemSetPlusStoresToInitialize(constant,
- CGM.getTargetData().getTypeAllocSize(constant->getType()))) {
+ CGM.getDataLayout().getTypeAllocSize(constant->getType()))) {
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
alignment.getQuantity(), isVolatile);
- if (!constant->isNullValue()) {
+ // Zero and undef don't require a stores.
+ if (!constant->isNullValue() && !isa<llvm::UndefValue>(constant)) {
Loc = Builder.CreateBitCast(Loc, constant->getType()->getPointerTo());
emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder);
}
@@ -1493,8 +1499,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
LocalDeclMap[&D] = Arg;
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().DebugInfo >=
- CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder);
}
@@ -1576,7 +1582,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// Emit debug info for param declaration.
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 492b95ad155b..65be3c19fb88 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -16,6 +16,7 @@
#include "CGCXXABI.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;
@@ -163,6 +164,9 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM,
CodeGenFunction CGF(CGM);
+ // Initialize debug info if needed.
+ CGF.maybeInitializeDebugInfo();
+
CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, fn,
CGM.getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -218,7 +222,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &CGM.getModule());
- if (!CGM.getContext().getLangOpts().AppleKext) {
+ if (!CGM.getLangOpts().AppleKext) {
// Set the section if needed.
if (const char *Section =
CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier())
@@ -228,8 +232,8 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (CGM.getLangOpts().AddressSanitizer)
- Fn->addFnAttr(llvm::Attribute::AddressSafety);
+ if (CGM.getLangOpts().SanitizeAddress)
+ Fn->addFnAttr(llvm::Attributes::AddressSafety);
return Fn;
}
@@ -252,8 +256,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
DelayedCXXInitPosition.erase(D);
- }
- else {
+ } else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
DelayedCXXInitPosition.find(D);
if (I == DelayedCXXInitPosition.end()) {
@@ -276,28 +279,50 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- // Create our global initialization function.
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
+ // Create our global initialization function.
if (!PrioritizedCXXGlobalInits.empty()) {
SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
- PrioritizedCXXGlobalInits.end());
- for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) {
- llvm::Function *Fn = PrioritizedCXXGlobalInits[i].second;
- LocalCXXGlobalInits.push_back(Fn);
- }
- LocalCXXGlobalInits.append(CXXGlobalInits.begin(), CXXGlobalInits.end());
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+ PrioritizedCXXGlobalInits.end());
+ // Iterate over "chunks" of ctors with same priority and emit each chunk
+ // into separate function. Note - everything is sorted first by priority,
+ // second - by lex order, so we emit ctor functions in proper order.
+ for (SmallVectorImpl<GlobalInitData >::iterator
+ I = PrioritizedCXXGlobalInits.begin(),
+ E = PrioritizedCXXGlobalInits.end(); I != E; ) {
+ SmallVectorImpl<GlobalInitData >::iterator
+ PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp());
+
+ LocalCXXGlobalInits.clear();
+ unsigned Priority = I->first.priority;
+ // Compute the function suffix from priority. Prepend with zeroes to make
+ // sure the function names are also ordered as priorities.
+ std::string PrioritySuffix = llvm::utostr(Priority);
+ // Priority is always <= 65535 (enforced by sema)..
+ PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
+ llvm::Function *Fn =
+ CreateGlobalInitOrDestructFunction(*this, FTy,
+ "_GLOBAL__I_" + PrioritySuffix);
+
+ for (; I < PrioE; ++I)
+ LocalCXXGlobalInits.push_back(I->second);
+
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&LocalCXXGlobalInits[0],
LocalCXXGlobalInits.size());
+ AddGlobalCtor(Fn, Priority);
+ }
}
- else
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
- &CXXGlobalInits[0],
- CXXGlobalInits.size());
+
+ llvm::Function *Fn =
+ CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
+
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+ &CXXGlobalInits[0],
+ CXXGlobalInits.size());
AddGlobalCtor(Fn);
+
CXXGlobalInits.clear();
PrioritizedCXXGlobalInits.clear();
}
@@ -321,8 +346,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit) {
- if (CGM.getModuleDebugInfo() && !D->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getModuleDebugInfo();
+ // Check if we need to emit debug info for variable initializer.
+ if (!D->hasAttr<NoDebugAttr>())
+ maybeInitializeDebugInfo();
StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
@@ -344,6 +370,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
llvm::Constant **Decls,
unsigned NumDecls) {
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
+
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -369,6 +398,9 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
+
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -405,6 +437,9 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
+
StartFunction(GlobalDecl(), getContext().VoidTy, fn, FI, args,
SourceLocation());
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index ba9c2967cd3d..86dee5a4ab98 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -307,14 +307,15 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
/// aggressive about only using the ObjC++ personality in a function
/// when it really needs it.
void CodeGenModule::SimplifyPersonality() {
- // For now, this is really a Darwin-specific operation.
- if (!Context.getTargetInfo().getTriple().isOSDarwin())
- return;
-
// If we're not in ObjC++ -fexceptions, there's nothing to do.
if (!LangOpts.CPlusPlus || !LangOpts.ObjC1 || !LangOpts.Exceptions)
return;
+ // Both the problem this endeavors to fix and the way the logic
+ // above works is specific to the NeXT runtime.
+ if (!LangOpts.ObjCRuntime.isNeXTFamily())
+ return;
+
const EHPersonality &ObjCXX = EHPersonality::get(LangOpts);
const EHPersonality &CXX = getCXXPersonality(LangOpts);
if (&ObjCXX == &CXX)
@@ -534,7 +535,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF,
llvm::Value *zero = CGF.Builder.getInt32(0);
llvm::Value *failsFilter =
CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails");
- CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock());
+ CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock(false));
CGF.EmitBlock(unexpectedBB);
}
@@ -614,7 +615,7 @@ CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) {
// The dispatch block for the end of the scope chain is a block that
// just resumes unwinding.
if (si == EHStack.stable_end())
- return getEHResumeBlock();
+ return getEHResumeBlock(true);
// Otherwise, we should look at the actual scope.
EHScope &scope = *EHStack.find(si);
@@ -1546,7 +1547,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
return TerminateHandler;
}
-llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
+llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
if (EHResumeBlock) return EHResumeBlock;
CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
@@ -1560,7 +1561,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
const char *RethrowName = Personality.CatchallRethrowFn;
- if (RethrowName != 0) {
+ if (RethrowName != 0 && !isCleanup) {
Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
getExceptionFromSlot())
->setDoesNotReturn();
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 1fe4c18badc6..63cc5b515da8 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -26,7 +26,8 @@
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
#include "llvm/MDBuilder.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
+#include "llvm/ADT/Hashing.h"
using namespace clang;
using namespace CodeGen;
@@ -156,50 +157,6 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
}
}
-namespace {
-/// \brief An adjustment to be made to the temporary created when emitting a
-/// reference binding, which accesses a particular subobject of that temporary.
- struct SubobjectAdjustment {
- enum {
- DerivedToBaseAdjustment,
- FieldAdjustment,
- MemberPointerAdjustment
- } Kind;
-
- union {
- struct {
- const CastExpr *BasePath;
- const CXXRecordDecl *DerivedClass;
- } DerivedToBase;
-
- FieldDecl *Field;
-
- struct {
- const MemberPointerType *MPT;
- llvm::Value *Ptr;
- } Ptr;
- };
-
- SubobjectAdjustment(const CastExpr *BasePath,
- const CXXRecordDecl *DerivedClass)
- : Kind(DerivedToBaseAdjustment) {
- DerivedToBase.BasePath = BasePath;
- DerivedToBase.DerivedClass = DerivedClass;
- }
-
- SubobjectAdjustment(FieldDecl *Field)
- : Kind(FieldAdjustment) {
- this->Field = Field;
- }
-
- SubobjectAdjustment(const MemberPointerType *MPT, llvm::Value *Ptr)
- : Kind(MemberPointerAdjustment) {
- this->Ptr.MPT = MPT;
- this->Ptr.Ptr = Ptr;
- }
- };
-}
-
static llvm::Value *
CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
const NamedDecl *InitializedDecl) {
@@ -232,32 +189,18 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
const CXXDestructorDecl *&ReferenceTemporaryDtor,
QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
- // Look through single-element init lists that claim to be lvalues. They're
- // just syntactic wrappers in this case.
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->getNumInits() == 1 && ILE->isGLValue())
- E = ILE->getInit(0);
- }
-
- // Look through expressions for materialized temporaries (for now).
- if (const MaterializeTemporaryExpr *M
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- // Objective-C++ ARC:
- // If we are binding a reference to a temporary that has ownership, we
- // need to perform retain/release operations on the temporary.
- if (CGF.getContext().getLangOpts().ObjCAutoRefCount &&
- E->getType()->isObjCLifetimeType() &&
- (E->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
- E->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
- E->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
- ObjCARCReferenceLifetimeType = E->getType();
-
- E = M->GetTemporaryExpr();
- }
+ const MaterializeTemporaryExpr *M = NULL;
+ E = E->findMaterializedTemporary(M);
+ // Objective-C++ ARC:
+ // If we are binding a reference to a temporary that has ownership, we
+ // need to perform retain/release operations on the temporary.
+ if (M && CGF.getLangOpts().ObjCAutoRefCount &&
+ M->getType()->isObjCLifetimeType() &&
+ (M->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
+ M->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
+ M->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
+ ObjCARCReferenceLifetimeType = M->getType();
- if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
- E = DAE->getExpr();
-
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
CGF.enterFullExpression(EWC);
CodeGenFunction::RunCleanupsScope Scope(CGF);
@@ -335,54 +278,13 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
return ReferenceTemporary;
}
-
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- while (true) {
- E = E->IgnoreParens();
-
- if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
- if ((CE->getCastKind() == CK_DerivedToBase ||
- CE->getCastKind() == CK_UncheckedDerivedToBase) &&
- E->getType()->isRecordType()) {
- E = CE->getSubExpr();
- CXXRecordDecl *Derived
- = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
- Adjustments.push_back(SubobjectAdjustment(CE, Derived));
- continue;
- }
-
- if (CE->getCastKind() == CK_NoOp) {
- E = CE->getSubExpr();
- continue;
- }
- } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (!ME->isArrow() && ME->getBase()->isRValue()) {
- assert(ME->getBase()->getType()->isRecordType());
- if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- E = ME->getBase();
- Adjustments.push_back(SubobjectAdjustment(Field));
- continue;
- }
- }
- } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- if (BO->isPtrMemOp()) {
- assert(BO->getLHS()->isRValue());
- E = BO->getLHS();
- const MemberPointerType *MPT =
- BO->getRHS()->getType()->getAs<MemberPointerType>();
- llvm::Value *Ptr = CGF.EmitScalarExpr(BO->getRHS());
- Adjustments.push_back(SubobjectAdjustment(MPT, Ptr));
- }
- }
- if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
- if (opaque->getType()->isRecordType())
- return CGF.EmitOpaqueValueLValue(opaque).getAddress();
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ E = E->skipRValueSubobjectAdjustments(Adjustments);
+ if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
+ if (opaque->getType()->isRecordType())
+ return CGF.EmitOpaqueValueLValue(opaque).getAddress();
- // Nothing changed.
- break;
- }
-
// Create a reference temporary if necessary.
AggValueSlot AggSlot = AggValueSlot::ignored();
if (CGF.hasAggregateLLVMType(E->getType()) &&
@@ -446,8 +348,9 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
}
case SubobjectAdjustment::MemberPointerAdjustment: {
+ llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
- CGF, Object, Adjustment.Ptr.Ptr, Adjustment.Ptr.MPT);
+ CGF, Object, Ptr, Adjustment.Ptr.MPT);
break;
}
}
@@ -486,6 +389,15 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
ReferenceTemporaryDtor,
ObjCARCReferenceLifetimeType,
InitializedDecl);
+ if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) {
+ // C++11 [dcl.ref]p5 (as amended by core issue 453):
+ // If a glvalue to which a reference is directly bound designates neither
+ // an existing object or function of an appropriate type nor a region of
+ // storage of suitable size and alignment to contain an object of the
+ // reference's type, the behavior is undefined.
+ QualType Ty = E->getType();
+ EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
+ }
if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull())
return RValue::get(Value);
@@ -549,22 +461,133 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
->getZExtValue();
}
-void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
- if (!CatchUndefined)
+/// Emit the hash_16_bytes function from include/llvm/ADT/Hashing.h.
+static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
+ llvm::Value *High) {
+ llvm::Value *KMul = Builder.getInt64(0x9ddfea08eb382d69ULL);
+ llvm::Value *K47 = Builder.getInt64(47);
+ llvm::Value *A0 = Builder.CreateMul(Builder.CreateXor(Low, High), KMul);
+ llvm::Value *A1 = Builder.CreateXor(Builder.CreateLShr(A0, K47), A0);
+ llvm::Value *B0 = Builder.CreateMul(Builder.CreateXor(High, A1), KMul);
+ llvm::Value *B1 = Builder.CreateXor(Builder.CreateLShr(B0, K47), B0);
+ return Builder.CreateMul(B1, KMul);
+}
+
+void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
+ llvm::Value *Address,
+ QualType Ty, CharUnits Alignment) {
+ if (!SanitizePerformTypeCheck)
return;
- // This needs to be to the standard address space.
- Address = Builder.CreateBitCast(Address, Int8PtrTy);
+ // Don't check pointers outside the default address space. The null check
+ // isn't correct, the object-size check isn't supported by LLVM, and we can't
+ // communicate the addresses to the runtime handler for the vptr check.
+ if (Address->getType()->getPointerAddressSpace())
+ return;
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy);
+ llvm::Value *Cond = 0;
- llvm::Value *Min = Builder.getFalse();
- llvm::Value *C = Builder.CreateCall2(F, Address, Min);
- llvm::BasicBlock *Cont = createBasicBlock();
- Builder.CreateCondBr(Builder.CreateICmpUGE(C,
- llvm::ConstantInt::get(IntPtrTy, Size)),
- Cont, getTrapBB());
- EmitBlock(Cont);
+ if (getLangOpts().SanitizeNull) {
+ // The glvalue must not be an empty glvalue.
+ Cond = Builder.CreateICmpNE(
+ Address, llvm::Constant::getNullValue(Address->getType()));
+ }
+
+ if (getLangOpts().SanitizeObjectSize && !Ty->isIncompleteType()) {
+ uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
+
+ // The glvalue must refer to a large enough storage region.
+ // FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation
+ // to check this.
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy);
+ llvm::Value *Min = Builder.getFalse();
+ llvm::Value *CastAddr = Builder.CreateBitCast(Address, Int8PtrTy);
+ llvm::Value *LargeEnough =
+ Builder.CreateICmpUGE(Builder.CreateCall2(F, CastAddr, Min),
+ llvm::ConstantInt::get(IntPtrTy, Size));
+ Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough;
+ }
+
+ uint64_t AlignVal = 0;
+
+ if (getLangOpts().SanitizeAlignment) {
+ AlignVal = Alignment.getQuantity();
+ if (!Ty->isIncompleteType() && !AlignVal)
+ AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
+
+ // The glvalue must be suitably aligned.
+ if (AlignVal) {
+ llvm::Value *Align =
+ Builder.CreateAnd(Builder.CreatePtrToInt(Address, IntPtrTy),
+ llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
+ llvm::Value *Aligned =
+ Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
+ Cond = Cond ? Builder.CreateAnd(Cond, Aligned) : Aligned;
+ }
+ }
+
+ if (Cond) {
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ llvm::ConstantInt::get(SizeTy, AlignVal),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ EmitCheck(Cond, "type_mismatch", StaticData, Address);
+ }
+
+ // If possible, check that the vptr indicates that there is a subobject of
+ // type Ty at offset zero within this object.
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (getLangOpts().SanitizeVptr && TCK != TCK_ConstructorCall &&
+ 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;
+ llvm::raw_svector_ostream Out(MangledName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
+ Out);
+ llvm::hash_code TypeHash = hash_value(Out.str());
+
+ // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
+ llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
+ llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0);
+ llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy);
+ llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
+ llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
+
+ llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
+ Hash = Builder.CreateTrunc(Hash, IntPtrTy);
+
+ // Look the hash up in our cache.
+ const int CacheSize = 128;
+ llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize);
+ llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable,
+ "__ubsan_vptr_type_cache");
+ llvm::Value *Slot = Builder.CreateAnd(Hash,
+ llvm::ConstantInt::get(IntPtrTy,
+ CacheSize-1));
+ llvm::Value *Indices[] = { Builder.getInt32(0), Slot };
+ llvm::Value *CacheVal =
+ Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices));
+
+ // If the hash isn't in the cache, call a runtime handler to perform the
+ // hard work of checking whether the vptr is for an object of the right
+ // type. This will either fill in the cache and return, or produce a
+ // diagnostic.
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ llvm::Value *DynamicData[] = { Address, Hash };
+ EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
+ "dynamic_type_cache_miss", StaticData, DynamicData, true);
+ }
}
@@ -641,11 +664,11 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
return MakeAddrLValue(llvm::UndefValue::get(Ty), E->getType());
}
-LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) {
+LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LValue LV = EmitLValue(E);
if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple())
- EmitCheck(LV.getAddress(),
- getContext().getTypeSizeInChars(E->getType()).getQuantity());
+ EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(),
+ E->getType(), LV.getAlignment());
return LV;
}
@@ -672,7 +695,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
llvm_unreachable("cannot emit a property reference directly");
case Expr::ObjCSelectorExprClass:
- return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
+ return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
case Expr::ObjCIsaExprClass:
return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
case Expr::BinaryOperatorClass:
@@ -709,6 +732,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
case Expr::CXXBindTemporaryExprClass:
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
+ case Expr::CXXUuidofExprClass:
+ return EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E));
case Expr::LambdaExprClass:
return EmitLambdaLValue(cast<LambdaExpr>(E));
@@ -1124,7 +1149,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// Get the output type.
llvm::Type *ResLTy = ConvertType(LV.getType());
- unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
+ unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
// Compute the result as an OR of all of the individual component accesses.
llvm::Value *Res = 0;
@@ -1322,7 +1347,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// Get the output type.
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
- unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
+ unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
@@ -1645,6 +1670,21 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
CharUnits Alignment = getContext().getDeclAlign(ND);
QualType T = E->getType();
+ // A DeclRefExpr for a reference initialized by a constant expression can
+ // appear without being odr-used. Directly emit the constant initializer.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ const Expr *Init = VD->getAnyInitializer(VD);
+ if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
+ VD->isUsableInConstantExpressions(getContext()) &&
+ VD->checkInitIsICE()) {
+ llvm::Constant *Val =
+ CGM.EmitConstantValue(*VD->evaluateValue(), VD->getType(), this);
+ assert(Val && "failed to emit reference constant expression");
+ // FIXME: Eventually we will want to emit vector element references.
+ return MakeAddrLValue(Val, T, Alignment);
+ }
+ }
+
// FIXME: We should be able to assert this for FunctionDecls as well!
// FIXME: We should be able to assert this for all DeclRefExprs, not just
// those with a valid source location.
@@ -1655,7 +1695,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (ND->hasAttr<WeakRefAttr>()) {
const ValueDecl *VD = cast<ValueDecl>(ND);
llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD);
- return MakeAddrLValue(Aliasee, E->getType(), Alignment);
+ return MakeAddrLValue(Aliasee, T, Alignment);
}
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
@@ -1683,9 +1723,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
}
assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
- CharUnits alignment = getContext().getDeclAlign(VD);
return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable),
- E->getType(), alignment);
+ T, Alignment);
}
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
@@ -1736,8 +1775,8 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
// of a pointer to object; as in void foo (__weak id *param); *param = 0;
// But, we continue to generate __strong write barrier on indirect write
// into a pointer to object.
- if (getContext().getLangOpts().ObjC1 &&
- getContext().getLangOpts().getGC() != LangOptions::NonGC &&
+ if (getLangOpts().ObjC1 &&
+ getLangOpts().getGC() != LangOptions::NonGC &&
LV.isObjCWeak())
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
return LV;
@@ -1815,8 +1854,9 @@ GetAddrOfConstantWideString(StringRef Str,
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
SmallString<32>& Target) {
Target.resize(CharByteWidth * (Source.size() + 1));
- char* ResultPtr = &Target[0];
- bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr);
+ char *ResultPtr = &Target[0];
+ const UTF8 *ErrorPtr;
+ bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr);
(void)success;
assert(success);
Target.resize(ResultPtr - &Target[0]);
@@ -1888,33 +1928,167 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
}
}
-llvm::BasicBlock *CodeGenFunction::getTrapBB() {
- const CodeGenOptions &GCO = CGM.getCodeGenOpts();
+/// Emit a type description suitable for use by a runtime sanitizer library. The
+/// format of a type descriptor is
+///
+/// \code
+/// { i16 TypeKind, i16 TypeInfo }
+/// \endcode
+///
+/// followed by an array of i8 containing the type name. TypeKind is 0 for an
+/// integer, 1 for a floating point value, and -1 for anything else.
+llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
+ // FIXME: Only emit each type's descriptor once.
+ uint16_t TypeKind = -1;
+ uint16_t TypeInfo = 0;
+
+ if (T->isIntegerType()) {
+ TypeKind = 0;
+ TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
+ T->isSignedIntegerType();
+ } else if (T->isFloatingType()) {
+ TypeKind = 1;
+ TypeInfo = getContext().getTypeSize(T);
+ }
+
+ // Format the type name as if for a diagnostic, including quotes and
+ // optionally an 'aka'.
+ llvm::SmallString<32> Buffer;
+ CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
+ (intptr_t)T.getAsOpaquePtr(),
+ 0, 0, 0, 0, 0, 0, Buffer,
+ ArrayRef<intptr_t>());
+
+ llvm::Constant *Components[] = {
+ Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo),
+ llvm::ConstantDataArray::getString(getLLVMContext(), Buffer)
+ };
+ llvm::Constant *Descriptor = llvm::ConstantStruct::getAnon(Components);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Descriptor->getType(),
+ /*isConstant=*/true,
+ llvm::GlobalVariable::PrivateLinkage,
+ Descriptor);
+ GV->setUnnamedAddr(true);
+ return GV;
+}
- // If we are not optimzing, don't collapse all calls to trap in the function
- // to the same call, that way, in the debugger they can see which operation
- // did in fact fail. If we are optimizing, we collapse all calls to trap down
- // to just one per function to save on codesize.
- if (GCO.OptimizationLevel && TrapBB)
- return TrapBB;
+llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
+ llvm::Type *TargetTy = IntPtrTy;
+
+ // Integers which fit in intptr_t are zero-extended and passed directly.
+ if (V->getType()->isIntegerTy() &&
+ V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth())
+ return Builder.CreateZExt(V, TargetTy);
+
+ // Pointers are passed directly, everything else is passed by address.
+ if (!V->getType()->isPointerTy()) {
+ llvm::Value *Ptr = Builder.CreateAlloca(V->getType());
+ Builder.CreateStore(V, Ptr);
+ V = Ptr;
+ }
+ return Builder.CreatePtrToInt(V, TargetTy);
+}
+
+/// \brief Emit a representation of a SourceLocation for passing to a handler
+/// in a sanitizer runtime library. The format for this data is:
+/// \code
+/// struct SourceLocation {
+/// const char *Filename;
+/// int32_t Line, Column;
+/// };
+/// \endcode
+/// For an invalid SourceLocation, the Filename pointer is null.
+llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
+ PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
+
+ llvm::Constant *Data[] = {
+ // FIXME: Only emit each file name once.
+ PLoc.isValid() ? cast<llvm::Constant>(
+ Builder.CreateGlobalStringPtr(PLoc.getFilename()))
+ : llvm::Constant::getNullValue(Int8PtrTy),
+ Builder.getInt32(PLoc.getLine()),
+ Builder.getInt32(PLoc.getColumn())
+ };
- llvm::BasicBlock *Cont = 0;
- if (HaveInsertPoint()) {
- Cont = createBasicBlock("cont");
- EmitBranch(Cont);
+ return llvm::ConstantStruct::getAnon(Data);
+}
+
+void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
+ llvm::ArrayRef<llvm::Constant *> StaticArgs,
+ llvm::ArrayRef<llvm::Value *> DynamicArgs,
+ bool Recoverable) {
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+
+ llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName);
+ Builder.CreateCondBr(Checked, Cont, Handler);
+ EmitBlock(Handler);
+
+ llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
+ llvm::GlobalValue *InfoPtr =
+ new llvm::GlobalVariable(CGM.getModule(), Info->getType(), true,
+ llvm::GlobalVariable::PrivateLinkage, Info);
+ InfoPtr->setUnnamedAddr(true);
+
+ llvm::SmallVector<llvm::Value *, 4> Args;
+ llvm::SmallVector<llvm::Type *, 4> ArgTypes;
+ Args.reserve(DynamicArgs.size() + 1);
+ ArgTypes.reserve(DynamicArgs.size() + 1);
+
+ // Handler functions take an i8* pointing to the (handler-specific) static
+ // information block, followed by a sequence of intptr_t arguments
+ // representing operand values.
+ Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
+ ArgTypes.push_back(Int8PtrTy);
+ for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
+ Args.push_back(EmitCheckValue(DynamicArgs[i]));
+ ArgTypes.push_back(IntPtrTy);
+ }
+
+ 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) {
+ Builder.CreateBr(Cont);
+ } else {
+ HandlerCall->setDoesNotReturn();
+ HandlerCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
}
- TrapBB = createBasicBlock("trap");
- EmitBlock(TrapBB);
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
- llvm::CallInst *TrapCall = Builder.CreateCall(F);
- TrapCall->setDoesNotReturn();
- TrapCall->setDoesNotThrow();
- Builder.CreateUnreachable();
+ EmitBlock(Cont);
+}
- if (Cont)
- EmitBlock(Cont);
- return TrapBB;
+void CodeGenFunction::EmitTrapvCheck(llvm::Value *Checked) {
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+
+ // If we're optimizing, collapse all calls to trap down to just one per
+ // function to save on code size.
+ if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) {
+ TrapBB = createBasicBlock("trap");
+ Builder.CreateCondBr(Checked, Cont, TrapBB);
+ EmitBlock(TrapBB);
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
+ llvm::CallInst *TrapCall = Builder.CreateCall(F);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ } else {
+ Builder.CreateCondBr(Checked, Cont, TrapBB);
+ }
+
+ EmitBlock(Cont);
}
/// isSimpleArrayDecayOperand - If the specified expr is a simple decay from an
@@ -2007,14 +2181,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// Propagate the alignment from the array itself to the result.
ArrayAlignment = ArrayLV.getAlignment();
- if (getContext().getLangOpts().isSignedOverflowDefined())
+ if (getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx");
else
Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx");
} else {
// The base must be a pointer, which is not an aggregate. Emit it.
llvm::Value *Base = EmitScalarExpr(E->getBase());
- if (getContext().getLangOpts().isSignedOverflowDefined())
+ if (getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
else
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
@@ -2037,8 +2211,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace());
- if (getContext().getLangOpts().ObjC1 &&
- getContext().getLangOpts().getGC() != LangOptions::NonGC) {
+ if (getLangOpts().ObjC1 &&
+ getLangOpts().getGC() != LangOptions::NonGC) {
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
setObjCGCLValueClass(getContext(), E, LV);
}
@@ -2114,11 +2288,13 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
LValue BaseLV;
- if (E->isArrow())
- BaseLV = MakeNaturalAlignAddrLValue(EmitScalarExpr(BaseExpr),
- BaseExpr->getType()->getPointeeType());
- else
- BaseLV = EmitLValue(BaseExpr);
+ if (E->isArrow()) {
+ llvm::Value *Ptr = EmitScalarExpr(BaseExpr);
+ QualType PtrTy = BaseExpr->getType()->getPointeeType();
+ EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Ptr, PtrTy);
+ BaseLV = MakeNaturalAlignAddrLValue(Ptr, PtrTy);
+ } else
+ BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
NamedDecl *ND = E->getMemberDecl();
if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
@@ -2355,7 +2531,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_Dependent:
llvm_unreachable("dependent cast kind in IR gen!");
-
+
+ case CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
// These two casts are currently treated as no-ops, although they could
// potentially be real operations depending on the target's ABI.
case CK_NonAtomicToAtomic:
@@ -2546,7 +2725,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXPseudoDestructorExpr *PseudoDtor
= dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
QualType DestroyedType = PseudoDtor->getDestroyedType();
- if (getContext().getLangOpts().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
DestroyedType->isObjCLifetimeType() &&
(DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong ||
DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
@@ -2635,7 +2814,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
}
RValue RV = EmitAnyExpr(E->getRHS());
- LValue LV = EmitLValue(E->getLHS());
+ LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
EmitStoreThroughLValue(RV, LV);
return LV;
}
@@ -2677,6 +2856,14 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
return MakeAddrLValue(EmitCXXTypeidExpr(E), E->getType());
}
+llvm::Value *CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
+ return CGM.GetAddrOfUuidDescriptor(E);
+}
+
+LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) {
+ return MakeAddrLValue(EmitCXXUuidofExpr(E), E->getType());
+}
+
LValue
CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
@@ -2977,11 +3164,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
uint64_t Size = sizeChars.getQuantity();
CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
unsigned Align = alignChars.getQuantity();
- unsigned MaxInlineWidth =
- getContext().getTargetInfo().getMaxAtomicInlineWidth();
- bool UseLibcall = (Size != Align || Size > MaxInlineWidth);
-
-
+ 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());
@@ -3177,6 +3363,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
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;
@@ -3194,14 +3387,20 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
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;
@@ -3221,13 +3420,6 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// Long case, when Order isn't obviously constant.
- 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;
-
// Create all the relevant BB's
llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
*AcqRelBB = 0, *SeqCstBB = 0;
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 61f7362ecaef..718e8f999ce7 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -549,8 +549,10 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
case CK_Dynamic: {
+ // FIXME: Can this actually happen? We have no test coverage for it.
assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
- LValue LV = CGF.EmitCheckedLValue(E->getSubExpr());
+ LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(),
+ CodeGenFunction::TCK_Load);
// FIXME: Do we also need to handle property references here?
if (LV.isSimple())
CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
@@ -645,6 +647,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -771,7 +774,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
Visit(E->getRHS());
// Now emit the LHS and copy into it.
- LValue LHS = CGF.EmitLValue(E->getLHS());
+ LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
@@ -1205,7 +1208,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return;
// C++ objects with a user-declared constructor don't need zero'ing.
- if (CGF.getContext().getLangOpts().CPlusPlus)
+ if (CGF.getLangOpts().CPlusPlus)
if (const RecordType *RT = CGF.getContext()
.getBaseElementType(E->getType())->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -1271,10 +1274,11 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Value *SrcPtr, QualType Ty,
bool isVolatile,
- CharUnits alignment) {
+ CharUnits alignment,
+ bool isAssignment) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
- if (getContext().getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
assert((Record->hasTrivialCopyConstructor() ||
@@ -1300,9 +1304,13 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
// implementation handles this case safely. If there is a libc that does not
// safely handle this, we can add a target hook.
- // Get size and alignment info for this aggregate.
- std::pair<CharUnits, CharUnits> TypeInfo =
- getContext().getTypeInfoInChars(Ty);
+ // Get data size and alignment info for this aggregate. If this is an
+ // assignment don't copy the tail padding. Otherwise copying it is fine.
+ std::pair<CharUnits, CharUnits> TypeInfo;
+ if (isAssignment)
+ TypeInfo = getContext().getTypeInfoDataSizeInChars(Ty);
+ else
+ TypeInfo = getContext().getTypeInfoInChars(Ty);
if (alignment.isZero())
alignment = TypeInfo.second;
@@ -1359,11 +1367,17 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
}
}
}
+
+ // Determine the metadata to describe the position of any padding in this
+ // memcpy, as well as the TBAA tags for the members of the struct, in case
+ // the optimizer wishes to expand it in to scalar memory operations.
+ llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty);
Builder.CreateMemCpy(DestPtr, SrcPtr,
llvm::ConstantInt::get(IntPtrTy,
TypeInfo.first.getQuantity()),
- alignment.getQuantity(), isVolatile);
+ alignment.getQuantity(), isVolatile,
+ /*TBAATag=*/0, TBAAStructTag);
}
void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc,
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 31ea1b5448a7..7f640f6e6433 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -24,6 +24,7 @@ using namespace clang;
using namespace CodeGen;
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
+ SourceLocation CallLoc,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
@@ -33,6 +34,13 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
+ // C++11 [class.mfct.non-static]p2:
+ // If a non-static member function of a class X is called for an object that
+ // is not of type X, or of a type derived from X, the behavior is undefined.
+ EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
+ : TCK_MemberCall,
+ CallLoc, This, getContext().getRecordType(MD->getParent()));
+
CallArgList Args;
// Push the this ptr.
@@ -168,8 +176,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
CGDebugInfo *DI = getDebugInfo();
- if (DI && CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo
- && !isa<CallExpr>(ME->getBase())) {
+ if (DI &&
+ CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo &&
+ !isa<CallExpr>(ME->getBase())) {
QualType PQTy = ME->getBase()->IgnoreParenImpCasts()->getType();
if (const PointerType * PTy = dyn_cast<PointerType>(PQTy)) {
DI->getOrCreateRecordType(PTy->getPointeeType(),
@@ -235,7 +244,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// We don't like to generate the trivial copy/move assignment operator
// when it isn't necessary; just produce the proper effect here.
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
- EmitAggregateCopy(This, RHS, CE->getType());
+ EmitAggregateAssign(This, RHS, CE->getType());
return RValue::get(This);
}
@@ -251,16 +260,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
// Compute the function type we're calling.
+ const CXXMethodDecl *CalleeDecl = DevirtualizedMethod ? DevirtualizedMethod : MD;
const CGFunctionInfo *FInfo = 0;
- if (isa<CXXDestructorDecl>(MD))
- FInfo = &CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
+ if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl))
+ FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor,
Dtor_Complete);
- else if (isa<CXXConstructorDecl>(MD))
- FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(
- cast<CXXConstructorDecl>(MD),
- Ctor_Complete);
+ else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl))
+ FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor,
+ Ctor_Complete);
else
- FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(MD);
+ FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl);
llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo);
@@ -277,7 +286,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
if (UseVirtualCall) {
Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty);
} else {
- if (getContext().getLangOpts().AppleKext &&
+ if (getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
@@ -295,7 +304,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
} else if (UseVirtualCall) {
Callee = BuildVirtualCall(MD, This, Ty);
} else {
- if (getContext().getLangOpts().AppleKext &&
+ if (getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
@@ -306,8 +315,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
}
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
- CE->arg_begin(), CE->arg_end());
+ return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
+ /*VTT=*/0, CE->arg_begin(), CE->arg_end());
}
RValue
@@ -337,6 +346,9 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
else
This = EmitLValue(BaseExpr).getAddress();
+ EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This,
+ QualType(MPT->getClass(), 0));
+
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *Callee =
CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, This, MemFnPtr, MPT);
@@ -370,13 +382,13 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
MD->isTrivial()) {
llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
QualType Ty = E->getType();
- EmitAggregateCopy(This, Src, Ty);
+ EmitAggregateAssign(This, Src, Ty);
return RValue::get(This);
}
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
- E->arg_begin() + 1, E->arg_end());
+ return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
+ /*VTT=*/0, E->arg_begin() + 1, E->arg_end());
}
RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -457,7 +469,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
// Elide the constructor if we're constructing from a temporary.
// The temporary check is required because Sema sets this on NRVO
// returns.
- if (getContext().getLangOpts().ElideConstructors && E->isElidable()) {
+ if (getLangOpts().ElideConstructors && E->isElidable()) {
assert(getContext().hasSameUnqualifiedType(E->getType(),
E->getArg(0)->getType()));
if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) {
@@ -878,7 +890,7 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
if (constNum->getZExtValue() <= initializerElements) {
// If there was a cleanup, deactivate it.
if (cleanupDominator)
- DeactivateCleanupBlock(cleanup, cleanupDominator);;
+ DeactivateCleanupBlock(cleanup, cleanupDominator);
return;
}
} else {
@@ -949,7 +961,6 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
if (E->isArray()) {
if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){
CXXConstructorDecl *Ctor = CCE->getConstructor();
- bool RequiresZeroInitialization = false;
if (Ctor->isTrivial()) {
// If new expression did not specify value-initialization, then there
// is no initialization.
@@ -962,13 +973,11 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
return;
}
-
- RequiresZeroInitialization = true;
}
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
CCE->arg_begin(), CCE->arg_end(),
- RequiresZeroInitialization);
+ CCE->requiresZeroInitialization());
return;
} else if (Init && isa<ImplicitValueInitExpr>(Init) &&
CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
@@ -1230,8 +1239,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::BasicBlock *contBB = 0;
llvm::Value *allocation = RV.getScalarVal();
- unsigned AS =
- cast<llvm::PointerType>(allocation->getType())->getAddressSpace();
+ unsigned AS = allocation->getType()->getPointerAddressSpace();
// The null-check means that the initializer is conditionally
// evaluated.
@@ -1377,8 +1385,14 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (UseGlobalDelete) {
// If we're supposed to call the global delete, make sure we do so
// even if the destructor throws.
+
+ // Derive the complete-object pointer, which is what we need
+ // to pass to the deallocation function.
+ llvm::Value *completePtr =
+ CGF.CGM.getCXXABI().adjustToCompleteObject(CGF, Ptr, ElementType);
+
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
- Ptr, OperatorDelete,
+ completePtr, OperatorDelete,
ElementType);
}
@@ -1390,8 +1404,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
= CGF.BuildVirtualCall(Dtor,
UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
Ptr, Ty);
- CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
- 0, 0);
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
+ Ptr, /*VTT=*/0, 0, 0);
if (UseGlobalDelete) {
CGF.PopCleanupBlock();
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 0233745afa91..66b6f8629a52 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -427,6 +427,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -640,7 +641,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
LValue LV = EmitCompoundAssignLValue(E, Func, Val);
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -675,7 +676,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LV = EmitBinAssignLValue(E, Val);
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the assignment.
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index a17a43639ad7..206f74a30258 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -24,7 +24,7 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -79,12 +79,12 @@ private:
CharUnits getAlignment(const llvm::Constant *C) const {
if (Packed) return CharUnits::One();
return CharUnits::fromQuantity(
- CGM.getTargetData().getABITypeAlignment(C->getType()));
+ CGM.getDataLayout().getABITypeAlignment(C->getType()));
}
CharUnits getSizeInChars(const llvm::Constant *C) const {
return CharUnits::fromQuantity(
- CGM.getTargetData().getTypeAllocSize(C->getType()));
+ CGM.getDataLayout().getTypeAllocSize(C->getType()));
}
};
@@ -204,7 +204,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
if (!FitsCompletelyInPreviousByte) {
unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
Tmp = Tmp.lshr(NewFieldWidth);
Tmp = Tmp.trunc(BitsInPreviousByte);
@@ -220,7 +220,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
}
Tmp = Tmp.zext(CharWidth);
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
if (FitsCompletelyInPreviousByte)
Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
} else {
@@ -269,7 +269,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
while (FieldValue.getBitWidth() > CharWidth) {
llvm::APInt Tmp;
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
// We want the high bits.
Tmp =
FieldValue.lshr(FieldValue.getBitWidth() - CharWidth).trunc(CharWidth);
@@ -292,7 +292,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
"Should not have more than a byte left!");
if (FieldValue.getBitWidth() < CharWidth) {
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
unsigned BitWidth = FieldValue.getBitWidth();
FieldValue = FieldValue.zext(CharWidth) << (CharWidth - BitWidth);
@@ -337,7 +337,7 @@ void ConstStructBuilder::ConvertStructToPacked() {
llvm::Constant *C = Elements[i];
CharUnits ElementAlign = CharUnits::fromQuantity(
- CGM.getTargetData().getABITypeAlignment(C->getType()));
+ CGM.getDataLayout().getABITypeAlignment(C->getType()));
CharUnits AlignedElementOffsetInChars =
ElementOffsetInChars.RoundUpToAlignment(ElementAlign);
@@ -379,7 +379,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
unsigned FieldNo = 0;
unsigned ElementNo = 0;
const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ bool IsMsStruct = RD->isMsStruct(CGM.getContext());
for (RecordDecl::field_iterator Field = RD->field_begin(),
FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
@@ -478,7 +478,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
unsigned FieldNo = 0;
const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ bool IsMsStruct = RD->isMsStruct(CGM.getContext());
uint64_t OffsetBits = CGM.getContext().toBits(Offset);
for (RecordDecl::field_iterator Field = RD->field_begin(),
@@ -665,8 +665,8 @@ public:
SmallVector<llvm::Type*, 2> Types;
Elts.push_back(C);
Types.push_back(C->getType());
- unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType());
- unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(destType);
+ unsigned CurSize = CGM.getDataLayout().getTypeAllocSize(C->getType());
+ unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destType);
assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
@@ -691,6 +691,9 @@ public:
case CK_Dependent: llvm_unreachable("saw dependent cast!");
+ case CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
case CK_ReinterpretMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_BaseToDerivedMemberPointer:
@@ -811,11 +814,7 @@ public:
return llvm::ConstantArray::get(AType, Elts);
}
- llvm::Constant *EmitStructInitialization(InitListExpr *ILE) {
- return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
- }
-
- llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) {
+ llvm::Constant *EmitRecordInitialization(InitListExpr *ILE) {
return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
}
@@ -828,10 +827,7 @@ public:
return EmitArrayInitialization(ILE);
if (ILE->getType()->isRecordType())
- return EmitStructInitialization(ILE);
-
- if (ILE->getType()->isUnionType())
- return EmitUnionInitialization(ILE);
+ return EmitRecordInitialization(ILE);
return 0;
}
@@ -999,6 +995,9 @@ public:
T = Typeid->getExprOperand()->getType();
return CGM.GetAddrOfRTTIDescriptor(T);
}
+ case Expr::CXXUuidofExprClass: {
+ return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E));
+ }
}
return 0;
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 1cccafe0d787..b429b1d6e47e 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -28,7 +28,7 @@
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Support/CFG.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdarg>
using namespace clang;
@@ -45,6 +45,7 @@ struct BinOpInfo {
Value *RHS;
QualType Ty; // Computation Type.
BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
+ bool FPContractable;
const Expr *E; // Entire expr, for error unsupported. May not be binop.
};
@@ -80,7 +81,11 @@ public:
llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
- LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); }
+ LValue EmitCheckedLValue(const Expr *E, CodeGenFunction::TypeCheckKind TCK) {
+ return CGF.EmitCheckedLValue(E, TCK);
+ }
+
+ void EmitBinOpCheck(Value *Check, const BinOpInfo &Info);
Value *EmitLoadOfLValue(LValue LV) {
return CGF.EmitLoadOfLValue(LV).getScalarVal();
@@ -90,13 +95,19 @@ public:
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
Value *EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(EmitCheckedLValue(E));
+ return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load));
}
/// EmitConversionToBool - Convert the specified expression value to a
/// boolean (i1) truth value. This is equivalent to "Val != 0".
Value *EmitConversionToBool(Value *Src, QualType DstTy);
+ /// \brief Emit a check that a conversion to or from a floating-point type
+ /// does not overflow.
+ void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType,
+ Value *Src, QualType SrcType,
+ QualType DstType, llvm::Type *DstTy);
+
/// EmitScalarConversion - Emit a conversion from the specified type to the
/// specified destination type, both of which are LLVM scalar types.
Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy);
@@ -391,34 +402,26 @@ public:
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
+ // Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(Ops);
}
}
-
+
if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
}
- bool isTrapvOverflowBehavior() {
- return CGF.getContext().getLangOpts().getSignedOverflowBehavior()
- == LangOptions::SOB_Trapping;
- }
/// Create a binary op that checks for overflow.
/// Currently only supports +, - and *.
Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops);
- // Emit the overflow BB when -ftrapv option is activated.
- void EmitOverflowBB(llvm::BasicBlock *overflowBB) {
- Builder.SetInsertPoint(overflowBB);
- llvm::Function *Trap = CGF.CGM.getIntrinsic(llvm::Intrinsic::trap);
- Builder.CreateCall(Trap);
- Builder.CreateUnreachable();
- }
+
// Check for undefined division and modulus behaviors.
void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
@@ -537,6 +540,110 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
return EmitPointerToBoolConversion(Src);
}
+void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
+ QualType OrigSrcType,
+ Value *Src, QualType SrcType,
+ QualType DstType,
+ llvm::Type *DstTy) {
+ using llvm::APFloat;
+ using llvm::APSInt;
+
+ llvm::Type *SrcTy = Src->getType();
+
+ llvm::Value *Check = 0;
+ if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
+ // Integer to floating-point. This can fail for unsigned short -> __half
+ // or unsigned __int128 -> float.
+ assert(DstType->isFloatingType());
+ bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType();
+
+ APFloat LargestFloat =
+ APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType));
+ APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned);
+
+ bool IsExact;
+ if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero,
+ &IsExact) != APFloat::opOK)
+ // The range of representable values of this floating point type includes
+ // all values of this integer type. Don't need an overflow check.
+ return;
+
+ llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt);
+ if (SrcIsUnsigned)
+ Check = Builder.CreateICmpULE(Src, Max);
+ else {
+ llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt);
+ llvm::Value *GE = Builder.CreateICmpSGE(Src, Min);
+ llvm::Value *LE = Builder.CreateICmpSLE(Src, Max);
+ 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)) {
+ unsigned Width = CGF.getContext().getIntWidth(DstType);
+ bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
+
+ APSInt Min = APSInt::getMinValue(Width, Unsigned);
+ 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);
+
+ APSInt Max = APSInt::getMaxValue(Width, Unsigned);
+ 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);
+ } else {
+ 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);
+
+ 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);
+ }
+
+ 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.
+ llvm::Constant *StaticArgs[] = {
+ CGF.EmitCheckTypeDescriptor(OrigSrcType),
+ CGF.EmitCheckTypeDescriptor(DstType)
+ };
+ CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc);
+}
+
/// EmitScalarConversion - Emit a conversion from the specified type to the
/// specified destination type, both of which are LLVM scalar types.
Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
@@ -547,6 +654,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (DstType->isVoidType()) return 0;
+ llvm::Value *OrigSrc = Src;
+ QualType OrigSrcType = SrcType;
llvm::Type *SrcTy = Src->getType();
// Floating casts might be a bit special: if we're doing casts to / from half
@@ -620,6 +729,12 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
Value *Res = NULL;
llvm::Type *ResTy = DstTy;
+ // An overflowing conversion has undefined behavior if either the source type
+ // or the destination type is a floating-point type.
+ if (CGF.getLangOpts().SanitizeFloatCastOverflow &&
+ (OrigSrcType->isFloatingType() || DstType->isFloatingType()))
+ EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy);
+
// Cast to half via float
if (DstType->isHalfType())
DstTy = CGF.FloatTy;
@@ -686,6 +801,54 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
return llvm::Constant::getNullValue(ConvertType(Ty));
}
+/// \brief Emit a sanitization check for the given "binary" operation (which
+/// might actually be a unary increment which has been lowered to a binary
+/// operation). The check passes if \p Check, which is an \c i1, is \c true.
+void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+ StringRef CheckName;
+ llvm::SmallVector<llvm::Constant *, 4> StaticData;
+ llvm::SmallVector<llvm::Value *, 2> DynamicData;
+
+ BinaryOperatorKind Opcode = Info.Opcode;
+ if (BinaryOperator::isCompoundAssignmentOp(Opcode))
+ Opcode = BinaryOperator::getOpForCompoundAssignment(Opcode);
+
+ StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc()));
+ const UnaryOperator *UO = dyn_cast<UnaryOperator>(Info.E);
+ if (UO && UO->getOpcode() == UO_Minus) {
+ CheckName = "negate_overflow";
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType()));
+ DynamicData.push_back(Info.RHS);
+ } else {
+ if (BinaryOperator::isShiftOp(Opcode)) {
+ // Shift LHS negative or too large, or RHS out of bounds.
+ CheckName = "shift_out_of_bounds";
+ const BinaryOperator *BO = cast<BinaryOperator>(Info.E);
+ StaticData.push_back(
+ CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType()));
+ StaticData.push_back(
+ CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType()));
+ } 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()));
+ } else {
+ // Signed arithmetic overflow (+, -, *).
+ switch (Opcode) {
+ case BO_Add: CheckName = "add_overflow"; break;
+ case BO_Sub: CheckName = "sub_overflow"; break;
+ case BO_Mul: CheckName = "mul_overflow"; break;
+ default: llvm_unreachable("unexpected opcode for bin op check");
+ }
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ }
+ DynamicData.push_back(Info.LHS);
+ DynamicData.push_back(Info.RHS);
+ }
+
+ CGF.EmitCheck(Check, CheckName, StaticData, DynamicData);
+}
+
//===----------------------------------------------------------------------===//
// Visitor Methods
//===----------------------------------------------------------------------===//
@@ -802,7 +965,8 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
// debug info size.
CGDebugInfo *DI = CGF.getDebugInfo();
if (DI &&
- CGF.CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) {
+ CGF.CGM.getCodeGenOpts().getDebugInfo()
+ == CodeGenOptions::LimitedDebugInfo) {
QualType PQTy = E->getBase()->IgnoreParenImpCasts()->getType();
if (const PointerType * PTy = dyn_cast<PointerType>(PQTy))
if (FieldDecl *M = dyn_cast<FieldDecl>(E->getMemberDecl()))
@@ -1032,7 +1196,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// are in the same order as in the CastKind enum.
switch (Kind) {
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
-
+ case CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
case CK_LValueBitCast:
case CK_ObjCObjectLValueCast: {
Value *V = EmitLValue(E).getAddress();
@@ -1055,19 +1221,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Visit(const_cast<Expr*>(E));
case CK_BaseToDerived: {
- const CXXRecordDecl *DerivedClassDecl =
- DestTy->getCXXRecordDeclForPointerType();
-
- return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
+ assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
+
+ return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE));
}
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
- const RecordType *DerivedClassTy =
- E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
- CXXRecordDecl *DerivedClassDecl =
- cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+ const CXXRecordDecl *DerivedClassDecl =
+ E->getType()->getPointeeCXXRecordDecl();
+ assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!");
return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
CE->path_begin(), CE->path_end(),
@@ -1248,17 +1413,20 @@ llvm::Value *ScalarExprEmitter::
EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
llvm::Value *InVal,
llvm::Value *NextVal, bool IsInc) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
+ // Fall through.
case LangOptions::SOB_Trapping:
BinOpInfo BinOp;
BinOp.LHS = InVal;
BinOp.RHS = NextVal;
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Add;
+ BinOp.FPContractable = false;
BinOp.E = E;
return EmitOverflowCheckedBinOp(BinOp);
}
@@ -1300,7 +1468,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Most common case by far: integer increment.
} else if (type->isIntegerType()) {
- llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount);
+ llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
// 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.
@@ -1320,7 +1488,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
= CGF.getContext().getAsVariableArrayType(type)) {
llvm::Value *numElts = CGF.getVLASize(vla).first;
if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, numElts, "vla.inc");
else
value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
@@ -1330,7 +1498,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *amt = Builder.getInt32(amount);
value = CGF.EmitCastToVoidPtr(value);
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.funcptr");
else
value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
@@ -1339,7 +1507,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// For everything else, we can just do a simple increment.
} else {
llvm::Value *amt = Builder.getInt32(amount);
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.ptr");
else
value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
@@ -1400,7 +1568,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *sizeValue =
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
else
value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
@@ -1444,6 +1612,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Sub;
+ BinOp.FPContractable = false;
BinOp.E = E;
return EmitSub(BinOp);
}
@@ -1652,6 +1821,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
Result.RHS = Visit(E->getRHS());
Result.Ty = E->getType();
Result.Opcode = E->getOpcode();
+ Result.FPContractable = E->isFPContractable();
Result.E = E;
return Result;
}
@@ -1678,9 +1848,10 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.RHS = Visit(E->getRHS());
OpInfo.Ty = E->getComputationResultType();
OpInfo.Opcode = E->getOpcode();
+ OpInfo.FPContractable = false;
OpInfo.E = E;
// Load/convert the LHS.
- LValue LHSLV = EmitCheckedLValue(E->getLHS());
+ LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
OpInfo.LHS = EmitLoadOfLValue(LHSLV);
llvm::PHINode *atomicPHI = 0;
@@ -1740,7 +1911,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
return 0;
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return RHS;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -1752,56 +1923,44 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
}
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
- const BinOpInfo &Ops,
- llvm::Value *Zero, bool isDiv) {
- llvm::Function::iterator insertPt = Builder.GetInsertBlock();
- llvm::BasicBlock *contBB =
- CGF.createBasicBlock(isDiv ? "div.cont" : "rem.cont", CGF.CurFn,
- llvm::next(insertPt));
- llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
+ const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
+ llvm::Value *Cond = 0;
+
+ if (CGF.getLangOpts().SanitizeDivideByZero)
+ Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
- llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
+ if (CGF.getLangOpts().SanitizeSignedIntegerOverflow &&
+ Ops.Ty->hasSignedIntegerRepresentation()) {
+ llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::Value *IntMin =
Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth()));
llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL);
- llvm::Value *Cond1 = Builder.CreateICmpEQ(Ops.RHS, Zero);
- llvm::Value *LHSCmp = Builder.CreateICmpEQ(Ops.LHS, IntMin);
- llvm::Value *RHSCmp = Builder.CreateICmpEQ(Ops.RHS, NegOne);
- llvm::Value *Cond2 = Builder.CreateAnd(LHSCmp, RHSCmp, "and");
- Builder.CreateCondBr(Builder.CreateOr(Cond1, Cond2, "or"),
- overflowBB, contBB);
- } else {
- CGF.Builder.CreateCondBr(Builder.CreateICmpEQ(Ops.RHS, Zero),
- overflowBB, contBB);
+ llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin);
+ llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne);
+ llvm::Value *Overflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
+ Cond = Cond ? Builder.CreateAnd(Cond, Overflow, "and") : Overflow;
}
- EmitOverflowBB(overflowBB);
- Builder.SetInsertPoint(contBB);
+
+ if (Cond)
+ EmitBinOpCheck(Cond, Ops);
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if (isTrapvOverflowBehavior()) {
+ if (CGF.getLangOpts().SanitizeDivideByZero ||
+ CGF.getLangOpts().SanitizeSignedIntegerOverflow) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
if (Ops.Ty->isIntegerType())
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- else if (Ops.Ty->isRealFloatingType()) {
- llvm::Function::iterator insertPt = Builder.GetInsertBlock();
- llvm::BasicBlock *DivCont = CGF.createBasicBlock("div.cont", CGF.CurFn,
- llvm::next(insertPt));
- llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow",
- CGF.CurFn);
- CGF.Builder.CreateCondBr(Builder.CreateFCmpOEQ(Ops.RHS, Zero),
- overflowBB, DivCont);
- EmitOverflowBB(overflowBB);
- Builder.SetInsertPoint(DivCont);
- }
+ else if (CGF.getLangOpts().SanitizeDivideByZero &&
+ Ops.Ty->isRealFloatingType())
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
}
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
- if (CGF.getContext().getLangOpts().OpenCL) {
+ if (CGF.getLangOpts().OpenCL) {
// OpenCL 1.1 7.4: minimum accuracy of single precision / is 2.5ulp
llvm::Type *ValTy = Val->getType();
if (ValTy->isFloatTy() ||
@@ -1819,7 +1978,7 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
- if (isTrapvOverflowBehavior()) {
+ if (CGF.getLangOpts().SanitizeDivideByZero) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
if (Ops.Ty->isIntegerType())
@@ -1866,6 +2025,19 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Value *result = Builder.CreateExtractValue(resultAndOverflow, 0);
Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1);
+ // Handle overflow with llvm.trap if no custom handler has been specified.
+ const std::string *handlerName =
+ &CGF.getLangOpts().OverflowHandler;
+ 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)
+ EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
+ else
+ CGF.EmitTrapvCheck(Builder.CreateNot(overflow));
+ return result;
+ }
+
// Branch in case of overflow.
llvm::BasicBlock *initialBB = Builder.GetInsertBlock();
llvm::Function::iterator insertPt = initialBB;
@@ -1875,15 +2047,6 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Builder.CreateCondBr(overflow, overflowBB, continueBB);
- // Handle overflow with llvm.trap.
- const std::string *handlerName =
- &CGF.getContext().getLangOpts().OverflowHandler;
- if (handlerName->empty()) {
- EmitOverflowBB(overflowBB);
- Builder.SetInsertPoint(continueBB);
- return result;
- }
-
// If an overflow handler is set, then we want to call it and then use its
// result, if it returns.
Builder.SetInsertPoint(overflowBB);
@@ -2001,24 +2164,106 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
}
+// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
+// Addend. Use negMul and negAdd to negate the first operand of the Mul or
+// the add operand respectively. This allows fmuladd to represent a*b-c, or
+// c-a*b. Patterns in LLVM should catch the negated forms and translate them to
+// efficient operations.
+static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend,
+ const CodeGenFunction &CGF, CGBuilderTy &Builder,
+ bool negMul, bool negAdd) {
+ assert(!(negMul && negAdd) && "Only one of negMul and negAdd should be set.");
+
+ Value *MulOp0 = MulOp->getOperand(0);
+ Value *MulOp1 = MulOp->getOperand(1);
+ if (negMul) {
+ MulOp0 =
+ Builder.CreateFSub(
+ llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0,
+ "neg");
+ } else if (negAdd) {
+ Addend =
+ Builder.CreateFSub(
+ llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend,
+ "neg");
+ }
+
+ Value *FMulAdd =
+ Builder.CreateCall3(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()),
+ MulOp0, MulOp1, Addend);
+ MulOp->eraseFromParent();
+
+ return FMulAdd;
+}
+
+// Check whether it would be legal to emit an fmuladd intrinsic call to
+// represent op and if so, build the fmuladd.
+//
+// Checks that (a) the operation is fusable, and (b) -ffp-contract=on.
+// Does NOT check the type of the operation - it's assumed that this function
+// will be called from contexts where it's known that the type is contractable.
+static Value* tryEmitFMulAdd(const BinOpInfo &op,
+ const CodeGenFunction &CGF, CGBuilderTy &Builder,
+ bool isSub=false) {
+
+ assert((op.Opcode == BO_Add || op.Opcode == BO_AddAssign ||
+ op.Opcode == BO_Sub || op.Opcode == BO_SubAssign) &&
+ "Only fadd/fsub can be the root of an fmuladd.");
+
+ // Check whether this op is marked as fusable.
+ if (!op.FPContractable)
+ return 0;
+
+ // 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)
+ return 0;
+
+ // We have a potentially fusable op. Look for a mul on one of the operands.
+ if (llvm::BinaryOperator* LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) {
+ if (LHSBinOp->getOpcode() == llvm::Instruction::FMul) {
+ assert(LHSBinOp->getNumUses() == 0 &&
+ "Operations with multiple uses shouldn't be contracted.");
+ return buildFMulAdd(LHSBinOp, op.RHS, CGF, Builder, false, isSub);
+ }
+ } else if (llvm::BinaryOperator* RHSBinOp =
+ dyn_cast<llvm::BinaryOperator>(op.RHS)) {
+ if (RHSBinOp->getOpcode() == llvm::Instruction::FMul) {
+ assert(RHSBinOp->getNumUses() == 0 &&
+ "Operations with multiple uses shouldn't be contracted.");
+ return buildFMulAdd(RHSBinOp, op.LHS, CGF, Builder, isSub, false);
+ }
+ }
+
+ return 0;
+}
+
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (op.LHS->getType()->isPointerTy() ||
op.RHS->getType()->isPointerTy())
return emitPointerArithmetic(CGF, op, /*subtraction*/ false);
if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
+ // Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
- if (op.LHS->getType()->isFPOrFPVectorTy())
+ if (op.LHS->getType()->isFPOrFPVectorTy()) {
+ // Try to form an fmuladd.
+ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
+ return FMulAdd;
+
return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+ }
return Builder.CreateAdd(op.LHS, op.RHS, "add");
}
@@ -2027,18 +2272,24 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// The LHS is always a pointer if either side is.
if (!op.LHS->getType()->isPointerTy()) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
+ // Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
- if (op.LHS->getType()->isFPOrFPVectorTy())
+ if (op.LHS->getType()->isFPOrFPVectorTy()) {
+ // Try to form an fmuladd.
+ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
+ return FMulAdd;
return Builder.CreateFSub(op.LHS, op.RHS, "sub");
+ }
return Builder.CreateSub(op.LHS, op.RHS, "sub");
}
@@ -2108,14 +2359,34 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.CatchUndefined
- && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ if (CGF.getLangOpts().SanitizeShift &&
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS,
- llvm::ConstantInt::get(RHS->getType(), Width)),
- Cont, CGF.getTrapBB());
- CGF.EmitBlock(Cont);
+ 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);
+
+ if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ // Check whether we are shifting any non-zero bits off the top of the
+ // integer.
+ llvm::Value *BitsShiftedOff =
+ Builder.CreateLShr(Ops.LHS,
+ Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
+ /*NUW*/true, /*NSW*/true),
+ "shl.check");
+ if (CGF.getLangOpts().CPlusPlus) {
+ // In C99, we are not permitted to shift a 1 bit into the sign bit.
+ // Under C++11's rules, shifting a 1 bit into the sign bit is
+ // OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't
+ // define signed left shifts, so we use the C99 and C++11 rules there).
+ llvm::Value *One = llvm::ConstantInt::get(BitsShiftedOff->getType(), 1);
+ BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
+ }
+ llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
+ EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops);
+ }
}
return Builder.CreateShl(Ops.LHS, RHS, "shl");
@@ -2128,14 +2399,11 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.CatchUndefined
- && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ if (CGF.getLangOpts().SanitizeShift &&
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS,
- llvm::ConstantInt::get(RHS->getType(), Width)),
- Cont, CGF.getTrapBB());
- CGF.EmitBlock(Cont);
+ llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width);
+ EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops);
}
if (Ops.Ty->hasUnsignedIntegerRepresentation())
@@ -2326,7 +2594,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
case Qualifiers::OCL_Weak:
RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS());
+ LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
break;
@@ -2336,7 +2604,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// __block variables need to have the rhs evaluated first, plus
// this should improve codegen just a little.
RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS());
+ LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
// Store the value into the LHS. Bit-fields are handled specially
// because the result is altered by the store, i.e., [C99 6.5.16p1]
@@ -2353,7 +2621,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return 0;
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return RHS;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -2567,7 +2835,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// OpenCL: If the condition is a vector, we can treat this condition like
// the select function.
- if (CGF.getContext().getLangOpts().OpenCL
+ if (CGF.getLangOpts().OpenCL
&& condExpr->getType()->isVectorType()) {
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 4ac172d1cbb5..c90e4eca8476 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -21,7 +21,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/InlineAsm.h"
using namespace clang;
using namespace CodeGen;
@@ -440,8 +440,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
SourceLocation StartLoc) {
FunctionArgList args;
// Check if we should generate debug info for this method.
- if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getModuleDebugInfo();
+ if (!OMD->hasAttr<NoDebugAttr>())
+ maybeInitializeDebugInfo();
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
@@ -613,7 +613,16 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
// which translates to objc_storeStrong. This isn't required, but
// it's slightly nicer.
} else if (CGM.getLangOpts().ObjCAutoRefCount && !IsAtomic) {
- Kind = Expression;
+ // Using standard expression emission for the setter is only
+ // acceptable if the ivar is __strong, which won't be true if
+ // the property is annotated with __attribute__((NSObject)).
+ // TODO: falling all the way back to objc_setProperty here is
+ // just laziness, though; we could still use objc_storeStrong
+ // if we hacked it right.
+ if (ivarType.getObjCLifetime() == Qualifiers::OCL_Strong)
+ Kind = Expression;
+ else
+ Kind = SetPropertyAndExpressionGet;
return;
// Otherwise, we need to at least use setProperty. However, if
@@ -801,6 +810,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
+ // We don't need to do anything for a zero-size struct.
+ if (strategy.getIvarSize().isZero())
+ return;
+
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
// Currently, all atomic accesses have to be through integer
@@ -1032,12 +1045,7 @@ static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
static bool UseOptimizedSetter(CodeGenModule &CGM) {
if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
return false;
- const TargetInfo &Target = CGM.getContext().getTargetInfo();
-
- if (Target.getPlatformName() != "macosx")
- return false;
-
- return Target.getPlatformMinVersion() >= VersionTuple(10, 8);
+ return CGM.getLangOpts().ObjCRuntime.hasOptimizedSetter();
}
void
@@ -1064,6 +1072,10 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
+ // We don't need to do anything for a zero-size struct.
+ if (strategy.getIvarSize().isZero())
+ return;
+
llvm::Value *argAddr = LocalDeclMap[*setterMethod->param_begin()];
LValue ivarLValue =
@@ -1097,7 +1109,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
llvm::Value *setOptimizedPropertyFn = 0;
llvm::Value *setPropertyFn = 0;
if (UseOptimizedSetter(CGM)) {
- // 10.8 code and GC is off
+ // 10.8 and iOS 6.0 code and GC is off
setOptimizedPropertyFn =
CGM.getObjCRuntime()
.GetOptimizedPropertySetFunction(strategy.isAtomic(),
@@ -1209,7 +1221,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
ivarRef.getType(), VK_RValue, OK_Ordinary,
- SourceLocation());
+ SourceLocation(), false);
EmitStmt(&assign);
}
@@ -1697,11 +1709,11 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
// 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.hasARC())
+ 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::Attribute::NonLazyBind);
+ f->addFnAttr(llvm::Attributes::NonLazyBind);
}
return fn;
@@ -1945,6 +1957,28 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
}
}
+/// Destroy a __strong variable.
+///
+/// At -O0, emit a call to store 'null' into the address;
+/// instrumenting tools prefer this because the address is exposed,
+/// but it's relatively cumbersome to optimize.
+///
+/// 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) {
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType());
+ llvm::Value *null = llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(addrTy->getElementType()));
+ EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
+ return;
+ }
+
+ llvm::Value *value = Builder.CreateLoad(addr);
+ EmitARCRelease(value, precise);
+}
+
/// Store into a strong object. Always calls this:
/// call void \@objc_storeStrong(i8** %addr, i8* %value)
llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
@@ -2218,15 +2252,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
- CGF.EmitARCRelease(ptr, /*precise*/ true);
+ CGF.EmitARCDestroyStrong(addr, /*precise*/ true);
}
void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
- CGF.EmitARCRelease(ptr, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(addr, /*precise*/ false);
}
void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
@@ -2730,7 +2762,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
// Keep track of the current cleanup stack depth.
RunCleanupsScope Scope(*this);
- if (CGM.getLangOpts().ObjCRuntime.hasARC()) {
+ if (CGM.getLangOpts().ObjCRuntime.hasNativeARC()) {
llvm::Value *token = EmitObjCAutoreleasePoolPush();
EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
} else {
@@ -2826,9 +2858,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
"__assign_helper_atomic_property_",
&CGM.getModule());
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
-
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -2845,8 +2876,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
Expr *Args[2] = { &DST, &SRC };
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(),
- Args, 2, DestTy->getPointeeType(),
- VK_LValue, SourceLocation());
+ Args, DestTy->getPointeeType(),
+ VK_LValue, SourceLocation(), false);
EmitStmt(&TheCall);
@@ -2912,9 +2943,8 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__copy_helper_atomic_property_", &CGM.getModule());
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
-
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -2940,7 +2970,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
CXXConstructExpr::Create(C, Ty, SourceLocation(),
CXXConstExpr->getConstructor(),
CXXConstExpr->isElidable(),
- &ConstructorArgs[0], ConstructorArgs.size(),
+ ConstructorArgs,
CXXConstExpr->hadMultipleCandidates(),
CXXConstExpr->isListInitialization(),
CXXConstExpr->requiresZeroInitialization(),
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 6d129d02a561..68d234dde6ea 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -33,7 +33,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdarg>
@@ -224,6 +224,25 @@ protected:
llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size());
return MakeGlobal(ArrayTy, V, Name, linkage);
}
+ /// Returns a property name and encoding string.
+ llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
+ const Decl *Container) {
+ ObjCRuntime R = CGM.getLangOpts().ObjCRuntime;
+ if ((R.getKind() == ObjCRuntime::GNUstep) &&
+ (R.getVersion() >= VersionTuple(1, 6))) {
+ std::string NameAndAttributes;
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr);
+ NameAndAttributes += '\0';
+ NameAndAttributes += TypeStr.length() + 3;
+ NameAndAttributes += TypeStr;
+ NameAndAttributes += '\0';
+ NameAndAttributes += PD->getNameAsString();
+ return llvm::ConstantExpr::getGetElementPtr(
+ CGM.GetAddrOfConstantString(NameAndAttributes), Zeros);
+ }
+ return MakeConstantString(PD->getNameAsString());
+ }
/// Ensures that the value has the required type, by inserting a bitcast if
/// required. This function lets us avoid inserting bitcasts that are
/// redundant.
@@ -514,7 +533,10 @@ public:
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
-
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ return NULLPtr;
+ }
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
return 0;
}
@@ -578,6 +600,8 @@ class CGObjCGNUstep : public CGObjCGNU {
/// Type of an slot structure pointer. This is returned by the various
/// lookup functions.
llvm::Type *SlotTy;
+ public:
+ virtual llvm::Constant *GetEHType(QualType T);
protected:
virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
llvm::Value *&Receiver,
@@ -653,11 +677,40 @@ class CGObjCGNUstep : public CGObjCGNU {
}
};
-/// The ObjFW runtime, which closely follows the GCC runtime's
-/// compiler ABI. Support here is due to Jonathan Schleifer, the
-/// ObjFW maintainer.
-class CGObjCObjFW : public CGObjCGCC {
- /// Emit class references unconditionally as direct symbol references.
+/// Support for the ObjFW runtime. Support here is due to
+/// Jonathan Schleifer <js@webkeks.org>, the ObjFW maintainer.
+class CGObjCObjFW: public CGObjCGNU {
+protected:
+ /// The GCC ABI message lookup function. Returns an IMP pointing to the
+ /// method implementation for this message.
+ LazyRuntimeFunction MsgLookupFn;
+ /// The GCC ABI superclass message lookup function. Takes a pointer to a
+ /// structure describing the receiver and the class, and a selector as
+ /// arguments. Returns the IMP for the corresponding method.
+ LazyRuntimeFunction MsgLookupSuperFn;
+
+ virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
+ llvm::Value *&Receiver,
+ llvm::Value *cmd,
+ llvm::MDNode *node) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *args[] = {
+ EnforceType(Builder, Receiver, IdTy),
+ EnforceType(Builder, cmd, SelectorTy) };
+ llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ imp->setMetadata(msgSendMDKind, node);
+ return imp.getInstruction();
+ }
+
+ virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
+ llvm::Value *ObjCSuper,
+ llvm::Value *cmd) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
+ PtrToObjCSuperTy), cmd};
+ return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ }
+
virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
const std::string &Name, bool isWeak) {
if (isWeak)
@@ -678,7 +731,13 @@ class CGObjCObjFW : public CGObjCGCC {
}
public:
- CGObjCObjFW(CodeGenModule &Mod): CGObjCGCC(Mod) {}
+ CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
+ // IMP objc_msg_lookup(id, SEL);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL);
+ // IMP objc_msg_lookup_super(struct objc_super*, SEL);
+ MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
+ PtrToObjCSuperTy, SelectorTy, NULL);
+ }
};
} // end anonymous namespace
@@ -909,29 +968,30 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
- if (!CGM.getLangOpts().CPlusPlus) {
- if (T->isObjCIdType()
- || T->isObjCQualifiedIdType()) {
- // With the old ABI, there was only one kind of catchall, which broke
- // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as
- // a pointer indicating object catchalls, and NULL to indicate real
- // catchalls
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- return MakeConstantString("@id");
- } else {
- return 0;
- }
- }
-
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *OPT =
- T->getAs<ObjCObjectPointerType>();
- assert(OPT && "Invalid @catch type.");
- const ObjCInterfaceDecl *IDecl =
- OPT->getObjectType()->getInterface();
- assert(IDecl && "Invalid @catch type.");
- return MakeConstantString(IDecl->getIdentifier()->getName());
+ if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
+ // With the old ABI, there was only one kind of catchall, which broke
+ // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as
+ // a pointer indicating object catchalls, and NULL to indicate real
+ // catchalls
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
+ return MakeConstantString("@id");
+ } else {
+ return 0;
+ }
}
+
+ // All other types should be Objective-C interface pointer types.
+ const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>();
+ assert(OPT && "Invalid @catch type.");
+ const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface();
+ assert(IDecl && "Invalid @catch type.");
+ return MakeConstantString(IDecl->getIdentifier()->getName());
+}
+
+llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
+ if (!CGM.getLangOpts().CPlusPlus)
+ return CGObjCGNU::GetEHType(T);
+
// For Objective-C++, we want to provide the ability to catch both C++ and
// Objective-C objects in the same function.
@@ -1436,7 +1496,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(Zero);
Elements.push_back(llvm::ConstantInt::get(LongTy, info));
if (isMeta) {
- llvm::TargetData td(&TheModule);
+ llvm::DataLayout td(&TheModule);
Elements.push_back(
llvm::ConstantInt::get(LongTy,
td.getTypeSizeInBits(ClassTy) /
@@ -1595,13 +1655,13 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(*iter, TypeStr);
if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
- InstanceMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
- InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
- } else {
OptionalInstanceMethodNames.push_back(
MakeConstantString((*iter)->getSelector().getAsString()));
OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr));
+ } else {
+ InstanceMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
}
// Collect information about class methods:
@@ -1615,13 +1675,13 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
- ClassMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
- ClassMethodTypes.push_back(MakeConstantString(TypeStr));
- } else {
OptionalClassMethodNames.push_back(
MakeConstantString((*iter)->getSelector().getAsString()));
OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr));
+ } else {
+ ClassMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
}
@@ -1656,7 +1716,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> Fields;
ObjCPropertyDecl *property = *iter;
- Fields.push_back(MakeConstantString(property->getNameAsString()));
+
+ Fields.push_back(MakePropertyEncodingString(property, PD));
+
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
property->getPropertyAttributes()));
Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
@@ -1909,7 +1971,7 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize);
- Fields.push_back(MakeConstantString(property->getNameAsString()));
+ Fields.push_back(MakePropertyEncodingString(property, OID));
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
property->getPropertyAttributes()));
Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized));
@@ -2011,7 +2073,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
// For non-fragile ivars, set the instance size to 0 - {the size of just this
// class}. The runtime will then set this to the correct value on load.
- if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) {
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
instanceSize = 0 - (instanceSize - superInstanceSize);
}
@@ -2026,7 +2088,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Get the offset
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
uint64_t Offset = BaseOffset;
- if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) {
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
Offset = BaseOffset - superInstanceSize;
}
llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset);
@@ -2334,7 +2396,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Runtime version, used for ABI compatibility checking.
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
// sizeof(ModuleTy)
- llvm::TargetData td(&TheModule);
+ llvm::DataLayout td(&TheModule);
Elements.push_back(
llvm::ConstantInt::get(LongTy,
td.getTypeSizeInBits(ModuleTy) /
@@ -2488,7 +2550,7 @@ void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF,
// Unlike the Apple non-fragile runtimes, which also uses
// unwind-based zero cost exceptions, the GNU Objective C runtime's
// EH support isn't a veneer over C++ EH. Instead, exception
- // objects are created by __objc_exception_throw and destroyed by
+ // objects are created by objc_exception_throw and destroyed by
// the personality function; this avoids the need for bracketing
// catch handlers with calls to __blah_begin_catch/__blah_end_catch
// (or even _Unwind_DeleteException), but probably doesn't
@@ -2513,7 +2575,9 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
- CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ llvm::CallSite Throw =
+ CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ Throw.setDoesNotReturn();
CGF.Builder.CreateUnreachable();
CGF.Builder.ClearInsertionPoint();
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index ef802a3ed0ca..2203f0182800 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -36,7 +36,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdio>
using namespace clang;
@@ -66,7 +66,8 @@ private:
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend",
- llvm::Attribute::NonLazyBind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -433,19 +434,19 @@ public:
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
- // void objc_sync_enter (id)
+ // int objc_sync_enter (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
+ llvm::FunctionType::get(CGM.IntTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
- // void objc_sync_exit (id)
+ // int objc_sync_exit (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
+ llvm::FunctionType::get(CGM.IntTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
}
@@ -583,7 +584,8 @@ public:
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
params, false),
"_setjmp",
- llvm::Attribute::ReturnsTwice);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NonLazyBind));
}
public:
@@ -753,6 +755,74 @@ public:
: skip(_skip), scan(_scan) {}
};
+ /// opcode for captured block variables layout 'instructions'.
+ /// In the following descriptions, 'I' is the value of the immediate field.
+ /// (field following the opcode).
+ ///
+ enum BLOCK_LAYOUT_OPCODE {
+ /// An operator which affects how the following layout should be
+ /// interpreted.
+ /// I == 0: Halt interpretation and treat everything else as
+ /// a non-pointer. Note that this instruction is equal
+ /// to '\0'.
+ /// I != 0: Currently unused.
+ BLOCK_LAYOUT_OPERATOR = 0,
+
+ /// The next I+1 bytes do not contain a value of object pointer type.
+ /// Note that this can leave the stream unaligned, meaning that
+ /// subsequent word-size instructions do not begin at a multiple of
+ /// the pointer size.
+ BLOCK_LAYOUT_NON_OBJECT_BYTES = 1,
+
+ /// The next I+1 words do not contain a value of object pointer type.
+ /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for
+ /// when the required skip quantity is a multiple of the pointer size.
+ BLOCK_LAYOUT_NON_OBJECT_WORDS = 2,
+
+ /// The next I+1 words are __strong pointers to Objective-C
+ /// objects or blocks.
+ BLOCK_LAYOUT_STRONG = 3,
+
+ /// The next I+1 words are pointers to __block variables.
+ BLOCK_LAYOUT_BYREF = 4,
+
+ /// The next I+1 words are __weak pointers to Objective-C
+ /// objects or blocks.
+ BLOCK_LAYOUT_WEAK = 5,
+
+ /// The next I+1 words are __unsafe_unretained pointers to
+ /// Objective-C objects or blocks.
+ BLOCK_LAYOUT_UNRETAINED = 6
+
+ /// The next I+1 words are block or object pointers with some
+ /// as-yet-unspecified ownership semantics. If we add more
+ /// flavors of ownership semantics, values will be taken from
+ /// this range.
+ ///
+ /// This is included so that older tools can at least continue
+ /// processing the layout past such things.
+ //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10,
+
+ /// All other opcodes are reserved. Halt interpretation and
+ /// treat everything else as opaque.
+ };
+
+ class RUN_SKIP {
+ public:
+ enum BLOCK_LAYOUT_OPCODE opcode;
+ CharUnits block_var_bytepos;
+ CharUnits block_var_size;
+ RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR,
+ CharUnits BytePos = CharUnits::Zero(),
+ CharUnits Size = CharUnits::Zero())
+ : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {}
+
+ // Allow sorting based on byte pos.
+ bool operator<(const RUN_SKIP &b) const {
+ return block_var_bytepos < b.block_var_bytepos;
+ }
+ };
+
protected:
llvm::LLVMContext &VMContext;
// FIXME! May not be needing this after all.
@@ -761,6 +831,9 @@ protected:
// gc ivar layout bitmap calculation helper caches.
SmallVector<GC_IVAR, 16> SkipIvars;
SmallVector<GC_IVAR, 16> IvarsInfo;
+
+ // arc/mrr layout of captured block literal variables.
+ SmallVector<RUN_SKIP, 16> RunSkipBlockVars;
/// LazySymbols - Symbols to generate a lazy reference for. See
/// DefinedSymbols and FinishModule().
@@ -869,6 +942,24 @@ protected:
ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
+
+ Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT);
+
+ void UpdateRunSkipBlockVars(bool IsByref,
+ Qualifiers::ObjCLifetime LifeTime,
+ CharUnits FieldOffset,
+ CharUnits FieldSize);
+
+ void BuildRCBlockVarRecordLayout(const RecordType *RT,
+ CharUnits BytePos, bool &HasUnion);
+
+ void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
+ const RecordDecl *RD,
+ ArrayRef<const FieldDecl*> RecFields,
+ CharUnits BytePos, bool &HasUnion);
+
+ uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
+
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
@@ -959,6 +1050,8 @@ public:
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo);
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo);
};
@@ -1787,8 +1880,8 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
+
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
!CGM.getLangOpts().ObjCAutoRefCount)
return nullPtr;
@@ -1807,7 +1900,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
// Calculate the basic layout of the block structure.
const llvm::StructLayout *layout =
- CGM.getTargetData().getStructLayout(blockInfo.StructureType);
+ CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
// Ignore the optional 'this' capture: C++ objects are not assumed
// to be GC'ed.
@@ -1860,7 +1953,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n block variable layout for block: ");
- const unsigned char *s = (unsigned char*)BitMap.c_str();
+ const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
@@ -1872,6 +1965,476 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
return C;
}
+/// 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) {
+ if (CGM.getLangOpts().ObjCAutoRefCount)
+ return FQT.getObjCLifetime();
+
+ // MRR.
+ if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
+ return Qualifiers::OCL_ExplicitNone;
+
+ return Qualifiers::OCL_None;
+}
+
+void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
+ Qualifiers::ObjCLifetime LifeTime,
+ CharUnits FieldOffset,
+ CharUnits FieldSize) {
+ // __block variables are passed by their descriptor address.
+ if (IsByref)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_Strong)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_Weak)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_ExplicitNone)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset,
+ FieldSize));
+ else
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES,
+ FieldOffset,
+ FieldSize));
+}
+
+void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
+ const RecordDecl *RD,
+ ArrayRef<const FieldDecl*> RecFields,
+ CharUnits BytePos, bool &HasUnion) {
+ bool IsUnion = (RD && RD->isUnion());
+ CharUnits MaxUnionSize = CharUnits::Zero();
+ const FieldDecl *MaxField = 0;
+ const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
+ CharUnits MaxFieldOffset = CharUnits::Zero();
+ CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
+
+ if (RecFields.empty())
+ return;
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ const FieldDecl *Field = RecFields[i];
+ // Note that 'i' here is actually the field index inside RD of Field,
+ // although this dependency is hidden.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ CharUnits FieldOffset =
+ CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i));
+
+ // Skip over unnamed or bitfields
+ if (!Field->getIdentifier() || Field->isBitField()) {
+ LastFieldBitfieldOrUnnamed = Field;
+ LastBitfieldOrUnnamedOffset = FieldOffset;
+ continue;
+ }
+
+ LastFieldBitfieldOrUnnamed = 0;
+ QualType FQT = Field->getType();
+ if (FQT->isRecordType() || FQT->isUnionType()) {
+ if (FQT->isUnionType())
+ HasUnion = true;
+
+ BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(),
+ BytePos + FieldOffset, HasUnion);
+ continue;
+ }
+
+ if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ uint64_t ElCount = CArray->getSize().getZExtValue();
+ assert(CArray && "only array with known element size is supported");
+ FQT = CArray->getElementType();
+ while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ ElCount *= CArray->getSize().getZExtValue();
+ FQT = CArray->getElementType();
+ }
+
+ assert(!FQT->isUnionType() &&
+ "layout for array of unions not supported");
+ if (FQT->isRecordType() && ElCount) {
+ int OldIndex = RunSkipBlockVars.size() - 1;
+ const RecordType *RT = FQT->getAs<RecordType>();
+ BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset,
+ HasUnion);
+
+ // Replicate layout information for each array element. Note that
+ // one element is already done.
+ uint64_t ElIx = 1;
+ for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) {
+ CharUnits Size = CGM.getContext().getTypeSizeInChars(RT);
+ for (int i = OldIndex+1; i <= FirstIndex; ++i)
+ RunSkipBlockVars.push_back(
+ RUN_SKIP(RunSkipBlockVars[i].opcode,
+ RunSkipBlockVars[i].block_var_bytepos + Size*ElIx,
+ RunSkipBlockVars[i].block_var_size));
+ }
+ continue;
+ }
+ }
+ CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType());
+ if (IsUnion) {
+ CharUnits UnionIvarSize = FieldSize;
+ if (UnionIvarSize > MaxUnionSize) {
+ MaxUnionSize = UnionIvarSize;
+ MaxField = Field;
+ MaxFieldOffset = FieldOffset;
+ }
+ } else {
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(FQT),
+ BytePos + FieldOffset,
+ FieldSize);
+ }
+ }
+
+ if (LastFieldBitfieldOrUnnamed) {
+ if (LastFieldBitfieldOrUnnamed->isBitField()) {
+ // Last field was a bitfield. Must update the info.
+ uint64_t BitFieldSize
+ = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
+ unsigned UnsSize = (BitFieldSize / ByteSizeInBits) +
+ ((BitFieldSize % ByteSizeInBits) != 0);
+ CharUnits Size = CharUnits::fromQuantity(UnsSize);
+ Size += LastBitfieldOrUnnamedOffset;
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ BytePos + LastBitfieldOrUnnamedOffset,
+ Size);
+ } else {
+ assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
+ // Last field was unnamed. Must update skip info.
+ CharUnits FieldSize
+ = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ BytePos + LastBitfieldOrUnnamedOffset,
+ FieldSize);
+ }
+ }
+
+ if (MaxField)
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(MaxField->getType()),
+ BytePos + MaxFieldOffset,
+ MaxUnionSize);
+}
+
+void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
+ CharUnits BytePos,
+ bool &HasUnion) {
+ const RecordDecl *RD = RT->getDecl();
+ SmallVector<const FieldDecl*, 16> Fields;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i)
+ Fields.push_back(*i);
+ llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
+ const llvm::StructLayout *RecLayout =
+ CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
+
+ BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion);
+}
+
+/// InlineLayoutInstruction - This routine produce an inline instruction for the
+/// block variable layout if it can. If not, it returns 0. Rules are as follow:
+/// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
+/// an inline layout of value 0x0000000000000xyz is interpreted as follows:
+/// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
+/// y captured object of BLOCK_LAYOUT_BYREF. Followed by
+/// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
+/// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
+/// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
+uint64_t CGObjCCommonMac::InlineLayoutInstruction(
+ SmallVectorImpl<unsigned char> &Layout) {
+ uint64_t Result = 0;
+ if (Layout.size() <= 3) {
+ unsigned size = Layout.size();
+ unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
+ unsigned char inst;
+ enum BLOCK_LAYOUT_OPCODE opcode ;
+ switch (size) {
+ case 3:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[2];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ case 2:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG) {
+ strong_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else if (opcode == BLOCK_LAYOUT_BYREF) {
+ byref_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ break;
+
+ case 1:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ // Cannot inline when any of the word counts is 15. Because this is one less
+ // than the actual work count (so 15 means 16 actual word counts),
+ // and we can only display 0 thru 15 word counts.
+ if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
+ return 0;
+
+ unsigned count =
+ (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
+
+ if (size == count) {
+ if (strong_word_count)
+ Result = strong_word_count;
+ Result <<= 4;
+ if (byref_word_count)
+ Result += byref_word_count;
+ Result <<= 4;
+ if (weak_word_count)
+ Result += weak_word_count;
+ }
+ }
+ return Result;
+}
+
+llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+
+ llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+
+ 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.
+
+ // 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;
+ CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
+ CharUnits end_byte_pos = start_byte_pos;
+ unsigned j = i+1;
+ while (j < size) {
+ if (opcode == RunSkipBlockVars[j].opcode) {
+ end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
+ i++;
+ }
+ else
+ break;
+ }
+ CharUnits size_in_bytes =
+ 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;
+ size_in_bytes += gap;
+ }
+ CharUnits residue_in_bytes = CharUnits::Zero();
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
+ residue_in_bytes = size_in_bytes % WordSizeInBytes;
+ 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
+ // value. So, 0xf means 16 words follow!
+ unsigned char inst = (opcode << 4) | 0xf;
+ Layout.push_back(inst);
+ size_in_words -= 16;
+ }
+ if (size_in_words > 0) {
+ // Note that value in imm. is one less that the actual
+ // value. So, we subtract 1 away!
+ unsigned char inst = (opcode << 4) | (size_in_words-1);
+ Layout.push_back(inst);
+ }
+ if (residue_in_bytes > CharUnits::Zero()) {
+ unsigned char inst =
+ (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
+ Layout.push_back(inst);
+ }
+ }
+
+ int e = Layout.size()-1;
+ while (e >= 0) {
+ unsigned char inst = Layout[e--];
+ enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
+ Layout.pop_back();
+ else
+ break;
+ }
+
+ uint64_t Result = InlineLayoutInstruction(Layout);
+ if (Result != 0) {
+ // Block variable layout instruction has been inlined.
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ printf("\n Inline instruction for block variable layout: ");
+ printf("0x0%llx\n", (unsigned long long)Result);
+ }
+ if (WordSizeInBytes == 8) {
+ const llvm::APInt Instruction(64, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int64Ty, Instruction);
+ }
+ else {
+ const llvm::APInt Instruction(32, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int32Ty, Instruction);
+ }
+ }
+
+ unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
+ Layout.push_back(inst);
+ std::string BitMap;
+ for (unsigned i = 0, e = Layout.size(); i != e; i++)
+ BitMap += Layout[i];
+
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ 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);
+ unsigned delta = 1;
+ switch (opcode) {
+ case BLOCK_LAYOUT_OPERATOR:
+ printf("BL_OPERATOR:");
+ delta = 0;
+ break;
+ case BLOCK_LAYOUT_NON_OBJECT_BYTES:
+ printf("BL_NON_OBJECT_BYTES:");
+ break;
+ case BLOCK_LAYOUT_NON_OBJECT_WORDS:
+ printf("BL_NON_OBJECT_WORD:");
+ break;
+ case BLOCK_LAYOUT_STRONG:
+ printf("BL_STRONG:");
+ break;
+ case BLOCK_LAYOUT_BYREF:
+ printf("BL_BYREF:");
+ break;
+ case BLOCK_LAYOUT_WEAK:
+ printf("BL_WEAK:");
+ break;
+ 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);
+ if (i < e-1)
+ printf(", ");
+ else
+ printf("\n");
+ }
+ }
+
+ llvm::GlobalVariable * Entry =
+ 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,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
@@ -2040,7 +2603,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
ArrayRef<llvm::Constant*> OptClassMethods,
ArrayRef<llvm::Constant*> MethodTypesExt) {
uint64_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
@@ -2180,7 +2743,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
unsigned PropertySize =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size());
@@ -2269,7 +2832,7 @@ CGObjCMac::EmitMethodDescList(Twine Name, const char *Section,
};
*/
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy);
// FIXME: This is poor design, the OCD should have a pointer to the category
// decl. Additionally, note that Category can be null for the @implementation
@@ -2338,15 +2901,37 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
MethodDefinitions.clear();
}
-// FIXME: Get from somewhere?
-enum ClassFlags {
- eClassFlags_Factory = 0x00001,
- eClassFlags_Meta = 0x00002,
- // <rdr://5142207>
- eClassFlags_HasCXXStructors = 0x02000,
- eClassFlags_Hidden = 0x20000,
- eClassFlags_ABI2_Hidden = 0x00010,
- eClassFlags_ABI2_HasCXXStructors = 0x00004 // <rdr://4923634>
+enum FragileClassFlags {
+ FragileABI_Class_Factory = 0x00001,
+ FragileABI_Class_Meta = 0x00002,
+ FragileABI_Class_HasCXXStructors = 0x02000,
+ FragileABI_Class_Hidden = 0x20000
+};
+
+enum NonFragileClassFlags {
+ /// Is a meta-class.
+ NonFragileABI_Class_Meta = 0x00001,
+
+ /// Is a root class.
+ NonFragileABI_Class_Root = 0x00002,
+
+ /// Has a C++ constructor and destructor.
+ NonFragileABI_Class_HasCXXStructors = 0x00004,
+
+ /// Has hidden visibility.
+ NonFragileABI_Class_Hidden = 0x00010,
+
+ /// Has the exception attribute.
+ NonFragileABI_Class_Exception = 0x00020,
+
+ /// (Obsolete) ARC-specific: this class has a .release_ivars method
+ NonFragileABI_Class_HasIvarReleaser = 0x00040,
+
+ /// Class implementation was compiled under ARC.
+ NonFragileABI_Class_CompiledByARC = 0x00080,
+
+ /// Class has non-trivial destructors, but zero-initialization is okay.
+ NonFragileABI_Class_HasCXXDestructorOnly = 0x00100
};
/*
@@ -2379,15 +2964,15 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(),
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
- unsigned Flags = eClassFlags_Factory;
- if (ID->hasCXXStructors())
- Flags |= eClassFlags_HasCXXStructors;
+ unsigned Flags = FragileABI_Class_Factory;
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors())
+ Flags |= FragileABI_Class_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
// FIXME: Set CXX-structors flag.
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= eClassFlags_Hidden;
+ Flags |= FragileABI_Class_Hidden;
llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
@@ -2470,11 +3055,11 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
ArrayRef<llvm::Constant*> Methods) {
- unsigned Flags = eClassFlags_Meta;
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
+ unsigned Flags = FragileABI_Class_Meta;
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy);
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= eClassFlags_Hidden;
+ Flags |= FragileABI_Class_Hidden;
llvm::Constant *Values[12];
// The isa for the metaclass is the root of the hierarchy.
@@ -2588,7 +3173,7 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
llvm::Constant *
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
uint64_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
@@ -3481,7 +4066,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3502,7 +4087,7 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3528,7 +4113,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3548,7 +4133,7 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3679,7 +4264,7 @@ void CGObjCCommonMac::EmitImageInfo() {
static const int ModuleVersion = 7;
void CGObjCMac::EmitModuleInfo() {
- uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy);
+ uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion),
@@ -3824,7 +4409,7 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
Fields.push_back(*i);
llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
- CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty));
+ CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos,
ForStrongLayout, HasUnion);
@@ -3951,7 +4536,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (IsUnion) {
// FIXME: Why the asymmetry? We divide by word size in bits on other
// side.
- uint64_t UnionIvarSize = FieldSize;
+ uint64_t UnionIvarSize = FieldSize / ByteSizeInBits;
if (UnionIvarSize > MaxSkippedUnionIvarSize) {
MaxSkippedUnionIvarSize = UnionIvarSize;
MaxSkippedField = Field;
@@ -4005,7 +4590,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
// Build the string of skip/scan nibbles
SmallVector<SKIP_SCAN, 32> SkipScanIvars;
unsigned int WordSize =
- CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
+ CGM.getTypes().getDataLayout().getTypeAllocSize(PtrTy);
if (IvarsInfo[0].ivar_bytepos == 0) {
WordsToSkip = 0;
WordsToScan = IvarsInfo[0].ivar_size;
@@ -4187,7 +4772,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getName().data());
- const unsigned char *s = (unsigned char*)BitMap.c_str();
+ const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
@@ -4835,7 +5420,7 @@ AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
llvm::GlobalValue::InternalLinkage,
Init,
SymbolName);
- GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.AddUsedGlobal(GV);
}
@@ -4941,19 +5526,6 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
return VTableDispatchMethods.count(Sel);
}
-// Metadata flags
-enum MetaDataDlags {
- CLS = 0x0,
- CLS_META = 0x1,
- CLS_ROOT = 0x2,
- OBJC2_CLS_HIDDEN = 0x10,
- CLS_EXCEPTION = 0x20,
-
- /// (Obsolete) ARC-specific: this class has a .release_ivars method
- CLS_HAS_IVAR_RELEASER = 0x40,
- /// class was compiled with -fobjc-arr
- CLS_COMPILED_BY_ARC = 0x80 // (1<<7)
-};
/// BuildClassRoTInitializer - generate meta-data for:
/// struct _class_ro_t {
/// uint32_t const flags;
@@ -4978,19 +5550,20 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
llvm::Constant *Values[10]; // 11 for 64bit targets!
if (CGM.getLangOpts().ObjCAutoRefCount)
- flags |= CLS_COMPILED_BY_ARC;
+ flags |= NonFragileABI_Class_CompiledByARC;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
// FIXME. For 64bit targets add 0 here.
- Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
+ Values[ 3] = (flags & NonFragileABI_Class_Meta)
+ ? GetIvarLayoutName(0, ObjCTypes)
: BuildIvarLayout(ID, true);
Values[ 4] = GetClassName(ID->getIdentifier());
// const struct _method_list_t * const baseMethods;
std::vector<llvm::Constant*> Methods;
std::string MethodListName("\01l_OBJC_$_");
- if (flags & CLS_META) {
+ if (flags & NonFragileABI_Class_Meta) {
MethodListName += "CLASS_METHODS_" + ID->getNameAsString();
for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
@@ -5030,28 +5603,27 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
OID->all_referenced_protocol_begin(),
OID->all_referenced_protocol_end());
- if (flags & CLS_META)
+ if (flags & NonFragileABI_Class_Meta) {
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
- else
- Values[ 7] = EmitIvarList(ID);
- Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
- : BuildIvarLayout(ID, false);
- if (flags & CLS_META)
+ Values[ 8] = GetIvarLayoutName(0, ObjCTypes);
Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
- else
+ } else {
+ Values[ 7] = EmitIvarList(ID);
+ Values[ 8] = BuildIvarLayout(ID, false);
Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
ID, ID->getClassInterface(), ObjCTypes);
+ }
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
Values);
llvm::GlobalVariable *CLASS_RO_GV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false,
llvm::GlobalValue::InternalLinkage,
Init,
- (flags & CLS_META) ?
+ (flags & NonFragileABI_Class_Meta) ?
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
return CLASS_RO_GV;
@@ -5088,7 +5660,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy));
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
return GV;
@@ -5138,23 +5710,31 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
"CGObjCNonFragileABIMac::GenerateClass - class is 0");
// FIXME: Is this correct (that meta class size is never computed)?
uint32_t InstanceStart =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
uint32_t InstanceSize = InstanceStart;
- uint32_t flags = CLS_META;
+ uint32_t flags = NonFragileABI_Class_Meta;
std::string ObjCMetaClassName(getMetaclassSymbolPrefix());
std::string ObjCClassName(getClassSymbolPrefix());
llvm::GlobalVariable *SuperClassGV, *IsAGV;
+ // Build the flags for the metaclass.
bool classIsHidden =
ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden)
- flags |= OBJC2_CLS_HIDDEN;
- if (ID->hasCXXStructors())
- flags |= eClassFlags_ABI2_HasCXXStructors;
+ flags |= NonFragileABI_Class_Hidden;
+
+ // FIXME: why is this flag set on the metaclass?
+ // ObjC metaclasses have no fields and don't really get constructed.
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
+ flags |= NonFragileABI_Class_HasCXXStructors;
+ if (!ID->hasNonZeroConstructors())
+ flags |= NonFragileABI_Class_HasCXXDestructorOnly;
+ }
+
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
- flags |= CLS_ROOT;
+ flags |= NonFragileABI_Class_Root;
SuperClassGV = GetClassGlobal(ObjCClassName + ClassName);
IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName);
} else {
@@ -5183,17 +5763,28 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedMetaClasses.push_back(MetaTClass);
// Metadata for the class
- flags = CLS;
+ flags = 0;
if (classIsHidden)
- flags |= OBJC2_CLS_HIDDEN;
- if (ID->hasCXXStructors())
- flags |= eClassFlags_ABI2_HasCXXStructors;
+ flags |= NonFragileABI_Class_Hidden;
+
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
+ flags |= NonFragileABI_Class_HasCXXStructors;
+
+ // Set a flag to enable a runtime optimization when a class has
+ // fields that require destruction but which don't require
+ // anything except zero-initialization during construction. This
+ // is most notably true of __strong and __weak types, but you can
+ // also imagine there being C++ types with non-trivial default
+ // constructors that merely set all fields to null.
+ if (!ID->hasNonZeroConstructors())
+ flags |= NonFragileABI_Class_HasCXXDestructorOnly;
+ }
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
- flags |= CLS_EXCEPTION;
+ flags |= NonFragileABI_Class_Exception;
if (!ID->getClassInterface()->getSuperClass()) {
- flags |= CLS_ROOT;
+ flags |= NonFragileABI_Class_Root;
SuperClassGV = 0;
} else {
// Has a root. Current class is not a root.
@@ -5220,7 +5811,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedNonLazyClasses.push_back(ClassMD);
// Force the definition of the EHType if necessary.
- if (flags & CLS_EXCEPTION)
+ if (flags & NonFragileABI_Class_Exception)
GetInterfaceEHType(ID->getClassInterface(), true);
// Make sure method definition entries are all clear for next implementation.
MethodDefinitions.clear();
@@ -5344,7 +5935,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Init,
ExtCatName);
GCATV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
@@ -5391,7 +5982,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::Constant *Values[3];
// sizeof(struct _objc_method)
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
// method_count
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
@@ -5403,7 +5994,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage, Init, Name);
- GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
@@ -5437,7 +6028,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.LongTy));
// FIXME: This matches gcc, but shouldn't the visibility be set on the use as
// well (i.e., in ObjCIvarOffsetVariable).
@@ -5490,7 +6081,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Ivar[2] = GetMethodVarType(IVD);
llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(IVD->getType());
- unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy);
unsigned Align = CGM.getContext().getPreferredTypeAlign(
IVD->getType().getTypePtr()) >> 3;
Align = llvm::Log2_32(Align);
@@ -5508,7 +6099,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
llvm::Constant *Values[3];
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
@@ -5522,7 +6113,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Init,
Prefix + OID->getName());
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GV);
@@ -5644,7 +6235,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(),
0, PD, ObjCTypes);
uint32_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
@@ -5663,7 +6254,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Init,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
Protocols[PD->getIdentifier()] = Entry;
@@ -5678,7 +6269,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
"\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
PTGV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
@@ -5732,7 +6323,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
Init, Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ CGM.getDataLayout().getABITypeAlignment(Init->getType()));
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
@@ -5970,7 +6561,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -6004,7 +6595,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -6030,7 +6621,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
MetaClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
@@ -6079,16 +6670,9 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
- if (IsClassMessage) {
- if (isCategoryImpl) {
- // Message sent to "super' in a class method defined in
- // a category implementation.
- Target = EmitClassRef(CGF.Builder, Class);
- Target = CGF.Builder.CreateStructGEP(Target, 0);
- Target = CGF.Builder.CreateLoad(Target);
- } else
+ if (IsClassMessage)
Target = EmitMetaClassRef(CGF.Builder, Class);
- } else
+ else
Target = EmitSuperClassRef(CGF.Builder, Class);
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
@@ -6143,7 +6727,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *ivarOffset) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6164,7 +6748,7 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6211,7 +6795,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6232,7 +6816,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6364,7 +6948,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
+ Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.EHTypeTy));
if (ForDefinition) {
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 9aa68376bcd0..6932dd709d16 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -78,6 +78,13 @@ uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
CGM.getContext().getCharWidth();
}
+unsigned CGObjCRuntime::ComputeBitfieldBitOffset(
+ CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar);
+}
+
LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID,
llvm::Value *BaseValue,
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 219a3e4df0d4..3e77875e6baf 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -261,6 +261,8 @@ public:
llvm::Value *Size) = 0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
struct MessageSendInfo {
@@ -275,6 +277,12 @@ public:
MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs);
+
+ // FIXME: This probably shouldn't be here, but the code to compute
+ // it is here.
+ unsigned ComputeBitfieldBitOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar);
};
/// Creates an instance of an Objective-C runtime class.
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index d1b370a1f728..7c83d39f8bce 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -105,7 +105,6 @@ public:
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
///
/// \param Force - true to force the creation of this RTTI value
- /// \param ForEH - true if this is for exception handling
llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
};
}
@@ -779,28 +778,24 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (Base->isVirtual()) {
- if (Bases.VirtualBases.count(BaseDecl)) {
+ // Mark the virtual base as seen.
+ if (!Bases.VirtualBases.insert(BaseDecl)) {
// If this virtual base has been seen before, then the class is diamond
// shaped.
Flags |= RTTIBuilder::VMI_DiamondShaped;
} else {
if (Bases.NonVirtualBases.count(BaseDecl))
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
-
- // Mark the virtual base as seen.
- Bases.VirtualBases.insert(BaseDecl);
}
} else {
- if (Bases.NonVirtualBases.count(BaseDecl)) {
+ // Mark the non-virtual base as seen.
+ if (!Bases.NonVirtualBases.insert(BaseDecl)) {
// If this non-virtual base has been seen before, then the class has non-
// diamond shaped repeated inheritance.
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
} else {
if (Bases.VirtualBases.count(BaseDecl))
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
-
- // Mark the non-virtual base as seen.
- Bases.NonVirtualBases.insert(BaseDecl);
}
}
@@ -891,7 +886,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
Offset = Layout.getBaseClassOffset(BaseDecl);
};
- OffsetFlags = Offset.getQuantity() << 8;
+ OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
// The low-order byte of __offset_flags contains flags, as given by the
// masks from the enumeration __offset_flags_masks.
@@ -982,7 +977,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
// Return a bogus pointer if RTTI is disabled, unless it's for EH.
// FIXME: should we even be calling this method if RTTI is disabled
// and it's not for EH?
- if (!ForEH && !getContext().getLangOpts().RTTI)
+ if (!ForEH && !getLangOpts().RTTI)
return llvm::Constant::getNullValue(Int8PtrTy);
if (ForEH && Ty->isObjCObjectPointerType() &&
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 94c822f49f17..3db5e0483bab 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -166,8 +166,8 @@ public:
class CGRecordLayout {
friend class CodeGenTypes;
- CGRecordLayout(const CGRecordLayout&); // DO NOT IMPLEMENT
- void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
+ CGRecordLayout(const CGRecordLayout &) LLVM_DELETED_FUNCTION;
+ void operator=(const CGRecordLayout &) LLVM_DELETED_FUNCTION;
private:
/// The LLVM type corresponding to this record layout; used when
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index d642ef8533c5..26ef3efe73e6 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -25,7 +25,7 @@
#include "llvm/Type.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -206,7 +206,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Alignment = Types.getContext().getASTRecordLayout(D).getAlignment();
Packed = D->hasAttr<PackedAttr>();
- IsMsStruct = D->hasAttr<MsStructAttr>();
+ IsMsStruct = D->isMsStruct(Types.getContext());
if (D->isUnion()) {
LayoutUnion(D);
@@ -239,7 +239,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
CharUnits TypeSizeInBytes =
- CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
+ CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty));
uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
@@ -259,7 +259,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
// in big-endian machines the first fields are in higher bit positions,
// so revert the offset. The byte offsets are reversed(back) later.
- if (Types.getTargetData().isBigEndian()) {
+ if (Types.getDataLayout().isBigEndian()) {
FieldOffset = ((ContainingTypeSizeInBits)-FieldOffset-FieldSize);
}
@@ -334,7 +334,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
// 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.getTargetData().isBigEndian()) {
+ if (Types.getDataLayout().isBigEndian()) {
AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(
ContainingTypeSizeInBits - AccessStart - AccessWidth);
} else {
@@ -553,9 +553,9 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
hasOnlyZeroSizedBitFields = false;
CharUnits fieldAlign = CharUnits::fromQuantity(
- Types.getTargetData().getABITypeAlignment(fieldType));
+ Types.getDataLayout().getABITypeAlignment(fieldType));
CharUnits fieldSize = CharUnits::fromQuantity(
- Types.getTargetData().getTypeAllocSize(fieldType));
+ Types.getDataLayout().getTypeAllocSize(fieldType));
if (fieldAlign < unionAlign)
continue;
@@ -884,7 +884,7 @@ void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) {
void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset,
llvm::Type *fieldType) {
CharUnits fieldSize =
- CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(fieldType));
+ CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(fieldType));
FieldTypes.push_back(fieldType);
@@ -957,7 +957,7 @@ CharUnits CGRecordLayoutBuilder::getTypeAlignment(llvm::Type *Ty) const {
if (Packed)
return CharUnits::One();
- return CharUnits::fromQuantity(Types.getTargetData().getABITypeAlignment(Ty));
+ return CharUnits::fromQuantity(Types.getDataLayout().getABITypeAlignment(Ty));
}
CharUnits CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const {
@@ -1036,7 +1036,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D);
uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize());
- assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) &&
+ assert(TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) &&
"Type size mismatch!");
if (BaseTy) {
@@ -1049,19 +1049,19 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
getContext().toBits(AlignedNonVirtualTypeSize);
assert(AlignedNonVirtualTypeSizeInBits ==
- getTargetData().getTypeAllocSizeInBits(BaseTy) &&
+ getDataLayout().getTypeAllocSizeInBits(BaseTy) &&
"Type size mismatch!");
}
// Verify that the LLVM and AST field offsets agree.
llvm::StructType *ST =
dyn_cast<llvm::StructType>(RL->getLLVMType());
- const llvm::StructLayout *SL = getTargetData().getStructLayout(ST);
+ const llvm::StructLayout *SL = getDataLayout().getStructLayout(ST);
const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
RecordDecl::field_iterator it = D->field_begin();
const FieldDecl *LastFD = 0;
- bool IsMsStruct = D->hasAttr<MsStructAttr>();
+ bool IsMsStruct = D->isMsStruct(getContext());
for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
const FieldDecl *FD = *it;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index d78908dee876..3548dbac6fc1 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -21,7 +21,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/InlineAsm.h"
#include "llvm/Intrinsics.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -132,8 +132,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
- case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
- case Stmt::MSAsmStmtClass: EmitMSAsmStmt(cast<MSAsmStmt>(*S)); break;
+ case Stmt::GCCAsmStmtClass: // Intentional fall-through.
+ case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
case Stmt::ObjCAtTryStmtClass:
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
@@ -237,6 +237,10 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
if (!BI || !BI->isUnconditional())
return;
+ // Can only simplify empty blocks.
+ if (BI != BB->begin())
+ return;
+
BB->replaceAllUsesWith(BI->getSuccessor(0));
BI->eraseFromParent();
BB->eraseFromParent();
@@ -743,6 +747,17 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// Emit the result value, even if unused, to evalute the side effects.
const Expr *RV = S.getRetValue();
+ // Treat block literals in a return expression as if they appeared
+ // in their own scope. This permits a small, easily-implemented
+ // exception to our over-conservative rules about not jumping to
+ // statements following block literals with non-trivial cleanups.
+ RunCleanupsScope cleanupScope(*this);
+ if (const ExprWithCleanups *cleanups =
+ dyn_cast_or_null<ExprWithCleanups>(RV)) {
+ enterFullExpression(cleanups);
+ RV = cleanups->getSubExpr();
+ }
+
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() &&
@@ -779,6 +794,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
AggValueSlot::IsNotAliased));
}
+ cleanupScope.ForceCleanup();
EmitBranchThroughCleanup(ReturnBlock);
}
@@ -899,7 +915,8 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
// If the body of the case is just a 'break', and if there was no fallthrough,
// try to not emit an empty block.
- if ((CGM.getCodeGenOpts().OptimizationLevel > 0) && isa<BreakStmt>(S.getSubStmt())) {
+ if ((CGM.getCodeGenOpts().OptimizationLevel > 0) &&
+ isa<BreakStmt>(S.getSubStmt())) {
JumpDest Block = BreakContinueStack.back().BreakBlock;
// Only do this optimization if there are no cleanups that need emitting.
@@ -1263,6 +1280,10 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
case '=': // Will see this and the following in mult-alt constraints.
case '+':
break;
+ case '#': // Ignore the rest of the constraint alternative.
+ while (Constraint[1] && Constraint[1] != ',')
+ Constraint++;
+ break;
case ',':
Result += "|";
break;
@@ -1323,8 +1344,7 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
}
llvm::Value*
-CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
- const TargetInfo::ConstraintInfo &Info,
+CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
LValue InputValue, QualType InputType,
std::string &ConstraintStr) {
llvm::Value *Arg;
@@ -1333,7 +1353,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
llvm::Type *Ty = ConvertType(InputType);
- uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
+ uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
Ty = llvm::PointerType::getUnqual(Ty);
@@ -1353,7 +1373,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
return Arg;
}
-llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
+llvm::Value* CodeGenFunction::EmitAsmInput(
const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr,
std::string &ConstraintStr) {
@@ -1363,7 +1383,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
- return EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(), ConstraintStr);
+ return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr);
}
/// getAsmSrcLocInfo - Return the !srcloc metadata node to attach to an inline
@@ -1396,23 +1416,8 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
}
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
- // Analyze the asm string to decompose it into its pieces. We know that Sema
- // has already done this, so it is guaranteed to be successful.
- SmallVector<AsmStmt::AsmStringPiece, 4> Pieces;
- unsigned DiagOffs;
- S.AnalyzeAsmString(Pieces, getContext(), DiagOffs);
-
- // Assemble the pieces into the final asm string.
- std::string AsmString;
- for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
- if (Pieces[i].isString())
- AsmString += Pieces[i].getString();
- else if (Pieces[i].getModifier() == '\0')
- AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo());
- else
- AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' +
- Pieces[i].getModifier() + '}';
- }
+ // Assemble the final asm string.
+ std::string AsmString = S.generateAsmString(getContext());
// Get all the output and input constraints together.
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
@@ -1511,7 +1516,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
InOutConstraints += ',';
const Expr *InputExpr = S.getOutputExpr(i);
- llvm::Value *Arg = EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(),
+ llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
InOutConstraints);
if (llvm::Type* AdjTy =
@@ -1549,7 +1554,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
*InputExpr->IgnoreParenNoopCasts(getContext()),
Target, CGM, S);
- llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, Constraints);
+ llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints);
// If this input argument is tied to a larger output result, extend the
// input to be the same size as the output. The LLVM backend wants to see
@@ -1596,7 +1601,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
- StringRef Clobber = S.getClobber(i)->getString();
+ StringRef Clobber = S.getClobber(i);
if (Clobber != "memory" && Clobber != "cc")
Clobber = Target.getNormalizedGCCRegisterName(Clobber);
@@ -1628,15 +1633,22 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::FunctionType *FTy =
llvm::FunctionType::get(ResultType, ArgTypes, false);
+ bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
+ llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ?
+ llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT;
llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, AsmString, Constraints,
- S.isVolatile() || S.getNumOutputs() == 0);
+ llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
+ /* IsAlignStack */ false, AsmDialect);
llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+ Result->addAttribute(llvm::AttrListPtr::FunctionIndex,
+ llvm::Attributes::get(getLLVMContext(),
+ llvm::Attributes::NoUnwind));
// Slap the source location of the inline asm into a !srcloc metadata on the
- // call.
- Result->setMetadata("srcloc", getAsmSrcLocInfo(S.getAsmString(), *this));
+ // call. FIXME: Handle metadata for MS-style inline asms.
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
+ Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(),
+ *this));
// Extract all of the register value results from the asm.
std::vector<llvm::Value*> RegResults;
@@ -1662,12 +1674,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
if (TruncTy->isFloatingPointTy())
Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
- uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
+ uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
Tmp = Builder.CreateTrunc(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
} else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
- uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType());
+ uint64_t TmpSize =CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
Tmp = Builder.CreatePtrToInt(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize));
Tmp = Builder.CreateTrunc(Tmp, TruncTy);
@@ -1681,47 +1693,3 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
}
}
-
-void CodeGenFunction::EmitMSAsmStmt(const MSAsmStmt &S) {
- // MS-style inline assembly is not fully supported, so sema emits a warning.
- if (!CGM.getCodeGenOpts().EmitMicrosoftInlineAsm)
- return;
-
- assert (S.isSimple() && "CodeGen can only handle simple MSAsmStmts.");
-
- std::vector<llvm::Value*> Args;
- std::vector<llvm::Type *> ArgTypes;
- std::string Constraints;
-
- // Clobbers
- for (unsigned i = 0, e = S.getNumClobbers(); i != e; ++i) {
- StringRef Clobber = S.getClobber(i);
-
- if (Clobber != "memory" && Clobber != "cc")
- Clobber = Target.getNormalizedGCCRegisterName(Clobber);
-
- if (i != 0)
- Constraints += ',';
-
- Constraints += "~{";
- Constraints += Clobber;
- Constraints += '}';
- }
-
- // Add machine specific clobbers
- std::string MachineClobbers = Target.getClobbers();
- if (!MachineClobbers.empty()) {
- if (!Constraints.empty())
- Constraints += ',';
- Constraints += MachineClobbers;
- }
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, ArgTypes, false);
-
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, *S.getAsmString(), Constraints, true);
- llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(~0, llvm::Attribute::NoUnwind);
- Result->addAttribute(~0, llvm::Attribute::IANSDialect);
-}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index cdaa26a2bad6..5b37fe4b9634 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -79,15 +79,16 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
llvm::Value *Ptr,
int64_t NonVirtualAdjustment,
- int64_t VirtualAdjustment) {
+ int64_t VirtualAdjustment,
+ bool IsReturnAdjustment) {
if (!NonVirtualAdjustment && !VirtualAdjustment)
return Ptr;
llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
- if (NonVirtualAdjustment) {
- // Do the non-virtual adjustment.
+ if (NonVirtualAdjustment && !IsReturnAdjustment) {
+ // Perform the non-virtual adjustment for a base-to-derived cast.
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
}
@@ -95,7 +96,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
- // Do the virtual adjustment.
+ // Perform the virtual adjustment.
llvm::Value *VTablePtrPtr =
CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
@@ -113,6 +114,11 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
V = CGF.Builder.CreateInBoundsGEP(V, Offset);
}
+ if (NonVirtualAdjustment && IsReturnAdjustment) {
+ // Perform the non-virtual adjustment for a derived-to-base cast.
+ V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+ }
+
// Cast back to the original type.
return CGF.Builder.CreateBitCast(V, Ptr->getType());
}
@@ -150,8 +156,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- if (!CGM.getCodeGenOpts().HiddenWeakTemplateVTables)
- return;
+ return;
break;
}
@@ -199,7 +204,8 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
ReturnValue = PerformTypeAdjustment(CGF, ReturnValue,
Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
+ Thunk.Return.VBaseOffsetOffset,
+ /*IsReturnAdjustment*/true);
if (NullCheckValue) {
CGF.Builder.CreateBr(AdjustEnd);
@@ -248,7 +254,9 @@ void CodeGenFunction::GenerateVarArgsThunk(
llvm::Function *BaseFn = cast<llvm::Function>(Callee);
// Clone to thunk.
- llvm::Function *NewFn = llvm::CloneFunction(BaseFn);
+ llvm::ValueToValueMapTy VMap;
+ llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap,
+ /*ModuleLevelChanges=*/false);
CGM.getModule().getFunctionList().push_back(NewFn);
Fn->replaceAllUsesWith(NewFn);
NewFn->takeName(Fn);
@@ -281,7 +289,8 @@ void CodeGenFunction::GenerateVarArgsThunk(
llvm::Value *AdjustedThisPtr =
PerformTypeAdjustment(*this, ThisPtr,
Thunk.This.NonVirtual,
- Thunk.This.VCallOffsetOffset);
+ Thunk.This.VCallOffsetOffset,
+ /*IsReturnAdjustment*/false);
ThisStore->setOperand(0, AdjustedThisPtr);
if (!Thunk.Return.isEmpty()) {
@@ -324,7 +333,10 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
FunctionArgs.push_back(Param);
}
-
+
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
+
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
SourceLocation());
@@ -335,7 +347,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
llvm::Value *AdjustedThisPtr =
PerformTypeAdjustment(*this, LoadCXXThis(),
Thunk.This.NonVirtual,
- Thunk.This.VCallOffsetOffset);
+ Thunk.This.VCallOffsetOffset,
+ /*IsReturnAdjustment*/false);
CallArgList CallArgs;
@@ -455,6 +468,8 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
return;
}
+ CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn);
+
if (ThunkFn->isVarArg()) {
// Varargs thunks are special; we can't just generate a call because
// we can't copy the varargs. Our implementation is rather
@@ -524,7 +539,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
unsigned NextVTableThunkIndex = 0;
- llvm::Constant* PureVirtualFn = 0;
+ llvm::Constant *PureVirtualFn = 0, *DeletedVirtualFn = 0;
for (unsigned I = 0; I != NumComponents; ++I) {
VTableComponent Component = Components[I];
@@ -573,14 +588,25 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
// We have a pure virtual member function.
if (!PureVirtualFn) {
- llvm::FunctionType *Ty =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
- StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName();
- PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName);
- PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
+ llvm::FunctionType *Ty =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName();
+ PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName);
+ PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
CGM.Int8PtrTy);
}
Init = PureVirtualFn;
+ } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) {
+ if (!DeletedVirtualFn) {
+ llvm::FunctionType *Ty =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ StringRef DeletedCallName =
+ CGM.getCXXABI().GetDeletedVirtualCallName();
+ DeletedVirtualFn = CGM.CreateRuntimeFunction(Ty, DeletedCallName);
+ DeletedVirtualFn = llvm::ConstantExpr::getBitCast(DeletedVirtualFn,
+ CGM.Int8PtrTy);
+ }
+ Init = DeletedVirtualFn;
} else {
// Check if we should use a thunk.
if (NextVTableThunkIndex < NumVTableThunks &&
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index dd32167b8477..9d6d183d97d9 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -65,9 +65,11 @@ namespace clang {
TargetOpts(targetopts),
LangOpts(langopts),
AsmOutStream(OS),
+ Context(),
LLVMIRGeneration("LLVM IR Generation Time"),
Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
- LinkModule(LinkModule) {
+ LinkModule(LinkModule)
+ {
llvm::TimePassesIsEnabled = TimePasses;
}
@@ -379,7 +381,7 @@ void CodeGenAction::ExecuteAction() {
// FIXME: This is stupid, IRReader shouldn't take ownership.
llvm::MemoryBuffer *MainFileCopy =
llvm::MemoryBuffer::getMemBufferCopy(MainFile->getBuffer(),
- getCurrentFile().c_str());
+ getCurrentFile());
llvm::SMDiagnostic Err;
TheModule.reset(ParseIR(MainFileCopy, Err, *VMContext));
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 1d02861ed786..18f1623d242e 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -24,7 +24,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
#include "llvm/MDBuilder.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -32,6 +32,10 @@ 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),
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
@@ -40,8 +44,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0),
CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0),
TerminateHandler(0), TrapBB(0) {
-
- CatchUndefined = getContext().getLangOpts().CatchUndefined;
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
}
@@ -348,11 +350,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
RE = FD->redecls_end(); RI != RE; ++RI)
if (RI->isInlineSpecified()) {
- Fn->addFnAttr(llvm::Attribute::InlineHint);
+ Fn->addFnAttr(llvm::Attributes::InlineHint);
break;
}
- if (getContext().getLangOpts().OpenCL) {
+ if (getLangOpts().OpenCL) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
EmitOpenCLKernelMetadata(FD, Fn);
@@ -485,7 +487,7 @@ static void TryMarkNoThrow(llvm::Function *F) {
} else if (isa<llvm::ResumeInst>(&*BI)) {
return;
}
- F->setDoesNotThrow(true);
+ F->setDoesNotThrow();
}
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
@@ -493,8 +495,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
- if (CGM.getModuleDebugInfo() && !FD->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getModuleDebugInfo();
+ if (!FD->hasAttr<NoDebugAttr>())
+ maybeInitializeDebugInfo();
FunctionArgList Args;
QualType ResTy = FD->getResultType();
@@ -517,7 +519,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitDestructorBody(Args);
else if (isa<CXXConstructorDecl>(FD))
EmitConstructorBody(Args);
- else if (getContext().getLangOpts().CUDA &&
+ else if (getLangOpts().CUDA &&
!CGM.getCodeGenOpts().CUDAIsDevice &&
FD->hasAttr<CUDAGlobalAttr>())
CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args);
@@ -535,6 +537,24 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
else
EmitFunctionBody(Args);
+ // C++11 [stmt.return]p2:
+ // Flowing off the end of a function [...] results in undefined behavior in
+ // a value-returning function.
+ // C11 6.9.1p12:
+ // If the '}' that terminates a function is reached, and the value of the
+ // function call is used by the caller, the behavior is undefined.
+ if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
+ !FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
+ if (getLangOpts().SanitizeReturn)
+ EmitCheck(Builder.getFalse(), "missing_return",
+ EmitCheckSourceLocation(FD->getLocation()),
+ llvm::ArrayRef<llvm::Value*>());
+ else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ }
+
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
@@ -806,7 +826,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
void
CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
// Ignore empty classes in C++.
- if (getContext().getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
return;
@@ -983,8 +1003,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
arrayType = getContext().getAsArrayType(eltType);
}
- unsigned AddressSpace =
- cast<llvm::PointerType>(addr->getType())->getAddressSpace();
+ unsigned AddressSpace = addr->getType()->getPointerAddressSpace();
llvm::Type *BaseType = ConvertType(eltType)->getPointerTo(AddressSpace);
addr = Builder.CreateBitCast(addr, BaseType, "array.begin");
} else {
@@ -1027,6 +1046,7 @@ CodeGenFunction::getVLASize(const VariableArrayType *type) {
numElements = vlaSize;
} else {
// It's undefined behavior if this wraps around, so mark it that way.
+ // FIXME: Teach -fcatch-undefined-behavior to trap this.
numElements = Builder.CreateNUWMul(numElements, vlaSize);
}
} while ((type = getContext().getAsVariableArrayType(elementType)));
@@ -1104,10 +1124,26 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// e.g. with a typedef and a pointer to it.
llvm::Value *&entry = VLASizeMap[size];
if (!entry) {
+ llvm::Value *Size = EmitScalarExpr(size);
+
+ // C11 6.7.6.2p5:
+ // 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 &&
+ size->getType()->isSignedIntegerType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
+ llvm::Constant *StaticArgs[] = {
+ EmitCheckSourceLocation(size->getLocStart()),
+ EmitCheckTypeDescriptor(size->getType())
+ };
+ EmitCheck(Builder.CreateICmpSGT(Size, Zero),
+ "vla_bound_not_positive", StaticArgs, Size);
+ }
+
// Always zexting here would be wrong if it weren't
// undefined behavior to have a negative bound.
- entry = Builder.CreateIntCast(EmitScalarExpr(size), SizeTy,
- /*signed*/ false);
+ entry = Builder.CreateIntCast(Size, SizeTy, /*signed*/ false);
}
}
type = vat->getElementType();
@@ -1156,7 +1192,7 @@ void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
llvm::Constant *Init) {
assert (Init && "Invalid DeclRefExpr initializer!");
if (CGDebugInfo *Dbg = getDebugInfo())
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo)
Dbg->EmitGlobalVariable(E->getDecl(), Init);
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index ed3e43beb0f8..f2ab226ab530 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -222,8 +222,7 @@ public:
/// immediately-enclosing context of the cleanup scope. For
/// EH cleanups, this is run in a terminate context.
///
- // \param IsForEHCleanup true if this is for an EH cleanup, false
- /// if for a normal cleanup.
+ // \param flags cleanup kind.
virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
};
@@ -533,8 +532,8 @@ public:
/// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code.
class CodeGenFunction : public CodeGenTypeCache {
- CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT
- void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT
+ CodeGenFunction(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
+ void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
friend class CGCXXABI;
public:
@@ -595,8 +594,9 @@ public:
/// potentially higher performance penalties.
unsigned char BoundsChecking;
- /// CatchUndefined - Emit run-time checks to catch undefined behaviors.
- bool CatchUndefined;
+ /// \brief Whether any type-checking sanitizers are enabled. If \c false,
+ /// calls to EmitTypeCheck can be skipped.
+ bool SanitizePerformTypeCheck;
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
@@ -795,8 +795,8 @@ public:
bool OldDidCallStackSave;
bool PerformCleanup;
- RunCleanupsScope(const RunCleanupsScope &); // DO NOT IMPLEMENT
- RunCleanupsScope &operator=(const RunCleanupsScope &); // DO NOT IMPLEMENT
+ RunCleanupsScope(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
protected:
CodeGenFunction& CGF;
@@ -839,8 +839,8 @@ public:
SourceRange Range;
bool PopDebugStack;
- LexicalScope(const LexicalScope &); // DO NOT IMPLEMENT THESE
- LexicalScope &operator=(const LexicalScope &);
+ LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION;
public:
/// \brief Enter a new cleanup scope.
@@ -908,7 +908,7 @@ public:
/// themselves).
void popCatchScope();
- llvm::BasicBlock *getEHResumeBlock();
+ llvm::BasicBlock *getEHResumeBlock(bool isCleanup);
llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope);
/// An object to manage conditionally-evaluated expressions.
@@ -1213,6 +1213,14 @@ public:
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
ASTContext &getContext() const { return CGM.getContext(); }
+ /// Returns true if DebugInfo is actually initialized.
+ bool maybeInitializeDebugInfo() {
+ if (CGM.getModuleDebugInfo()) {
+ DebugInfo = CGM.getModuleDebugInfo();
+ return true;
+ }
+ return false;
+ }
CGDebugInfo *getDebugInfo() {
if (DisableDebugInfo)
return NULL;
@@ -1504,7 +1512,7 @@ public:
static bool hasAggregateLLVMType(QualType T);
/// createBasicBlock - Create an LLVM basic block.
- llvm::BasicBlock *createBasicBlock(StringRef name = "",
+ llvm::BasicBlock *createBasicBlock(const Twine &name = "",
llvm::Function *parent = 0,
llvm::BasicBlock *before = 0) {
#ifdef NDEBUG
@@ -1631,7 +1639,7 @@ public:
/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
/// the result should be returned.
///
- /// \param IgnoreResult - True if the resulting value isn't used.
+ /// \param ignoreResult True if the resulting value isn't used.
RValue EmitAnyExpr(const Expr *E,
AggValueSlot aggSlot = AggValueSlot::ignored(),
bool ignoreResult = false);
@@ -1654,13 +1662,26 @@ public:
void EmitExprAsInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit);
+ /// EmitAggregateCopy - Emit an aggrate 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);
+ }
+
/// EmitAggregateCopy - Emit an aggrate copy.
///
/// \param isVolatile - True iff either the source or the destination is
/// volatile.
+ /// \param isAssignment - If false, allow padding to be copied. This often
+ /// yields more efficient.
void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
QualType EltTy, bool isVolatile=false,
- CharUnits Alignment = CharUnits::Zero());
+ CharUnits Alignment = CharUnits::Zero(),
+ bool isAssignment = false);
/// StartBlock - Start new block named N. If insert block is a dummy block
/// then reuse it.
@@ -1829,12 +1850,37 @@ public:
llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
+ llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E);
void MaybeEmitStdInitializerListCleanup(llvm::Value *loc, const Expr *init);
void EmitStdInitializerListCleanup(llvm::Value *loc,
const InitListExpr *init);
- void EmitCheck(llvm::Value *, unsigned Size);
+ /// \brief Situations in which we might emit a check for the suitability of a
+ /// pointer or glvalue.
+ enum TypeCheckKind {
+ /// Checking the operand of a load. Must be suitably sized and aligned.
+ TCK_Load,
+ /// Checking the destination of a store. Must be suitably sized and aligned.
+ TCK_Store,
+ /// Checking the bound value in a reference binding. Must be suitably sized
+ /// and aligned, but is not required to refer to an object (until the
+ /// reference is used), per core issue 453.
+ TCK_ReferenceBinding,
+ /// Checking the object expression in a non-static data member access. Must
+ /// be an object within its lifetime.
+ TCK_MemberAccess,
+ /// Checking the 'this' pointer for a call to a non-static member function.
+ /// Must be an object within its lifetime.
+ TCK_MemberCall,
+ /// Checking the 'this' pointer for a constructor call.
+ TCK_ConstructorCall
+ };
+
+ /// \brief Emit a check that \p V is the address of storage of the
+ /// appropriate size and alignment for an object of type \p Type.
+ void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
+ QualType Type, CharUnits Alignment = CharUnits::Zero());
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
@@ -1981,7 +2027,6 @@ public:
void EmitCaseStmt(const CaseStmt &S);
void EmitCaseStmtRange(const CaseStmt &S);
void EmitAsmStmt(const AsmStmt &S);
- void EmitMSAsmStmt(const MSAsmStmt &S);
void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
@@ -2033,11 +2078,10 @@ public:
///
LValue EmitLValue(const Expr *E);
- /// EmitCheckedLValue - Same as EmitLValue but additionally we generate
- /// checking code to guard against undefined behavior. This is only
- /// suitable when we know that the address will be used to access the
- /// object.
- LValue EmitCheckedLValue(const Expr *E);
+ /// \brief Same as EmitLValue but additionally we generate checking code to
+ /// guard against undefined behavior. This is only suitable when we know
+ /// that the address will be used to access the object.
+ LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
@@ -2178,6 +2222,7 @@ public:
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
LValue EmitLambdaLValue(const LambdaExpr *E);
LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
+ LValue EmitCXXUuidofLValue(const CXXUuidofExpr *E);
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
@@ -2230,6 +2275,7 @@ public:
const CXXRecordDecl *RD);
RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
+ SourceLocation CallLoc,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
@@ -2310,6 +2356,7 @@ public:
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);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
@@ -2516,9 +2563,29 @@ public:
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock);
- /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll
- /// generate a branch around the created basic block as necessary.
- llvm::BasicBlock *getTrapBB();
+ /// \brief Emit a description of a type in a format suitable for passing to
+ /// a runtime sanitizer handler.
+ llvm::Constant *EmitCheckTypeDescriptor(QualType T);
+
+ /// \brief Convert a value into a format suitable for passing to a runtime
+ /// sanitizer handler.
+ llvm::Value *EmitCheckValue(llvm::Value *V);
+
+ /// \brief Emit a description of a source location in a format suitable for
+ /// passing to a runtime sanitizer handler.
+ llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
+
+ /// \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);
+
+ /// \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);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
@@ -2553,12 +2620,10 @@ private:
SmallVector<llvm::Value*, 16> &Args,
llvm::FunctionType *IRFuncTy);
- llvm::Value* EmitAsmInput(const AsmStmt &S,
- const TargetInfo::ConstraintInfo &Info,
+ llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr, std::string &ConstraintStr);
- llvm::Value* EmitAsmInputLValue(const AsmStmt &S,
- const TargetInfo::ConstraintInfo &Info,
+ llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
LValue InputValue, QualType InputType,
std::string &ConstraintStr);
@@ -2624,15 +2689,9 @@ private:
void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
- /// GetPointeeAlignment - Given an expression with a pointer type, find the
- /// alignment of the type referenced by the pointer. Skip over implicit
- /// casts.
- unsigned GetPointeeAlignment(const Expr *Addr);
-
- /// GetPointeeAlignmentValue - Given an expression with a pointer type, find
- /// the alignment of the type referenced by the pointer. Skip over implicit
- /// casts. Return the alignment as an llvm::Value.
- llvm::Value *GetPointeeAlignmentValue(const Expr *Addr);
+ /// GetPointeeAlignment - Given an expression with a pointer type, emit the
+ /// value and compute our best estimate of the alignment of the pointee.
+ std::pair<llvm::Value*, unsigned> EmitPointerWithAlignment(const Expr *Addr);
};
/// Helper class with most of the code for saving a value for a
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 3ae3c521300b..17972e29b65a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -42,7 +42,7 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Target/Mangler.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -62,10 +62,10 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
- llvm::Module &M, const llvm::TargetData &TD,
+ llvm::Module &M, const llvm::DataLayout &TD,
DiagnosticsEngine &diags)
: Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
- TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
+ TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
Types(*this),
TBAA(0),
@@ -103,14 +103,14 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
createCUDARuntime();
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.ThreadSanitizer ||
+ if (LangOpts.SanitizeThread ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(),
ABI.getMangleContext());
// If debug info or coverage generation is enabled, create the CGDebugInfo
// object.
- if (CodeGenOpts.DebugInfo != CodeGenOptions::NoDebugInfo ||
+ if (CodeGenOpts.getDebugInfo() != CodeGenOptions::NoDebugInfo ||
CodeGenOpts.EmitGcovArcs ||
CodeGenOpts.EmitGcovNotes)
DebugInfo = new CGDebugInfo(*this);
@@ -202,6 +202,12 @@ llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() {
return TBAA->getTBAAInfoForVTablePtr();
}
+llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructInfo(QTy);
+}
+
void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
@@ -287,7 +293,7 @@ void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV,
assert(D.isThreadSpecified() && "setting TLS mode on non-TLS var!");
llvm::GlobalVariable::ThreadLocalMode TLM;
- TLM = GetLLVMTLSModel(CodeGenOpts.DefaultTLSModel);
+ TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
// Override the TLS model if it is explicitly specified.
if (D.hasAttr<TLSModelAttr>()) {
@@ -347,9 +353,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
// to deal with mixed-visibility symbols.
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- if (!CodeGenOpts.HiddenWeakTemplateVTables)
- return;
- break;
+ return;
}
// If there's a key function, there may be translation units
@@ -529,7 +533,7 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
unsigned CallingConv;
AttributeListType AttributeList;
ConstructAttributeList(Info, D, AttributeList, CallingConv);
- F->setAttributes(llvm::AttrListPtr::get(AttributeList));
+ F->setAttributes(llvm::AttrListPtr::get(getLLVMContext(), AttributeList));
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -559,39 +563,46 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->setHasUWTable();
if (!hasUnwindExceptions(LangOpts))
- F->addFnAttr(llvm::Attribute::NoUnwind);
+ F->addFnAttr(llvm::Attributes::NoUnwind);
if (D->hasAttr<NakedAttr>()) {
// Naked implies noinline: we should not be inlining such functions.
- F->addFnAttr(llvm::Attribute::Naked);
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::Naked);
+ F->addFnAttr(llvm::Attributes::NoInline);
}
if (D->hasAttr<NoInlineAttr>())
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
// (noinline wins over always_inline, and we can't specify both in IR)
if ((D->hasAttr<AlwaysInlineAttr>() || D->hasAttr<ForceInlineAttr>()) &&
- !F->hasFnAttr(llvm::Attribute::NoInline))
- F->addFnAttr(llvm::Attribute::AlwaysInline);
+ !F->getFnAttributes().hasAttribute(llvm::Attributes::NoInline))
+ F->addFnAttr(llvm::Attributes::AlwaysInline);
// FIXME: Communicate hot and cold attributes to LLVM more directly.
if (D->hasAttr<ColdAttr>())
- F->addFnAttr(llvm::Attribute::OptimizeForSize);
+ F->addFnAttr(llvm::Attributes::OptimizeForSize);
+
+ if (D->hasAttr<MinSizeAttr>())
+ F->addFnAttr(llvm::Attributes::MinSize);
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
+ if (MD->isVirtual())
+ F->setUnnamedAddr(true);
+
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- F->addFnAttr(llvm::Attribute::StackProtect);
+ F->addFnAttr(llvm::Attributes::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- F->addFnAttr(llvm::Attribute::StackProtectReq);
+ F->addFnAttr(llvm::Attributes::StackProtectReq);
- if (LangOpts.AddressSanitizer) {
+ 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::Attribute::AddressSafety);
+ F->addFnAttr(llvm::Attributes::AddressSafety);
}
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
@@ -636,7 +647,8 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
if (unsigned IID = F->getIntrinsicID()) {
// If this is an intrinsic function, set the function's attributes
// to the intrinsic's attributes.
- F->setAttributes(llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)IID));
+ F->setAttributes(llvm::Intrinsic::getAttributes(getLLVMContext(),
+ (llvm::Intrinsic::ID)IID));
return;
}
@@ -822,6 +834,49 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
return !getContext().DeclMustBeEmitted(Global);
}
+llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
+ const CXXUuidofExpr* E) {
+ // Sema has verified that IIDSource has a __declspec(uuid()), and that its
+ // well-formed.
+ StringRef Uuid;
+ if (E->isTypeOperand())
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(E->getTypeOperand())->getGuid();
+ else {
+ // Special case: __uuidof(0) means an all-zero GUID.
+ Expr *Op = E->getExprOperand();
+ if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid();
+ else
+ Uuid = "00000000-0000-0000-0000-000000000000";
+ }
+ std::string Name = "__uuid_" + Uuid.str();
+
+ // Look for an existing global.
+ if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name))
+ return GV;
+
+ llvm::Constant *Init = EmitUuidofInitializer(Uuid, E->getType());
+ assert(Init && "failed to initialize as constant");
+
+ // GUIDs are assumed to be 16 bytes, spread over 4-2-2-8 bytes. However, the
+ // first field is declared as "long", which for many targets is 8 bytes.
+ // Those architectures are not supported. (With the MS abi, long is always 4
+ // bytes.)
+ llvm::Type *GuidType = getTypes().ConvertType(E->getType());
+ if (Init->getType() != GuidType) {
+ DiagnosticsEngine &Diags = getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "__uuidof codegen is not supported on this architecture");
+ Diags.Report(E->getExprLoc(), DiagID) << E->getSourceRange();
+ Init = llvm::UndefValue::get(GuidType);
+ }
+
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), GuidType,
+ /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, Init, Name);
+ GV->setUnnamedAddr(true);
+ return GV;
+}
+
llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
const AliasAttr *AA = VD->getAttr<AliasAttr>();
assert(AA && "No alias?");
@@ -830,19 +885,23 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
// See if there is already something with the target's name in the module.
llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
+ if (Entry) {
+ unsigned AS = getContext().getTargetAddressSpace(VD->getType());
+ return llvm::ConstantExpr::getBitCast(Entry, DeclTy->getPointerTo(AS));
+ }
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(),
+ Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy,
+ GlobalDecl(cast<FunctionDecl>(VD)),
/*ForVTable=*/false);
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy), 0);
- if (!Entry) {
- llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
- F->setLinkage(llvm::Function::ExternalWeakLinkage);
- WeakRefReferences.insert(F);
- }
+
+ llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
+ F->setLinkage(llvm::Function::ExternalWeakLinkage);
+ WeakRefReferences.insert(F);
return Aliasee;
}
@@ -1051,12 +1110,10 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
- if (WeakRefReferences.count(Entry)) {
+ if (WeakRefReferences.erase(Entry)) {
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
if (FD && !FD->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
-
- WeakRefReferences.erase(Entry);
}
if (Entry->getType()->getElementType() == Ty)
@@ -1085,8 +1142,8 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
- if (ExtraAttrs != llvm::Attribute::None)
- F->addFnAttr(ExtraAttrs);
+ if (ExtraAttrs.hasAttributes())
+ F->addAttribute(llvm::AttrListPtr::FunctionIndex, ExtraAttrs);
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@@ -1197,11 +1254,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
- if (WeakRefReferences.count(Entry)) {
+ if (WeakRefReferences.erase(Entry)) {
if (D && !D->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
-
- WeakRefReferences.erase(Entry);
}
if (UnnamedAddr)
@@ -1279,7 +1334,7 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
// Because C++ name mangling, the only way we can end up with an already
// existing global with the same name is if it has been declared extern "C".
- assert(GV->isDeclaration() && "Declaration has wrong type!");
+ assert(GV->isDeclaration() && "Declaration has wrong type!");
OldGV = GV;
}
@@ -1424,7 +1479,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
return Context.toCharUnitsFromBits(
- TheTargetData.getTypeStoreSizeInBits(Ty));
+ TheDataLayout.getTypeStoreSizeInBits(Ty));
}
llvm::Constant *
@@ -1473,10 +1528,10 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
// Now clone the InitListExpr to initialize the array instead.
// Incredible hack: we want to use the existing InitListExpr here, so we need
// to tell it that it no longer initializes a std::initializer_list.
- Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(),
- const_cast<InitListExpr*>(init)->getInits(),
- init->getNumInits(),
- init->getRBraceLoc());
+ ArrayRef<Expr*> Inits(const_cast<InitListExpr*>(init)->getInits(),
+ init->getNumInits());
+ Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(), Inits,
+ init->getRBraceLoc());
arrayInit->setType(arrayType);
if (!cleanups.empty())
@@ -1682,9 +1737,21 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
+ // If we are compiling with ASan, add metadata indicating dynamically
+ // initialized globals.
+ if (LangOpts.SanitizeAddress && NeedsGlobalCtor) {
+ llvm::Module &M = getModule();
+
+ llvm::NamedMDNode *DynamicInitializers =
+ M.getOrInsertNamedMetadata("llvm.asan.dynamically_initialized_globals");
+ llvm::Value *GlobalToAdd[] = { GV };
+ llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalToAdd);
+ DynamicInitializers->addOperand(ThisGlobal);
+ }
+
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo)
+ if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo)
DI->EmitGlobalVariable(GV, D);
}
@@ -1758,8 +1825,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Attributes RAttrs = AttrList.getRetAttributes();
// Add the return attributes.
- if (RAttrs)
- AttrVec.push_back(llvm::AttributeWithIndex::get(0, RAttrs));
+ 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
@@ -1775,14 +1844,18 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
}
// Add any parameter attributes.
- if (llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1))
+ llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1);
+ if (PAttrs.hasAttributes())
AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs));
}
if (DontTransform)
continue;
- if (llvm::Attributes FnAttrs = AttrList.getFnAttributes())
- AttrVec.push_back(llvm::AttributeWithIndex::get(~0, FnAttrs));
+ llvm::Attributes FnAttrs = AttrList.getFnAttributes();
+ if (FnAttrs.hasAttributes())
+ AttrVec.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
+ FnAttrs));
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
@@ -1791,7 +1864,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
ArgList.clear();
if (!NewCall->getType()->isVoidTy())
NewCall->takeName(CI);
- NewCall->setAttributes(llvm::AttrListPtr::get(AttrVec));
+ NewCall->setAttributes(llvm::AttrListPtr::get(OldFn->getContext(), AttrVec));
NewCall->setCallingConv(CI->getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
@@ -1911,7 +1984,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
// if a deferred decl.
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(),
+ Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD,
/*ForVTable=*/false);
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
@@ -1987,7 +2060,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
IsUTF16 = true;
SmallVector<UTF16, 128> ToBuf(NumBytes + 1); // +1 for ending nulls.
- const UTF8 *FromPtr = (UTF8 *)String.data();
+ const UTF8 *FromPtr = (const UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
(void)ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes,
@@ -2019,7 +2092,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
bool isUTF16 = false;
llvm::StringMapEntry<llvm::Constant*> &Entry =
GetConstantCFStringEntry(CFConstantStringMap, Literal,
- getTargetData().isLittleEndian(),
+ getDataLayout().isLittleEndian(),
isUTF16, StringLength);
if (llvm::Constant *C = Entry.getValue())
@@ -2429,7 +2502,7 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
ObjCPropertyDecl *PD = PID->getPropertyDecl();
// Determine which methods need to be implemented, some may have
- // been overridden. Note that ::isSynthesized is not the method
+ // been overridden. Note that ::isPropertyAccessor is not the method
// we want, that just indicates if the decl came from a
// property. What we want to know is if the method is defined in
// this implementation.
@@ -2465,11 +2538,11 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
cxxSelector, getContext().VoidTy, 0, D,
/*isInstance=*/true, /*isVariadic=*/false,
- /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true,
+ /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
- D->setHasCXXStructors(true);
+ D->setHasDestructors(true);
}
// If the implementation doesn't have any ivar initializers, we don't need
@@ -2487,13 +2560,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
getContext().getObjCIdType(), 0,
D, /*isInstance=*/true,
/*isVariadic=*/false,
- /*isSynthesized=*/true,
+ /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
- D->setHasCXXStructors(true);
+ D->setHasNonZeroConstructors(true);
}
/// EmitNamespace - Emit all declarations in a namespace.
@@ -2512,8 +2585,17 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
}
for (RecordDecl::decl_iterator I = LSD->decls_begin(), E = LSD->decls_end();
- I != E; ++I)
+ I != E; ++I) {
+ // Meta-data for ObjC class includes references to implemented methods.
+ // Generate class's method definitions first.
+ if (ObjCImplDecl *OID = dyn_cast<ObjCImplDecl>(*I)) {
+ for (ObjCContainerDecl::method_iterator M = OID->meth_begin(),
+ MEnd = OID->meth_end();
+ M != MEnd; ++M)
+ EmitTopLevelDecl(*M);
+ }
EmitTopLevelDecl(*I);
+ }
}
/// EmitTopLevelDecl - Emit code for a single top level declaration.
@@ -2737,3 +2819,32 @@ void CodeGenModule::EmitCoverageFile() {
}
}
}
+
+llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
+ QualType GuidType) {
+ // Sema has checked that all uuid strings are of the form
+ // "12345678-1234-1234-1234-1234567890ab".
+ assert(Uuid.size() == 36);
+ 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]));
+ }
+
+ llvm::APInt Field0(32, StringRef(Uuidstr , 8), 16);
+ llvm::APInt Field1(16, StringRef(Uuidstr + 9, 4), 16);
+ llvm::APInt Field2(16, StringRef(Uuidstr + 14, 4), 16);
+ static const int Field3ValueOffsets[] = { 19, 21, 24, 26, 28, 30, 32, 34 };
+
+ APValue InitStruct(APValue::UninitStruct(), /*NumBases=*/0, /*NumFields=*/4);
+ InitStruct.getStructField(0) = APValue(llvm::APSInt(Field0));
+ InitStruct.getStructField(1) = APValue(llvm::APSInt(Field1));
+ InitStruct.getStructField(2) = APValue(llvm::APSInt(Field2));
+ APValue& Arr = InitStruct.getStructField(3);
+ Arr = APValue(APValue::UninitArray(), 8, 8);
+ for (int t = 0; t < 8; ++t)
+ Arr.getArrayInitializedElt(t) = APValue(llvm::APSInt(
+ llvm::APInt(8, StringRef(Uuidstr + Field3ValueOffsets[t], 2), 16)));
+
+ return EmitConstantValue(InitStruct, GuidType);
+}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index d6ff50d5ad79..1167c87ce13b 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -35,7 +35,7 @@ namespace llvm {
class ConstantInt;
class Function;
class GlobalValue;
- class TargetData;
+ class DataLayout;
class FunctionType;
class LLVMContext;
}
@@ -210,8 +210,8 @@ struct ARCEntrypoints {
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public CodeGenTypeCache {
- CodeGenModule(const CodeGenModule&); // DO NOT IMPLEMENT
- void operator=(const CodeGenModule&); // DO NOT IMPLEMENT
+ CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION;
+ void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION;
typedef std::vector<std::pair<llvm::Constant*, int> > CtorList;
@@ -219,7 +219,7 @@ class CodeGenModule : public CodeGenTypeCache {
const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
- const llvm::TargetData &TheTargetData;
+ const llvm::DataLayout &TheDataLayout;
mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
DiagnosticsEngine &Diags;
CGCXXABI &ABI;
@@ -296,11 +296,18 @@ class CodeGenModule : public CodeGenTypeCache {
/// order.
llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
+ typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData;
+
+ struct GlobalInitPriorityCmp {
+ bool operator()(const GlobalInitData &LHS,
+ const GlobalInitData &RHS) const {
+ return LHS.first.priority < RHS.first.priority;
+ }
+ };
+
/// - Global variables with initializers whose order of initialization
/// is set by init_priority attribute.
-
- SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8>
- PrioritizedCXXGlobalInits;
+ SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
/// CXXGlobalDtors - Global destructor functions and arguments that need to
/// run on termination.
@@ -357,7 +364,7 @@ class CodeGenModule : public CodeGenTypeCache {
/// @}
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
- llvm::Module &M, const llvm::TargetData &TD,
+ llvm::Module &M, const llvm::DataLayout &TD,
DiagnosticsEngine &Diags);
~CodeGenModule();
@@ -451,7 +458,7 @@ public:
CodeGenVTables &getVTables() { return VTables; }
VTableContext &getVTableContext() { return VTables.getVTableContext(); }
DiagnosticsEngine &getDiags() const { return Diags; }
- const llvm::TargetData &getTargetData() const { return TheTargetData; }
+ const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
const TargetInfo &getTarget() const { return Context.getTargetInfo(); }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
const TargetCodeGenInfo &getTargetCodeGenInfo();
@@ -461,6 +468,7 @@ public:
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
+ llvm::MDNode *getTBAAStructInfo(QualType QTy);
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
@@ -548,6 +556,9 @@ public:
/// for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
+ /// GetAddrOfUuidDescriptor - Get the address of a uuid descriptor .
+ llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
+
/// GetAddrOfThunk - Get the address of the thunk for the given global decl.
llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk);
@@ -701,7 +712,7 @@ public:
llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty,
StringRef Name,
llvm::Attributes ExtraAttrs =
- llvm::Attribute::None);
+ llvm::Attributes());
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
@@ -880,7 +891,7 @@ private:
GlobalDecl D,
bool ForVTable,
llvm::Attributes ExtraAttrs =
- llvm::Attribute::None);
+ llvm::Attributes());
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
const VarDecl *D,
@@ -984,6 +995,9 @@ private:
/// to emit the .gcno and .gcda files in a way that persists in .bc files.
void EmitCoverageFile();
+ /// Emits the initializer for a uuidof string.
+ llvm::Constant *EmitUuidofInitializer(StringRef uuidstr, QualType IIDType);
+
/// MayDeferGeneration - Determine if the given decl can be emitted
/// lazily; this is only relevant for definitions. The given decl
/// must be either a function or var decl.
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index bab60afbb7f2..d9004a02ae25 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -17,6 +17,7 @@
#include "CodeGenTBAA.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/Mangle.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/LLVMContext.h"
@@ -167,3 +168,59 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() {
return MDHelper.createTBAANode("vtable pointer", getRoot());
}
+
+bool
+CodeGenTBAA::CollectFields(uint64_t BaseOffset,
+ QualType QTy,
+ SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &
+ Fields,
+ bool MayAlias) {
+ /* Things not handled yet include: C++ base classes, bitfields, */
+
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ // TODO: Handle C++ base classes.
+ if (const CXXRecordDecl *Decl = dyn_cast<CXXRecordDecl>(RD))
+ if (Decl->bases_begin() != Decl->bases_end())
+ return false;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i, ++idx) {
+ uint64_t Offset = BaseOffset +
+ Layout.getFieldOffset(idx) / Context.getCharWidth();
+ QualType FieldQTy = i->getType();
+ if (!CollectFields(Offset, FieldQTy, Fields,
+ MayAlias || TypeHasMayAlias(FieldQTy)))
+ return false;
+ }
+ return true;
+ }
+
+ /* Otherwise, treat whatever it is as a field. */
+ uint64_t Offset = BaseOffset;
+ uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity();
+ llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy);
+ Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAAInfo));
+ return true;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
+ const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
+
+ if (llvm::MDNode *N = StructMetadataCache[Ty])
+ return N;
+
+ SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields;
+ if (CollectFields(0, QTy, Fields, TypeHasMayAlias(QTy)))
+ return MDHelper.createTBAAStructNode(Fields);
+
+ // For now, handle any other kind of type conservatively.
+ return StructMetadataCache[Ty] = NULL;
+}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index c17a5cf03c60..eedb996f3eef 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -49,6 +49,10 @@ class CodeGenTBAA {
/// MetadataCache - This maps clang::Types to llvm::MDNodes describing them.
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
+ /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
+ /// them for struct assignments.
+ llvm::DenseMap<const Type *, llvm::MDNode *> StructMetadataCache;
+
llvm::MDNode *Root;
llvm::MDNode *Char;
@@ -60,6 +64,13 @@ class CodeGenTBAA {
/// considered to be equivalent to it.
llvm::MDNode *getChar();
+ /// CollectFields - Collect information about the fields of a type for
+ /// !tbaa.struct metadata formation. Return false for an unsupported type.
+ bool CollectFields(uint64_t BaseOffset,
+ QualType Ty,
+ SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields,
+ bool MayAlias);
+
public:
CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext,
const CodeGenOptions &CGO,
@@ -74,6 +85,10 @@ public:
/// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a
/// dereference of a vtable pointer.
llvm::MDNode *getTBAAInfoForVTablePtr();
+
+ /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
+ /// the given type.
+ llvm::MDNode *getTBAAStructInfo(QualType QTy);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 9a78daefc71c..3c6c5c9a2e2f 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -23,13 +23,13 @@
#include "clang/AST/RecordLayout.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
CodeGenTypes::CodeGenTypes(CodeGenModule &CGM)
: Context(CGM.getContext()), Target(Context.getTargetInfo()),
- TheModule(CGM.getModule()), TheTargetData(CGM.getTargetData()),
+ TheModule(CGM.getModule()), TheDataLayout(CGM.getDataLayout()),
TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()),
TheCXXABI(CGM.getCXXABI()),
CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) {
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 3c29d2d74626..0519911a07ef 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -23,7 +23,7 @@
namespace llvm {
class FunctionType;
class Module;
- class TargetData;
+ class DataLayout;
class Type;
class LLVMContext;
class StructType;
@@ -62,7 +62,7 @@ class CodeGenTypes {
ASTContext &Context;
const TargetInfo &Target;
llvm::Module &TheModule;
- const llvm::TargetData &TheTargetData;
+ const llvm::DataLayout &TheDataLayout;
const ABIInfo &TheABIInfo;
CGCXXABI &TheCXXABI;
const CodeGenOptions &CodeGenOpts;
@@ -108,7 +108,7 @@ public:
CodeGenTypes(CodeGenModule &CGM);
~CodeGenTypes();
- const llvm::TargetData &getTargetData() const { return TheTargetData; }
+ const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const { return TheABIInfo; }
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0b7ce36d5b94..245150c88d0a 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -23,11 +23,11 @@
#include "CGVTables.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include <clang/AST/Mangle.h>
-#include <clang/AST/Type.h>
-#include <llvm/Intrinsics.h>
-#include <llvm/Target/TargetData.h>
-#include <llvm/Value.h>
+#include "clang/AST/Mangle.h"
+#include "clang/AST/Type.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/DataLayout.h"
+#include "llvm/Value.h"
using namespace clang;
using namespace CodeGen;
@@ -92,6 +92,10 @@ public:
llvm::Value *Addr,
const MemberPointerType *MPT);
+ llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type);
+
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType T,
CanQualType &ResTy,
@@ -109,6 +113,7 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
+ StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
CharUnits getArrayCookieSizeImpl(QualType elementType);
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
@@ -299,7 +304,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
CGBuilderTy &Builder = CGF.Builder;
- unsigned AS = cast<llvm::PointerType>(Base->getType())->getAddressSpace();
+ unsigned AS = Base->getType()->getPointerAddressSpace();
// Cast to char*.
Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
@@ -677,6 +682,25 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
return MPT->getPointeeType()->isFunctionType();
}
+/// The Itanium ABI always places an offset to the complete object
+/// at entry -2 in the vtable.
+llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type) {
+ // Grab the vtable pointer as an intptr_t*.
+ llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo());
+
+ // Track back to entry -2 and pull out the offset there.
+ llvm::Value *offsetPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr");
+ llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr);
+ offset->setAlignment(CGF.PointerAlignInBytes);
+
+ // Apply the offset.
+ ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
+ return CGF.Builder.CreateInBoundsGEP(ptr, offset);
+}
+
/// The generic ABI passes 'this', plus a VTT if it's initializing a
/// base subobject.
void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
@@ -810,7 +834,7 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
QualType ElementType) {
assert(requiresArrayCookie(expr));
- unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+ unsigned AS = NewPtr->getType()->getPointerAddressSpace();
ASTContext &Ctx = getContext();
QualType SizeTy = Ctx.getSizeType();
@@ -852,7 +876,7 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
CGF.Builder.CreateConstInBoundsGEP1_64(numElementsPtr,
numElementsOffset.getQuantity());
- unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+ unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
@@ -878,7 +902,7 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
// NewPtr is a char*.
- unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+ unsigned AS = NewPtr->getType()->getPointerAddressSpace();
ASTContext &Ctx = getContext();
CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
@@ -913,7 +937,7 @@ llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *numElementsPtr
= CGF.Builder.CreateConstInBoundsGEP1_64(allocPtr, CGF.SizeSizeInBytes);
- unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+ unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
@@ -927,9 +951,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
GuardPtrTy, /*isVarArg=*/false);
-
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire",
- llvm::Attribute::NoUnwind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NoUnwind));
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
@@ -937,9 +961,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
// void __cxa_guard_release(__guard *guard_object);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
-
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release",
- llvm::Attribute::NoUnwind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NoUnwind));
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
@@ -947,9 +971,9 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
// void __cxa_guard_abort(__guard *guard_object);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
-
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort",
- llvm::Attribute::NoUnwind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NoUnwind));
}
namespace {
@@ -1149,7 +1173,7 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
// In Apple kexts, we want to add a global destructor entry.
// FIXME: shouldn't this be guarded by some variable?
- if (CGM.getContext().getLangOpts().AppleKext) {
+ if (CGM.getLangOpts().AppleKext) {
// Generate a global destructor entry.
return CGM.AddCXXDtorEntry(dtor, addr);
}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 6a2925bbd953..8d205c3d0f5d 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -29,14 +29,18 @@ public:
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
StringRef GetPureVirtualCallName() { return "_purecall"; }
+ // No known support for deleted functions in MSVC yet, so this choice is
+ // arbitrary.
+ StringRef GetDeletedVirtualCallName() { return "_purecall"; }
+
+ llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type);
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
- // TODO: 'for base' flag
- }
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
CXXDtorType Type,
@@ -48,15 +52,9 @@ public:
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
- FunctionArgList &Params) {
- BuildThisParam(CGF, Params);
- // TODO: 'for base' flag
- }
+ FunctionArgList &Params);
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
- EmitThisParam(CGF);
- // TODO: 'for base' flag
- }
+ void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
@@ -99,10 +97,49 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
CharUnits cookieSize);
+ static bool needThisReturn(GlobalDecl GD);
};
}
+llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type) {
+ // FIXME: implement
+ return ptr;
+}
+
+bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
+ const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
+ return isa<CXXConstructorDecl>(MD);
+}
+
+void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) {
+ // 'this' is already in place
+ // TODO: 'for base' flag
+ // Ctor returns this ptr
+ ResTy = ArgTys[0];
+}
+
+void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
+ QualType &ResTy,
+ FunctionArgList &Params) {
+ BuildThisParam(CGF, Params);
+ if (needThisReturn(CGF.CurGD)) {
+ ResTy = Params[0]->getType();
+ }
+}
+
+void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
+ EmitThisParam(CGF);
+ if (needThisReturn(CGF.CurGD)) {
+ CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
+ }
+}
+
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
QualType elementType) {
// Microsoft seems to completely ignore the possibility of a
@@ -127,7 +164,7 @@ CharUnits MicrosoftCXXABI::getArrayCookieSizeImpl(QualType type) {
llvm::Value *MicrosoftCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
CharUnits cookieSize) {
- unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+ unsigned AS = allocPtr->getType()->getPointerAddressSpace();
llvm::Value *numElementsPtr =
CGF.Builder.CreateBitCast(allocPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
@@ -147,7 +184,7 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *cookiePtr = newPtr;
// Write the number of elements into the appropriate slot.
- unsigned AS = cast<llvm::PointerType>(newPtr->getType())->getAddressSpace();
+ unsigned AS = newPtr->getType()->getPointerAddressSpace();
llvm::Value *numElementsPtr
= CGF.Builder.CreateBitCast(cookiePtr, CGF.SizeTy->getPointerTo(AS));
CGF.Builder.CreateStore(numElements, numElementsPtr);
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index ea2389e66b5a..012555962f82 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -21,14 +21,14 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/ADT/OwningPtr.h"
using namespace clang;
namespace {
class CodeGeneratorImpl : public CodeGenerator {
DiagnosticsEngine &Diags;
- OwningPtr<const llvm::TargetData> TD;
+ OwningPtr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
protected:
@@ -54,7 +54,7 @@ namespace {
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
- TD.reset(new llvm::TargetData(Ctx->getTargetInfo().getTargetDescription()));
+ TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
*M, *TD, Diags));
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 9c23ed9871da..ffff0d0a1bc4 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Type.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -51,8 +51,8 @@ llvm::LLVMContext &ABIInfo::getVMContext() const {
return CGT.getLLVMContext();
}
-const llvm::TargetData &ABIInfo::getTargetData() const {
- return CGT.getTargetData();
+const llvm::DataLayout &ABIInfo::getDataLayout() const {
+ return CGT.getDataLayout();
}
@@ -389,6 +389,90 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
+//===----------------------------------------------------------------------===//
+// le32/PNaCl bitcode ABI Implementation
+//===----------------------------------------------------------------------===//
+
+class PNaClABIInfo : public ABIInfo {
+ public:
+ PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {}
+};
+
+void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+
+ unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0;
+
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, FreeRegs);
+ }
+
+llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty,
+ unsigned &FreeRegs) const {
+ if (isAggregateTypeForABI(Ty)) {
+ // Records with non trivial destructors/constructors should not be passed
+ // by value.
+ FreeRegs = 0;
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ 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) {
+ FreeRegs = 0;
+ return BaseInfo;
+ }
+ FreeRegs -= SizeInRegs;
+ return BaseInfo.isDirect() ?
+ ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) :
+ ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType());
+}
+
+ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy))
+ return ABIArgInfo::getIndirect(0);
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ return (RetTy->isPromotableIntegerType() ?
+ 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) {
@@ -435,7 +519,8 @@ class X86_32ABIInfo : public ABIInfo {
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty, bool ByVal = true) const;
+ ABIArgInfo getIndirectResult(QualType Ty, bool ByVal,
+ unsigned &FreeRegs) const;
/// \brief Return the alignment to use for the given type on the stack.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
@@ -443,9 +528,10 @@ class X86_32ABIInfo : public ABIInfo {
Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy,
unsigned callingConvention) const;
- ABIArgInfo classifyArgumentTypeWithReg(QualType RetTy,
- unsigned &FreeRegs) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs,
+ bool IsFastCall) const;
+ bool shouldUseInReg(QualType Ty, unsigned &FreeRegs,
+ bool IsFastCall, bool &NeedsPadding) const;
public:
@@ -682,9 +768,15 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
return MinABIStackAlignInBytes;
}
-ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
- if (!ByVal)
+ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
+ unsigned &FreeRegs) const {
+ if (!ByVal) {
+ if (FreeRegs) {
+ --FreeRegs; // Non byval indirects just use one pointer.
+ return ABIArgInfo::getIndirectInReg(0, false);
+ }
return ABIArgInfo::getIndirect(0, false);
+ }
// Compute the byval alignment.
unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
@@ -714,45 +806,51 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
return Integer;
}
-ABIArgInfo
-X86_32ABIInfo::classifyArgumentTypeWithReg(QualType Ty,
- unsigned &FreeRegs) const {
- // Common case first.
- if (FreeRegs == 0)
- return classifyArgumentType(Ty);
-
+bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
+ bool IsFastCall, bool &NeedsPadding) const {
+ NeedsPadding = false;
Class C = classify(Ty);
if (C == Float)
- return classifyArgumentType(Ty);
+ return false;
+
+ unsigned Size = getContext().getTypeSize(Ty);
+ unsigned SizeInRegs = (Size + 31) / 32;
- unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
if (SizeInRegs == 0)
- return classifyArgumentType(Ty);
+ return false;
if (SizeInRegs > FreeRegs) {
FreeRegs = 0;
- return classifyArgumentType(Ty);
+ return false;
}
- assert(SizeInRegs >= 1 && SizeInRegs <= 3);
+
FreeRegs -= SizeInRegs;
- // If it is a simple scalar, keep the type so that we produce a cleaner IR.
- ABIArgInfo Foo = classifyArgumentType(Ty);
- if (Foo.isDirect() && !Foo.getDirectOffset() && !Foo.getPaddingType())
- return ABIArgInfo::getDirectInReg(Foo.getCoerceToType());
- if (Foo.isExtend())
- return ABIArgInfo::getExtendInReg(Foo.getCoerceToType());
+ if (IsFastCall) {
+ if (Size > 32)
+ return false;
+
+ if (Ty->isIntegralOrEnumerationType())
+ return true;
+
+ if (Ty->isPointerType())
+ return true;
+
+ if (Ty->isReferenceType())
+ return true;
+
+ if (FreeRegs)
+ NeedsPadding = true;
- llvm::LLVMContext &LLVMContext = getVMContext();
- llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext);
- SmallVector<llvm::Type*, 3> Elements;
- for (unsigned I = 0; I < SizeInRegs; ++I)
- Elements.push_back(Int32);
- llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
- return ABIArgInfo::getDirectInReg(Result);
+ return false;
+ }
+
+ return true;
}
-ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
+ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
+ unsigned &FreeRegs,
+ bool IsFastCall) const {
// FIXME: Set alignment on indirect arguments.
if (isAggregateTypeForABI(Ty)) {
// Structures with flexible arrays are always indirect.
@@ -760,25 +858,38 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
if (hasNonTrivialDestructorOrCopyConstructor(RT))
- return getIndirectResult(Ty, /*ByVal=*/false);
+ return getIndirectResult(Ty, false, FreeRegs);
if (RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectResult(Ty);
+ return getIndirectResult(Ty, true, FreeRegs);
}
// Ignore empty structs/unions.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
+ llvm::LLVMContext &LLVMContext = getVMContext();
+ llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
+ bool NeedsPadding;
+ if (shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding)) {
+ unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ SmallVector<llvm::Type*, 3> Elements;
+ for (unsigned I = 0; I < SizeInRegs; ++I)
+ Elements.push_back(Int32);
+ llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
+ return ABIArgInfo::getDirectInReg(Result);
+ }
+ llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : 0;
+
// Expand small (<= 128-bit) record types when we know that the stack layout
// of those arguments will match the struct. This is important because the
// LLVM backend isn't smart enough to remove byval, which inhibits many
// optimizations.
if (getContext().getTypeSize(Ty) <= 4*32 &&
canExpandIndirectArgument(Ty, getContext()))
- return ABIArgInfo::getExpand();
+ return ABIArgInfo::getExpandWithPadding(IsFastCall, PaddingType);
- return getIndirectResult(Ty);
+ return getIndirectResult(Ty, true, FreeRegs);
}
if (const VectorType *VT = Ty->getAs<VectorType>()) {
@@ -809,16 +920,32 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ bool NeedsPadding;
+ bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding);
+
+ if (Ty->isPromotableIntegerType()) {
+ if (InReg)
+ return ABIArgInfo::getExtendInReg();
+ return ABIArgInfo::getExtend();
+ }
+ if (InReg)
+ return ABIArgInfo::getDirectInReg();
+ return ABIArgInfo::getDirect();
}
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
FI.getCallingConvention());
- unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() :
- DefaultNumRegisterParameters;
+ unsigned CC = FI.getCallingConvention();
+ bool IsFastCall = CC == llvm::CallingConv::X86_FastCall;
+ unsigned FreeRegs;
+ if (IsFastCall)
+ FreeRegs = 2;
+ else if (FI.getHasRegParm())
+ FreeRegs = FI.getRegParm();
+ else
+ FreeRegs = DefaultNumRegisterParameters;
// If the return value is indirect, then the hidden argument is consuming one
// integer register.
@@ -832,7 +959,7 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentTypeWithReg(it->type, FreeRegs);
+ it->info = classifyArgumentType(it->type, FreeRegs, IsFastCall);
}
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -884,7 +1011,10 @@ void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
llvm::Function *Fn = cast<llvm::Function>(GV);
// Now add the 'alignstack' attribute with a value of 16.
- Fn->addFnAttr(llvm::Attribute::constructStackAlignmentFromInt(16));
+ llvm::AttrBuilder B;
+ B.addStackAlignmentAttr(16);
+ Fn->addAttribute(llvm::AttrListPtr::FunctionIndex,
+ llvm::Attributes::get(CGM.getLLVMContext(), B));
}
}
}
@@ -1030,10 +1160,15 @@ class X86_64ABIInfo : public ABIInfo {
}
bool HasAVX;
+ // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
+ // 64-bit hardware.
+ bool Has64BitPointers;
public:
X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) :
- ABIInfo(CGT), HasAVX(hasavx) {}
+ ABIInfo(CGT), HasAVX(hasavx),
+ Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) {
+ }
bool isPassedUsingAVXType(QualType type) const {
unsigned neededInt, neededSSE;
@@ -1070,7 +1205,7 @@ public:
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
- : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
+ : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
const X86_64ABIInfo &getABIInfo() const {
return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
@@ -1243,7 +1378,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Hi = Integer;
} else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
Current = Integer;
- } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
+ } else if ((k == BuiltinType::Float || k == BuiltinType::Double) ||
+ (k == BuiltinType::LongDouble &&
+ getContext().getTargetInfo().getTriple().getOS() ==
+ llvm::Triple::NativeClient)) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
Lo = X87;
@@ -1266,7 +1404,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
}
if (Ty->isMemberPointerType()) {
- if (Ty->isMemberFunctionPointerType())
+ if (Ty->isMemberFunctionPointerType() && Has64BitPointers)
Lo = Hi = Integer;
else
Current = Integer;
@@ -1329,7 +1467,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Lo = Hi = Integer;
} else if (ET == getContext().FloatTy)
Current = SSE;
- else if (ET == getContext().DoubleTy)
+ else if (ET == getContext().DoubleTy ||
+ (ET == getContext().LongDoubleTy &&
+ getContext().getTargetInfo().getTriple().getOS() ==
+ llvm::Triple::NativeClient))
Lo = Hi = SSE;
else if (ET == getContext().LongDoubleTy)
Current = ComplexX87;
@@ -1708,7 +1849,7 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
/// float at offset 4. It is conservatively correct for this routine to return
/// false.
static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset,
- const llvm::TargetData &TD) {
+ const llvm::DataLayout &TD) {
// Base case if we find a float.
if (IROffset == 0 && IRType->isFloatTy())
return true;
@@ -1748,8 +1889,8 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
// We want to pass as <2 x float> if the LLVM IR type contains a float at
// offset+0 and offset+4. Walk the LLVM IR type to find out if this is the
// case.
- if (ContainsFloatAtOffset(IRType, IROffset, getTargetData()) &&
- ContainsFloatAtOffset(IRType, IROffset+4, getTargetData()))
+ if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) &&
+ ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout()))
return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2);
return llvm::Type::getDoubleTy(getVMContext());
@@ -1777,7 +1918,8 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
// returning an 8-byte unit starting with it. See if we can safely use it.
if (IROffset == 0) {
// Pointers and int64's always fill the 8-byte unit.
- if (isa<llvm::PointerType>(IRType) || IRType->isIntegerTy(64))
+ if ((isa<llvm::PointerType>(IRType) && Has64BitPointers) ||
+ IRType->isIntegerTy(64))
return IRType;
// If we have a 1/2/4-byte integer, we can use it only if the rest of the
@@ -1787,8 +1929,10 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
// have to do this analysis on the source type because we can't depend on
// unions being lowered a specific way etc.
if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) ||
- IRType->isIntegerTy(32)) {
- unsigned BitWidth = cast<llvm::IntegerType>(IRType)->getBitWidth();
+ IRType->isIntegerTy(32) ||
+ (isa<llvm::PointerType>(IRType) && !Has64BitPointers)) {
+ unsigned BitWidth = isa<llvm::PointerType>(IRType) ? 32 :
+ cast<llvm::IntegerType>(IRType)->getBitWidth();
if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth,
SourceOffset*8+64, getContext()))
@@ -1798,7 +1942,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
// If this is a struct, recurse into the field at the specified offset.
- const llvm::StructLayout *SL = getTargetData().getStructLayout(STy);
+ const llvm::StructLayout *SL = getDataLayout().getStructLayout(STy);
if (IROffset < SL->getSizeInBytes()) {
unsigned FieldIdx = SL->getElementContainingOffset(IROffset);
IROffset -= SL->getElementOffset(FieldIdx);
@@ -1810,7 +1954,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
llvm::Type *EltTy = ATy->getElementType();
- unsigned EltSize = getTargetData().getTypeAllocSize(EltTy);
+ unsigned EltSize = getDataLayout().getTypeAllocSize(EltTy);
unsigned EltOffset = IROffset/EltSize*EltSize;
return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy,
SourceOffset);
@@ -1837,14 +1981,14 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
/// return {i32*, float}.
static llvm::Type *
GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
- const llvm::TargetData &TD) {
+ const llvm::DataLayout &TD) {
// In order to correctly satisfy the ABI, we need to the high part to start
// at offset 8. If the high and low parts we inferred are both 4-byte types
// (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have
// the second element at offset 8. Check for this:
unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo);
unsigned HiAlign = TD.getABITypeAlignment(Hi);
- unsigned HiStart = llvm::TargetData::RoundUpAlignment(LoSize, HiAlign);
+ unsigned HiStart = llvm::DataLayout::RoundUpAlignment(LoSize, HiAlign);
assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
// To handle this, we have to increase the size of the low part so that the
@@ -1996,7 +2140,7 @@ classifyReturnType(QualType RetTy) const {
// known to pass in the high eightbyte of the result. We do this by forming a
// first class struct aggregate with the high and low part: {low, high}
if (HighPart)
- ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData());
+ ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout());
return ABIArgInfo::getDirect(ResType);
}
@@ -2122,7 +2266,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
// known to pass in the high eightbyte of the result. We do this by forming a
// first class struct aggregate with the high and low part: {low, high}
if (HighPart)
- ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData());
+ ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout());
return ABIArgInfo::getDirect(ResType);
}
@@ -2435,6 +2579,43 @@ llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return AddrTyped;
}
+namespace {
+
+class NaClX86_64ABIInfo : public ABIInfo {
+ public:
+ NaClX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, HasAVX) {}
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+ private:
+ PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
+ X86_64ABIInfo NInfo; // Used for everything else.
+};
+
+class NaClX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ NaClX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : TargetCodeGenInfo(new NaClX86_64ABIInfo(CGT, HasAVX)) {}
+};
+
+}
+
+void NaClX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (FI.getASTCallingConvention() == CC_PnaclCall)
+ PInfo.computeInfo(FI);
+ else
+ NInfo.computeInfo(FI);
+}
+
+llvm::Value *NaClX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // Always use the native convention; calling pnacl-style varargs functions
+ // is unuspported.
+ return NInfo.EmitVAArg(VAListAddr, Ty, CGF);
+}
+
+
// PowerPC-32
namespace {
@@ -2497,6 +2678,62 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// PowerPC-64
namespace {
+/// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information.
+class PPC64_SVR4_ABIInfo : public DefaultABIInfo {
+
+public:
+ PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+
+ bool isPromotableTypeForABI(QualType Ty) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType Ty) const;
+
+ // TODO: We can add more logic to computeInfo to improve performance.
+ // Example: For aggregate arguments that fit in a register, we could
+ // use getDirectInReg (as is done below for structs containing a single
+ // floating-point value) to avoid pushing them to memory on function
+ // entry. This would require changing the logic in PPCISelLowering
+ // when lowering the parameters in the caller and args in the callee.
+ virtual void computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ // We rely on the default argument classification for the most part.
+ // One exception: An aggregate containing a single floating-point
+ // item must be passed in a register if one is available.
+ const Type *T = isSingleElementStruct(it->type, getContext());
+ if (T) {
+ const BuiltinType *BT = T->getAs<BuiltinType>();
+ if (BT && BT->isFloatingPoint()) {
+ QualType QT(T, 0);
+ it->info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
+ continue;
+ }
+ }
+ it->info = classifyArgumentType(it->type);
+ }
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT)) {}
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ // This is recovered from gcc output.
+ return 1; // r1 is the dedicated stack pointer
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const;
+};
+
class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
public:
PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {}
@@ -2512,9 +2749,94 @@ public:
}
+// Return true if the ABI requires Ty to be passed sign- or zero-
+// extended to 64 bits.
bool
-PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
+PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ // Promotable integer types are required to be promoted by the ABI.
+ if (Ty->isPromotableIntegerType())
+ return true;
+
+ // In addition to the usual promotable integer types, we also need to
+ // extend all 32-bit types, since the ABI requires promotion to 64 bits.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+ABIArgInfo
+PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty)) {
+ // Records with non trivial destructors/constructors should not be passed
+ // by value.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ return (isPromotableTypeForABI(Ty) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo
+PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy))
+ return ABIArgInfo::getIndirect(0);
+
+ return (isPromotableTypeForABI(RetTy) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+// Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine.
+llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) const {
+ llvm::Type *BP = CGF.Int8PtrTy;
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+
+ // Update the va_list pointer.
+ unsigned SizeInBytes = CGF.getContext().getTypeSize(Ty) / 8;
+ 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 the argument is smaller than 8 bytes, it is right-adjusted in
+ // its doubleword slot. Adjust the pointer to pick it up from the
+ // correct offset.
+ if (SizeInBytes < 8) {
+ llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
+ AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt64(8 - SizeInBytes));
+ Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
+ }
+
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ return Builder.CreateBitCast(Addr, PTy);
+}
+
+static bool
+PPC64_initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) {
// This is calculated from the LLVM and GCC tables and verified
// against gcc output. AFAIK all ABIs use the same encoding.
@@ -2553,6 +2875,21 @@ PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
return false;
}
+bool
+PPC64_SVR4_TargetCodeGenInfo::initDwarfEHRegSizeTable(
+ CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+
+ return PPC64_initDwarfEHRegSizeTable(CGF, Address);
+}
+
+bool
+PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+
+ return PPC64_initDwarfEHRegSizeTable(CGF, Address);
+}
+
//===----------------------------------------------------------------------===//
// ARM ABI Implementation
//===----------------------------------------------------------------------===//
@@ -2576,14 +2913,18 @@ public:
bool isEABI() const {
StringRef Env =
getContext().getTargetInfo().getTriple().getEnvironmentName();
- return (Env == "gnueabi" || Env == "eabi" || Env == "androideabi");
+ return (Env == "gnueabi" || Env == "eabi" ||
+ Env == "android" || Env == "androideabi");
}
private:
ABIKind getABIKind() const { return Kind; }
ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs,
+ unsigned &AllocatedVFP,
+ bool &IsHA) const;
+ bool isIllegalVectorType(QualType Ty) const;
virtual void computeInfo(CGFunctionInfo &FI) const;
@@ -2626,10 +2967,33 @@ public:
}
void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ // To correctly handle Homogeneous Aggregate, we need to keep track of the
+ // VFP registers allocated so far.
+ // C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive
+ // VFP registers of the appropriate type unallocated then the argument is
+ // allocated to the lowest-numbered sequence of such registers.
+ // C.2.vfp If the argument is a VFP CPRC then any VFP registers that are
+ // unallocated are marked as unavailable.
+ unsigned AllocatedVFP = 0;
+ int VFPRegs[16] = { 0 };
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ it != ie; ++it) {
+ unsigned PreAllocation = AllocatedVFP;
+ bool IsHA = false;
+ // 6.1.2.3 There is one VFP co-processor register class using registers
+ // s0-s15 (d0-d7) for passing arguments.
+ const unsigned NumVFPs = 16;
+ it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA);
+ // If we do not have enough VFP registers for the HA, any VFP registers
+ // that are unallocated are marked as unavailable. To achieve this, we add
+ // padding of (NumVFPs - PreAllocation) floats.
+ if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
+ llvm::Type *PaddingTy = llvm::ArrayType::get(
+ llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
+ it->info = ABIArgInfo::getExpandWithPadding(false, PaddingTy);
+ }
+ }
// Always honor user-specified calling convention.
if (FI.getCallingConvention() != llvm::CallingConv::C)
@@ -2637,7 +3001,9 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Calling convention as default by an ABI.
llvm::CallingConv::ID DefaultCC;
- if (isEABI())
+ if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf")
+ DefaultCC = llvm::CallingConv::ARM_AAPCS_VFP;
+ else if (isEABI())
DefaultCC = llvm::CallingConv::ARM_AAPCS;
else
DefaultCC = llvm::CallingConv::ARM_APCS;
@@ -2729,7 +3095,88 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
return (Members > 0 && Members <= 4);
}
-ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
+/// markAllocatedVFPs - update VFPRegs according to the alignment and
+/// number of VFP registers (unit is S register) requested.
+static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP,
+ unsigned Alignment,
+ unsigned NumRequired) {
+ // Early Exit.
+ if (AllocatedVFP >= 16)
+ return;
+ // C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive
+ // VFP registers of the appropriate type unallocated then the argument is
+ // allocated to the lowest-numbered sequence of such registers.
+ for (unsigned I = 0; I < 16; I += Alignment) {
+ bool FoundSlot = true;
+ for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++)
+ if (J >= 16 || VFPRegs[J]) {
+ FoundSlot = false;
+ break;
+ }
+ if (FoundSlot) {
+ for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++)
+ VFPRegs[J] = 1;
+ AllocatedVFP += NumRequired;
+ return;
+ }
+ }
+ // C.2.vfp If the argument is a VFP CPRC then any VFP registers that are
+ // unallocated are marked as unavailable.
+ for (unsigned I = 0; I < 16; I++)
+ VFPRegs[I] = 1;
+ AllocatedVFP = 17; // We do not have enough VFP registers.
+}
+
+ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
+ unsigned &AllocatedVFP,
+ bool &IsHA) const {
+ // We update number of allocated VFPs according to
+ // 6.1.2.1 The following argument types are VFP CPRCs:
+ // A single-precision floating-point type (including promoted
+ // half-precision types); A double-precision floating-point type;
+ // A 64-bit or 128-bit containerized vector type; Homogeneous Aggregate
+ // with a Base Type of a single- or double-precision floating-point type,
+ // 64-bit containerized vectors or 128-bit containerized vectors with one
+ // to four Elements.
+
+ // Handle illegal vector types here.
+ if (isIllegalVectorType(Ty)) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size <= 32) {
+ llvm::Type *ResType =
+ llvm::Type::getInt32Ty(getVMContext());
+ return ABIArgInfo::getDirect(ResType);
+ }
+ if (Size == 64) {
+ llvm::Type *ResType = llvm::VectorType::get(
+ llvm::Type::getInt32Ty(getVMContext()), 2);
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2);
+ return ABIArgInfo::getDirect(ResType);
+ }
+ if (Size == 128) {
+ llvm::Type *ResType = llvm::VectorType::get(
+ llvm::Type::getInt32Ty(getVMContext()), 4);
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 4, 4);
+ return ABIArgInfo::getDirect(ResType);
+ }
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
+ // Update VFPRegs for legal vector types.
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ uint64_t Size = getContext().getTypeSize(VT);
+ // Size of a legal vector should be power of 2 and above 64.
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, Size >= 128 ? 4 : 2, Size / 32);
+ }
+ // Update VFPRegs for floating point types.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::Half ||
+ BT->getKind() == BuiltinType::Float)
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, 1);
+ if (BT->getKind() == BuiltinType::Double ||
+ BT->getKind() == BuiltinType::LongDouble)
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2);
+ }
+
if (!isAggregateTypeForABI(Ty)) {
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
@@ -2749,18 +3196,42 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
- // Homogeneous Aggregates need to be expanded.
+ // Homogeneous Aggregates need to be expanded when we can fit the aggregate
+ // into VFP registers.
const Type *Base = 0;
- if (isHomogeneousAggregate(Ty, Base, getContext())) {
+ uint64_t Members = 0;
+ if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
assert(Base && "Base class should be set for homogeneous aggregate");
+ // Base can be a floating-point or a vector.
+ if (Base->isVectorType()) {
+ // ElementSize is in number of floats.
+ unsigned ElementSize = getContext().getTypeSize(Base) == 64 ? 2 : 4;
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, ElementSize,
+ Members * ElementSize);
+ } else if (Base->isSpecificBuiltinType(BuiltinType::Float))
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, Members);
+ else {
+ assert(Base->isSpecificBuiltinType(BuiltinType::Double) ||
+ Base->isSpecificBuiltinType(BuiltinType::LongDouble));
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, Members * 2);
+ }
+ IsHA = true;
return ABIArgInfo::getExpand();
}
}
// Support byval for ARM.
- if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64) ||
- getContext().getTypeAlign(Ty) > 64) {
- return ABIArgInfo::getIndirect(0, /*ByVal=*/true);
+ // The ABI alignment for APCS is 4-byte and for AAPCS at least 4-byte and at
+ // most 8-byte. We realign the indirect argument if type alignment is bigger
+ // than ABI alignment.
+ uint64_t ABIAlign = 4;
+ uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8;
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
+ getABIKind() == ARMABIInfo::AAPCS)
+ ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
+ if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/true,
+ /*Realign=*/TyAlign > ABIAlign);
}
// Otherwise, pass by coercing to a structure of the appropriate size.
@@ -2946,6 +3417,21 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIndirect(0);
}
+/// isIllegalVector - check whether Ty is an illegal vector type.
+bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ // Check whether VT is legal.
+ unsigned NumElements = VT->getNumElements();
+ uint64_t Size = getContext().getTypeSize(VT);
+ // NumElements should be power of 2.
+ if ((NumElements & (NumElements - 1)) != 0)
+ return true;
+ // Size should be greater than 32 bits.
+ return Size <= 32;
+ }
+ return false;
+}
+
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
llvm::Type *BP = CGF.Int8PtrTy;
@@ -2954,30 +3440,104 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- // Handle address alignment for type alignment > 32 bits
+
+ uint64_t Size = CGF.getContext().getTypeSize(Ty) / 8;
uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
+ bool IsIndirect = false;
+
+ // The ABI alignment for 64-bit or 128-bit vectors is 8 for AAPCS and 4 for
+ // APCS. For AAPCS, the ABI alignment is at least 4-byte and at most 8-byte.
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
+ getABIKind() == ARMABIInfo::AAPCS)
+ TyAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
+ else
+ TyAlign = 4;
+ // Use indirect if size of the illegal vector is bigger than 16 bytes.
+ if (isIllegalVectorType(Ty) && Size > 16) {
+ IsIndirect = true;
+ Size = 4;
+ TyAlign = 4;
+ }
+
+ // Handle address alignment for ABI alignment > 4 bytes.
if (TyAlign > 4) {
assert((TyAlign & (TyAlign - 1)) == 0 &&
"Alignment is not power of 2!");
llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1));
AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1)));
- Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
+ Addr = Builder.CreateIntToPtr(AddrAsInt, BP, "ap.align");
}
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
- llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
uint64_t Offset =
- llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::RoundUpToAlignment(Size, 4);
llvm::Value *NextAddr =
Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+ if (IsIndirect)
+ Addr = Builder.CreateLoad(Builder.CreateBitCast(Addr, BPP));
+ else if (TyAlign < CGF.getContext().getTypeAlign(Ty) / 8) {
+ // We can't directly cast ap.cur to pointer to a vector type, since ap.cur
+ // may not be correctly aligned for the vector type. We create an aligned
+ // temporary space and copy the content over from ap.cur to the temporary
+ // space. This is necessary if the natural alignment of the type is greater
+ // than the ABI alignment.
+ llvm::Type *I8PtrTy = Builder.getInt8PtrTy();
+ CharUnits CharSize = getContext().getTypeSizeInChars(Ty);
+ llvm::Value *AlignedTemp = CGF.CreateTempAlloca(CGF.ConvertType(Ty),
+ "var.align");
+ llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy);
+ llvm::Value *Src = Builder.CreateBitCast(Addr, I8PtrTy);
+ Builder.CreateMemCpy(Dst, Src,
+ llvm::ConstantInt::get(CGF.IntPtrTy, CharSize.getQuantity()),
+ TyAlign, false);
+ Addr = AlignedTemp; //The content is in aligned location.
+ }
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
return AddrTyped;
}
+namespace {
+
+class NaClARMABIInfo : public ABIInfo {
+ public:
+ NaClARMABIInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
+ : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, Kind) {}
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+ private:
+ PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
+ ARMABIInfo NInfo; // Used for everything else.
+};
+
+class NaClARMTargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ NaClARMTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
+ : TargetCodeGenInfo(new NaClARMABIInfo(CGT, Kind)) {}
+};
+
+}
+
+void NaClARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (FI.getASTCallingConvention() == CC_PnaclCall)
+ PInfo.computeInfo(FI);
+ else
+ static_cast<const ABIInfo&>(NInfo).computeInfo(FI);
+}
+
+llvm::Value *NaClARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // Always use the native convention; calling pnacl-style varargs functions
+ // is unsupported.
+ return static_cast<const ABIInfo&>(NInfo).EmitVAArg(VAListAddr, Ty, CGF);
+}
+
//===----------------------------------------------------------------------===//
// NVPTX ABI Implementation
//===----------------------------------------------------------------------===//
@@ -3072,7 +3632,7 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// OpenCL __kernel functions get a kernel calling convention
F->setCallingConv(llvm::CallingConv::PTX_Kernel);
// And kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
}
}
@@ -3188,7 +3748,7 @@ void MBlazeTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(CC);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
}
// Step 3: Emit _interrupt_handler alias.
@@ -3226,7 +3786,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(llvm::CallingConv::MSP430_INTR);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
// Step 3: Emit ISR vector alias.
unsigned Num = attr->getNumber() + 0xffe0;
@@ -3583,7 +4143,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::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
@@ -3767,6 +4327,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
default:
return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types));
+ case llvm::Triple::le32:
+ return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types));
case llvm::Triple::mips:
case llvm::Triple::mipsel:
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true));
@@ -3779,19 +4341,29 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::thumb:
{
ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
-
if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0)
Kind = ARMABIInfo::APCS;
- else if (CodeGenOpts.FloatABI == "hard")
+ else if (CodeGenOpts.FloatABI == "hard" ||
+ (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment()==llvm::Triple::GNUEABIHF))
Kind = ARMABIInfo::AAPCS_VFP;
- return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind));
+ switch (Triple.getOS()) {
+ case llvm::Triple::NativeClient:
+ return *(TheTargetCodeGenInfo =
+ new NaClARMTargetCodeGenInfo(Types, Kind));
+ default:
+ return *(TheTargetCodeGenInfo =
+ new ARMTargetCodeGenInfo(Types, Kind));
+ }
}
case llvm::Triple::ppc:
return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
case llvm::Triple::ppc64:
- return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
+ if (Triple.isOSBinFormatELF())
+ return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types));
+ else
+ return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
case llvm::Triple::nvptx:
case llvm::Triple::nvptx64:
@@ -3848,6 +4420,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::MinGW32:
case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
+ case llvm::Triple::NativeClient:
+ return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
default:
return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
HasAVX));
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index c0a2a506a6ba..93d70a9fefed 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Arg.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
#include "llvm/ADT/SmallString.h"
@@ -15,22 +16,23 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
+using clang::StringRef;
-Arg::Arg(const Option *_Opt, unsigned _Index, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg)
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
}
-Arg::Arg(const Option *_Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
}
-Arg::Arg(const Option *_Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const char *Value1, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
Values.push_back(Value1);
@@ -47,7 +49,7 @@ void Arg::dump() const {
llvm::errs() << "<";
llvm::errs() << " Opt:";
- Opt->dump();
+ Opt.dump();
llvm::errs() << " Index:" << Index;
@@ -83,39 +85,39 @@ void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const {
}
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, i));
+ Output.push_back(getValue(i));
}
void Arg::render(const ArgList &Args, ArgStringList &Output) const {
switch (getOption().getRenderStyle()) {
case Option::RenderValuesStyle:
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, i));
+ Output.push_back(getValue(i));
break;
case Option::RenderCommaJoinedStyle: {
SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
- OS << getOption().getName();
+ OS << getSpelling();
for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
if (i) OS << ',';
- OS << getValue(Args, i);
+ OS << getValue(i);
}
Output.push_back(Args.MakeArgString(OS.str()));
break;
}
-
+
case Option::RenderJoinedStyle:
Output.push_back(Args.GetOrMakeJoinedArgString(
- getIndex(), getOption().getName(), getValue(Args, 0)));
+ getIndex(), getSpelling(), getValue(0)));
for (unsigned i = 1, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, i));
+ Output.push_back(getValue(i));
break;
case Option::RenderSeparateStyle:
- Output.push_back(getOption().getName().data());
+ Output.push_back(Args.MakeArgString(getSpelling()));
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, i));
+ Output.push_back(getValue(i));
break;
}
}
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 7fd439e63082..b3a43df98041 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -211,7 +211,7 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
StringRef ArgList::getLastArgValue(OptSpecifier Id,
StringRef Default) const {
if (Arg *A = getLastArg(Id))
- return A->getValue(*this);
+ return A->getValue();
return Default;
}
@@ -220,10 +220,10 @@ int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
int Res = Default;
if (Arg *A = getLastArg(Id)) {
- if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) {
+ if (StringRef(A->getValue()).getAsInteger(10, Res)) {
if (Diags)
Diags->Report(diag::err_drv_invalid_int_value)
- << A->getAsString(*this) << A->getValue(*this);
+ << A->getAsString(*this) << A->getValue();
}
}
@@ -258,7 +258,7 @@ void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
ie = filtered_end(); it != ie; ++it) {
(*it)->claim();
for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
- Output.push_back((*it)->getValue(*this, i));
+ Output.push_back((*it)->getValue(i));
}
}
@@ -271,10 +271,10 @@ void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
if (Joined) {
Output.push_back(MakeArgString(StringRef(Translation) +
- (*it)->getValue(*this, 0)));
+ (*it)->getValue(0)));
} else {
Output.push_back(Translation);
- Output.push_back((*it)->getValue(*this, 0));
+ Output.push_back((*it)->getValue(0));
}
}
}
@@ -362,33 +362,40 @@ const char *DerivedArgList::MakeArgString(StringRef Str) const {
return BaseArgs.MakeArgString(Str);
}
-Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const {
- Arg *A = new Arg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg);
+Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const {
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())),
+ BaseArgs.MakeIndex(Opt.getName()), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
-Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt,
+Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Value);
- Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg);
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())),
+ Index, BaseArgs.getArgString(Index), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
-Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
+Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Opt->getName(), Value);
- Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg);
+ unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value);
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())),
+ Index, BaseArgs.getArgString(Index + 1), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
-Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
+Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Opt->getName().str() + Value.str());
- Arg *A = new Arg(Opt, Index,
- BaseArgs.getArgString(Index) + Opt->getName().size(),
+ unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str());
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())), Index,
+ BaseArgs.getArgString(Index) + Opt.getName().size(),
BaseArg);
SynthesizedArgs.push_back(A);
return A;
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index ea80f5a20eae..4f89b73a46d3 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -15,11 +15,19 @@ using namespace clang::driver;
using namespace clang::driver::options;
using namespace clang::driver::cc1asoptions;
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR)
+#include "clang/Driver/CC1AsOptions.inc"
+#undef OPTION
+#undef PREFIX
+
static const OptTable::Info CC1AsInfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
- OPT_##GROUP, OPT_##ALIAS },
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+ FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/CC1AsOptions.inc"
};
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index c962fca0bf9a..124e50c32ea4 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -17,6 +17,7 @@
#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>
@@ -101,6 +102,105 @@ void Compilation::PrintJob(raw_ostream &OS, const Job &J,
}
}
+static bool skipArg(const char *Flag, bool &SkipNextArg) {
+ StringRef FlagRef(Flag);
+
+ // Assume we're going to see -Flag <Arg>.
+ SkipNextArg = true;
+
+ // These flags are all of the form -Flag <Arg> and are treated as two
+ // arguments. Therefore, we need to skip the flag and the next argument.
+ 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("-include", "-include-pch", "-internal-isystem", true)
+ .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
+ .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
+ .Cases("-resource-dir", "-serialize-diagnostic-file", true)
+ .Case("-dwarf-debug-flags", true)
+ .Default(false);
+
+ // Match found.
+ if (Res)
+ return Res;
+
+ // The remaining flags are treated as a single argument.
+ SkipNextArg = false;
+
+ // These flags are all of the form -Flag and have no second argument.
+ Res = llvm::StringSwitch<bool>(Flag)
+ .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
+ .Case("-MMD", true)
+ .Default(false);
+
+ // Match found.
+ if (Res)
+ return Res;
+
+ // These flags are treated as a single argument (e.g., -F<Dir>).
+ if (FlagRef.startswith("-F") || FlagRef.startswith("-I"))
+ return true;
+
+ return false;
+}
+
+static bool quoteNextArg(const char *flag) {
+ return llvm::StringSwitch<bool>(flag)
+ .Case("-D", true)
+ .Default(false);
+}
+
+void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const {
+ if (const Command *C = dyn_cast<Command>(&J)) {
+ OS << C->getExecutable();
+ unsigned QuoteNextArg = 0;
+ for (ArgStringList::const_iterator it = C->getArguments().begin(),
+ ie = C->getArguments().end(); it != ie; ++it) {
+
+ bool SkipNext;
+ if (skipArg(*it, SkipNext)) {
+ if (SkipNext) ++it;
+ continue;
+ }
+
+ if (!QuoteNextArg)
+ QuoteNextArg = quoteNextArg(*it) ? 2 : 0;
+
+ OS << ' ';
+
+ if (QuoteNextArg == 1)
+ OS << '"';
+
+ if (!std::strpbrk(*it, " \"\\$")) {
+ OS << *it;
+ } else {
+ // Quote the argument and escape shell special characters; this isn't
+ // really complete but is good enough.
+ OS << '"';
+ for (const char *s = *it; *s; ++s) {
+ if (*s == '"' || *s == '\\' || *s == '$')
+ OS << '\\';
+ OS << *s;
+ }
+ OS << '"';
+ }
+
+ if (QuoteNextArg) {
+ if (QuoteNextArg == 1)
+ OS << '"';
+ --QuoteNextArg;
+ }
+ }
+ OS << '\n';
+ } else {
+ const JobList *Jobs = cast<JobList>(&J);
+ for (JobList::const_iterator
+ it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
+ PrintDiagnosticJob(OS, **it);
+ }
+}
+
bool Compilation::CleanupFileList(const ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 87d533dd2953..68471ec04c6a 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -52,25 +52,13 @@ Driver::Driver(StringRef ClangExecutable,
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
DefaultImageName(DefaultImageName),
- DriverTitle("clang \"gcc-compatible\" driver"),
+ DriverTitle("clang LLVM compiler"),
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
CCLogDiagnosticsFilename(0), CCCIsCXX(false),
CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
- CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true),
- ForcedClangUse(false), CCCUsePCH(true), SuppressMissingInputWarning(false) {
- if (IsProduction) {
- // In a "production" build, only use clang on architectures we expect to
- // work.
- //
- // During development its more convenient to always have the driver use
- // clang, but we don't want users to be confused when things don't work, or
- // to file bugs for things we don't support.
- CCCClangArchs.insert(llvm::Triple::x86);
- CCCClangArchs.insert(llvm::Triple::x86_64);
- CCCClangArchs.insert(llvm::Triple::arm);
- }
+ CCCUsePCH(true), SuppressMissingInputWarning(false) {
Name = llvm::sys::path::stem(ClangExecutable);
Dir = llvm::sys::path::parent_path(ClangExecutable);
@@ -109,7 +97,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
it != ie; ++it) {
Arg *A = *it;
- if (A->getOption().isUnsupported()) {
+ if (A->getOption().hasFlag(options::Unsupported)) {
Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args);
continue;
}
@@ -186,9 +174,9 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Add the remaining values as Xlinker arguments.
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (StringRef(A->getValue(Args, i)) != "--no-demangle")
+ if (StringRef(A->getValue(i)) != "--no-demangle")
DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker),
- A->getValue(Args, i));
+ A->getValue(i));
continue;
}
@@ -197,22 +185,22 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// some build systems. We don't try to be complete here because we don't
// care to encourage this usage model.
if (A->getOption().matches(options::OPT_Wp_COMMA) &&
- A->getNumValues() == 2 &&
- (A->getValue(Args, 0) == StringRef("-MD") ||
- A->getValue(Args, 0) == StringRef("-MMD"))) {
+ (A->getValue(0) == StringRef("-MD") ||
+ A->getValue(0) == StringRef("-MMD"))) {
// Rewrite to -MD/-MMD along with -MF.
- if (A->getValue(Args, 0) == StringRef("-MD"))
+ if (A->getValue(0) == StringRef("-MD"))
DAL->AddFlagArg(A, Opts->getOption(options::OPT_MD));
else
DAL->AddFlagArg(A, Opts->getOption(options::OPT_MMD));
- DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF),
- A->getValue(Args, 1));
+ if (A->getNumValues() == 2)
+ DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF),
+ A->getValue(1));
continue;
}
// Rewrite reserved library names.
if (A->getOption().matches(options::OPT_l)) {
- StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue();
// Rewrite unless -nostdlib is present.
if (!HasNostdlib && Value == "stdc++") {
@@ -285,48 +273,23 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX;
CCCEcho = Args->hasArg(options::OPT_ccc_echo);
if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name))
- CCCGenericGCCName = A->getValue(*Args);
- CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx,
- options::OPT_ccc_no_clang_cxx,
- CCCUseClangCXX);
+ CCCGenericGCCName = A->getValue();
CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch,
options::OPT_ccc_pch_is_pth);
- CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang);
- CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp);
- if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) {
- StringRef Cur = A->getValue(*Args);
-
- CCCClangArchs.clear();
- while (!Cur.empty()) {
- std::pair<StringRef, StringRef> Split = Cur.split(',');
-
- if (!Split.first.empty()) {
- llvm::Triple::ArchType Arch =
- llvm::Triple(Split.first, "", "").getArch();
-
- if (Arch == llvm::Triple::UnknownArch)
- Diag(clang::diag::err_drv_invalid_arch_name) << Split.first;
-
- CCCClangArchs.insert(Arch);
- }
-
- Cur = Split.second;
- }
- }
// FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld
// and getToolChain is const.
if (const Arg *A = Args->getLastArg(options::OPT_target))
- DefaultTargetTriple = A->getValue(*Args);
+ DefaultTargetTriple = A->getValue();
if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
- Dir = InstalledDir = A->getValue(*Args);
+ Dir = InstalledDir = A->getValue();
for (arg_iterator it = Args->filtered_begin(options::OPT_B),
ie = Args->filtered_end(); it != ie; ++it) {
const Arg *A = *it;
A->claim();
- PrefixDirs.push_back(A->getValue(*Args, 0));
+ PrefixDirs.push_back(A->getValue(0));
}
if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ))
- SysRoot = A->getValue(*Args);
+ SysRoot = A->getValue();
if (Args->hasArg(options::OPT_nostdlib))
UseStdLib = false;
@@ -399,11 +362,11 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
std::string Cmd;
llvm::raw_string_ostream OS(Cmd);
if (FailingCommand)
- C.PrintJob(OS, *FailingCommand, "\n", false);
+ C.PrintDiagnosticJob(OS, *FailingCommand);
else
// Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an
// associated FailingCommand, so just pass all jobs.
- C.PrintJob(OS, C.getJobs(), "\n", false);
+ C.PrintDiagnosticJob(OS, C.getJobs());
OS.flush();
// Clear stale state and suppress tool output.
@@ -418,7 +381,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
bool IgnoreInput = false;
// Ignore input from stdin or any inputs that cannot be preprocessed.
- if (!strcmp(it->second->getValue(C.getArgs()), "-")) {
+ if (!strcmp(it->second->getValue(), "-")) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s) - ignoring input from stdin"
".";
@@ -442,7 +405,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
it != ie; ++it) {
Arg *A = *it;
if (A->getOption().matches(options::OPT_arch)) {
- StringRef ArchName = A->getValue(C.getArgs());
+ StringRef ArchName = A->getValue();
ArchNames.insert(ArchName);
}
}
@@ -501,57 +464,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating run script: " + Script + " " + Err;
} else {
- // Strip away options not necessary to reproduce the crash.
- // FIXME: This doesn't work with quotes (e.g., -D "foo bar").
- SmallVector<std::string, 16> Flag;
- Flag.push_back("-D ");
- Flag.push_back("-F");
- Flag.push_back("-I ");
- Flag.push_back("-M ");
- Flag.push_back("-MD ");
- Flag.push_back("-MF ");
- Flag.push_back("-MG ");
- Flag.push_back("-MM ");
- Flag.push_back("-MMD ");
- Flag.push_back("-MP ");
- Flag.push_back("-MQ ");
- Flag.push_back("-MT ");
- Flag.push_back("-o ");
- Flag.push_back("-coverage-file ");
- Flag.push_back("-dependency-file ");
- Flag.push_back("-fdebug-compilation-dir ");
- Flag.push_back("-fmodule-cache-path ");
- Flag.push_back("-idirafter ");
- Flag.push_back("-include ");
- Flag.push_back("-include-pch ");
- Flag.push_back("-internal-isystem ");
- Flag.push_back("-internal-externc-isystem ");
- Flag.push_back("-iprefix ");
- Flag.push_back("-iwithprefix ");
- Flag.push_back("-iwithprefixbefore ");
- Flag.push_back("-isysroot ");
- Flag.push_back("-isystem ");
- Flag.push_back("-iquote ");
- Flag.push_back("-resource-dir ");
- Flag.push_back("-serialize-diagnostic-file ");
- for (unsigned i = 0, e = Flag.size(); i < e; ++i) {
- size_t I = 0, E = 0;
- do {
- I = Cmd.find(Flag[i], I);
- if (I == std::string::npos) break;
-
- E = Cmd.find(" ", I + Flag[i].length());
- if (E == std::string::npos) break;
- // The -D option is not removed. Instead, the argument is quoted.
- if (Flag[i] != "-D ") {
- Cmd.erase(I, E - I + 1);
- } else {
- Cmd.insert(I+3, "\"");
- Cmd.insert(++E, "\"");
- I = E;
- }
- } while(1);
- }
// Append the new filename with correct preprocessed suffix.
size_t I, E;
I = Cmd.find("-main-file-name ");
@@ -639,12 +551,12 @@ void Driver::PrintOptions(const ArgList &Args) const {
it != ie; ++it, ++i) {
Arg *A = *it;
llvm::errs() << "Option " << i << " - "
- << "Name: \"" << A->getOption().getName() << "\", "
+ << "Name: \"" << A->getOption().getPrefixedName() << "\", "
<< "Values: {";
for (unsigned j = 0; j < A->getNumValues(); ++j) {
if (j)
llvm::errs() << ", ";
- llvm::errs() << '"' << A->getValue(Args, j) << '"';
+ llvm::errs() << '"' << A->getValue(j) << '"';
}
llvm::errs() << "}\n";
}
@@ -652,7 +564,9 @@ void Driver::PrintOptions(const ArgList &Args) const {
void Driver::PrintHelp(bool ShowHidden) const {
getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(),
- ShowHidden);
+ /*Include*/0,
+ /*Exclude*/options::NoDriverOption |
+ (ShowHidden ? 0 : options::HelpHidden));
}
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -750,12 +664,12 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
// FIXME: The following handlers should use a callback mechanism, we don't
// know what the client would like to do.
if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) {
- llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\n";
+ llvm::outs() << GetFilePath(A->getValue(), TC) << "\n";
return false;
}
if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) {
- llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n";
+ llvm::outs() << GetProgramPath(A->getValue(), TC) << "\n";
return false;
}
@@ -818,7 +732,7 @@ static unsigned PrintActions1(const Compilation &C, Action *A,
os << Action::getClassName(A->getKind()) << ", ";
if (InputAction *IA = dyn_cast<InputAction>(A)) {
- os << "\"" << IA->getInputArg().getValue(C.getArgs()) << "\"";
+ os << "\"" << IA->getInputArg().getValue() << "\"";
} else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) {
os << '"' << BIA->getArchName() << '"'
<< ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}";
@@ -878,7 +792,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// Validate the option here; we don't save the type here because its
// particular spelling may participate in other driver choices.
llvm::Triple::ArchType Arch =
- llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+ tools::darwin::getArchTypeForDarwinArchName(A->getValue());
if (Arch == llvm::Triple::UnknownArch) {
Diag(clang::diag::err_drv_invalid_arch_name)
<< A->getAsString(Args);
@@ -886,15 +800,15 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
}
A->claim();
- if (ArchNames.insert(A->getValue(Args)))
- Archs.push_back(A->getValue(Args));
+ if (ArchNames.insert(A->getValue()))
+ Archs.push_back(A->getValue());
}
}
// When there is no explicit arch for this platform, make sure we still bind
// the architecture (to the default) so that -Xarch_ is handled correctly.
if (!Archs.size())
- Archs.push_back(Args.MakeArgString(TC.getArchName()));
+ Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName()));
// FIXME: We killed off some others but these aren't yet detected in a
// functional manner. If we added information to jobs about which "auxiliary"
@@ -981,8 +895,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
it != ie; ++it) {
Arg *A = *it;
- if (isa<InputOption>(A->getOption())) {
- const char *Value = A->getValue(Args);
+ if (A->getOption().getKind() == Option::InputClass) {
+ const char *Value = A->getValue();
types::ID Ty = types::TY_INVALID;
// Infer the input type if necessary.
@@ -1049,8 +963,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
if (CheckInputsExist && memcmp(Value, "-", 2) != 0) {
SmallString<64> Path(Value);
if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) {
- SmallString<64> Directory(WorkDir->getValue(Args));
- if (llvm::sys::path::is_absolute(Directory.str())) {
+ if (!llvm::sys::path::is_absolute(Path.str())) {
+ SmallString<64> Directory(WorkDir->getValue());
llvm::sys::path::append(Directory, Value);
Path.assign(Directory);
}
@@ -1064,21 +978,21 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
} else
Inputs.push_back(std::make_pair(Ty, A));
- } else if (A->getOption().isLinkerInput()) {
+ } else if (A->getOption().hasFlag(options::LinkerInput)) {
// Just treat as object type, we could make a special type for this if
// necessary.
Inputs.push_back(std::make_pair(types::TY_Object, A));
} else if (A->getOption().matches(options::OPT_x)) {
InputTypeArg = A;
- InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args));
+ InputType = types::lookupTypeForTypeSpecifier(A->getValue());
A->claim();
// Follow gcc behavior and treat as linker input for invalid -x
// options. Its not clear why we shouldn't just revert to unknown; but
// this isn't very important, we might as well be bug compatible.
if (!InputType) {
- Diag(clang::diag::err_drv_unknown_language) << A->getValue(Args);
+ Diag(clang::diag::err_drv_unknown_language) << A->getValue();
InputType = types::TY_Object;
}
}
@@ -1301,7 +1215,7 @@ void Driver::BuildJobs(Compilation &C) const {
const char *LinkingOutput = 0;
if (isa<LipoJobAction>(A)) {
if (FinalOutput)
- LinkingOutput = FinalOutput->getValue(C.getArgs());
+ LinkingOutput = FinalOutput->getValue();
else
LinkingOutput = DefaultImageName.c_str();
}
@@ -1331,13 +1245,13 @@ void Driver::BuildJobs(Compilation &C) const {
// DiagnosticsEngine, so that extra values, position, and so on could be
// printed.
if (!A->isClaimed()) {
- if (A->getOption().hasNoArgumentUnused())
+ if (A->getOption().hasFlag(options::NoArgumentUnused))
continue;
// Suppress the warning automatically if this is just a flag, and it is an
// instance of an argument we already claimed.
const Option &Opt = A->getOption();
- if (isa<FlagOption>(Opt)) {
+ if (Opt.getKind() == Option::FlagClass) {
bool DuplicateClaimed = false;
for (arg_iterator it = C.getArgs().filtered_begin(&Opt),
@@ -1392,6 +1306,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
!C.getArgs().hasArg(options::OPT_traditional_cpp) &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
+ !C.getArgs().hasArg(options::OPT_rewrite_objc) &&
ToolForJob->hasIntegratedCPP())
Inputs = &(*Inputs)[0]->getInputs();
@@ -1413,7 +1328,7 @@ void Driver::BuildJobsForAction(Compilation &C,
const Arg &Input = IA->getInputArg();
Input.claim();
if (Input.getOption().matches(options::OPT_INPUT)) {
- const char *Name = Input.getValue(C.getArgs());
+ const char *Name = Input.getValue();
Result = InputInfo(Name, A->getType(), Name);
} else
Result = InputInfo(&Input, A->getType(), "");
@@ -1502,7 +1417,7 @@ 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(C.getArgs()));
+ return C.addResultFile(FinalOutput->getValue());
}
// Default to writing to stdout?
@@ -1580,7 +1495,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
// Respect a limited subset of the '-Bprefix' functionality in GCC by
- // attempting to use this prefix when lokup up program paths.
+ // attempting to use this prefix when looking for file paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
ie = PrefixDirs.end(); it != ie; ++it) {
std::string Dir(*it);
@@ -1619,26 +1534,26 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
return Name;
}
-static bool isPathExecutable(llvm::sys::Path &P, bool WantFile) {
- bool Exists;
- return (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists
- : P.canExecute());
-}
-
-std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
- bool WantFile) const {
+std::string Driver::GetProgramPath(const char *Name,
+ const ToolChain &TC) const {
// FIXME: Needs a better variable than DefaultTargetTriple
std::string TargetSpecificExecutable(DefaultTargetTriple + "-" + Name);
// Respect a limited subset of the '-Bprefix' functionality in GCC by
- // attempting to use this prefix when lokup up program paths.
+ // attempting to use this prefix when looking for program paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
ie = PrefixDirs.end(); it != ie; ++it) {
- llvm::sys::Path P(*it);
- P.appendComponent(TargetSpecificExecutable);
- if (isPathExecutable(P, WantFile)) return P.str();
- P.eraseComponent();
- P.appendComponent(Name);
- if (isPathExecutable(P, WantFile)) return P.str();
+ bool IsDirectory;
+ if (!llvm::sys::fs::is_directory(*it, IsDirectory) && IsDirectory) {
+ llvm::sys::Path P(*it);
+ P.appendComponent(TargetSpecificExecutable);
+ if (P.canExecute()) return P.str();
+ P.eraseComponent();
+ P.appendComponent(Name);
+ if (P.canExecute()) return P.str();
+ } else {
+ llvm::sys::Path P(*it + Name);
+ if (P.canExecute()) return P.str();
+ }
}
const ToolChain::path_list &List = TC.getProgramPaths();
@@ -1646,10 +1561,10 @@ std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
it = List.begin(), ie = List.end(); it != ie; ++it) {
llvm::sys::Path P(*it);
P.appendComponent(TargetSpecificExecutable);
- if (isPathExecutable(P, WantFile)) return P.str();
+ if (P.canExecute()) return P.str();
P.eraseComponent();
P.appendComponent(Name);
- if (isPathExecutable(P, WantFile)) return P.str();
+ if (P.canExecute()) return P.str();
}
// If all else failed, search the path.
@@ -1701,7 +1616,7 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
StringRef DarwinArchName) {
// FIXME: Already done in Compilation *Driver::BuildCompilation
if (const Arg *A = Args.getLastArg(options::OPT_target))
- DefaultTargetTriple = A->getValue(Args);
+ DefaultTargetTriple = A->getValue();
llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple));
@@ -1710,14 +1625,14 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
// If an explict Darwin arch name is given, that trumps all.
if (!DarwinArchName.empty()) {
Target.setArch(
- llvm::Triple::getArchTypeForDarwinArchName(DarwinArchName));
+ tools::darwin::getArchTypeForDarwinArchName(DarwinArchName));
return Target;
}
// Handle the Darwin '-arch' flag.
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
llvm::Triple::ArchType DarwinArch
- = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+ = tools::darwin::getArchTypeForDarwinArchName(A->getValue());
if (DarwinArch != llvm::Triple::UnknownArch)
Target.setArch(DarwinArch);
}
@@ -1820,37 +1735,14 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
const llvm::Triple &Triple) const {
// Check if user requested no clang, or clang doesn't understand this type (we
// only handle single inputs for now).
- if (!CCCUseClang || JA.size() != 1 ||
+ if (JA.size() != 1 ||
!types::isAcceptedByClang((*JA.begin())->getType()))
return false;
// Otherwise make sure this is an action clang understands.
- if (isa<PreprocessJobAction>(JA)) {
- if (!CCCUseClangCPP) {
- Diag(clang::diag::warn_drv_not_using_clang_cpp);
- return false;
- }
- } else if (!isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA))
- return false;
-
- // Use clang for C++?
- if (!CCCUseClangCXX && types::isCXX((*JA.begin())->getType())) {
- Diag(clang::diag::warn_drv_not_using_clang_cxx);
+ if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) &&
+ !isa<CompileJobAction>(JA))
return false;
- }
-
- // Always use clang for precompiling, AST generation, and rewriting,
- // regardless of archs.
- if (isa<PrecompileJobAction>(JA) ||
- types::isOnlyAcceptedByClang(JA.getType()))
- return true;
-
- // Finally, don't use clang if this isn't one of the user specified archs to
- // build.
- if (!CCCClangArchs.empty() && !CCCClangArchs.count(Triple.getArch())) {
- Diag(clang::diag::warn_drv_not_using_clang_arch) << Triple.getArchName();
- return false;
- }
return true;
}
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 715819d04b26..3925b8aa35c5 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -14,11 +14,19 @@
using namespace clang::driver;
using namespace clang::driver::options;
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR)
+#include "clang/Driver/Options.inc"
+#undef OPTION
+#undef PREFIX
+
static const OptTable::Info InfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
- OPT_##GROUP, OPT_##ALIAS },
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+ FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/Options.inc"
};
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index a3e38b26f20f..6e7b6951fb83 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -11,6 +11,7 @@
#include "clang/Driver/Arg.h"
#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 <algorithm>
@@ -54,6 +55,13 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
if (int N = StrCmpOptionName(A.Name, B.Name))
return N == -1;
+ for (const char * const *APre = A.Prefixes,
+ * const *BPre = B.Prefixes;
+ *APre != 0 && *BPre != 0; ++APre, ++BPre) {
+ if (int N = StrCmpOptionName(*APre, *BPre))
+ return N == -1;
+ }
+
// Names are the same, check that classes are in order; exactly one
// should be joined, and it should succeed the other.
assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
@@ -78,23 +86,24 @@ OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
//
OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
- : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos),
- Options(new Option*[NumOptionInfos]),
- TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0)
+ : OptionInfos(_OptionInfos),
+ NumOptionInfos(_NumOptionInfos),
+ TheInputOptionID(0),
+ TheUnknownOptionID(0),
+ FirstSearchableIndex(0)
{
// Explicitly zero initialize the error to work around a bug in array
// value-initialization on MinGW with gcc 4.3.5.
- memset(Options, 0, sizeof(*Options) * NumOptionInfos);
// Find start of normal options.
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
unsigned Kind = getInfo(i + 1).Kind;
if (Kind == Option::InputClass) {
- assert(!TheInputOption && "Cannot have multiple input options!");
- TheInputOption = getOption(i + 1);
+ assert(!TheInputOptionID && "Cannot have multiple input options!");
+ TheInputOptionID = getInfo(i + 1).ID;
} else if (Kind == Option::UnknownClass) {
- assert(!TheUnknownOption && "Cannot have multiple input options!");
- TheUnknownOption = getOption(i + 1);
+ assert(!TheUnknownOptionID && "Cannot have multiple unknown options!");
+ TheUnknownOptionID = getInfo(i + 1).ID;
} else if (Kind != Option::GroupClass) {
FirstSearchableIndex = i;
break;
@@ -115,91 +124,80 @@ OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
// Check that options are in order.
for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
if (!(getInfo(i) < getInfo(i + 1))) {
- getOption(i)->dump();
- getOption(i + 1)->dump();
+ getOption(i).dump();
+ getOption(i + 1).dump();
llvm_unreachable("Options are not in order!");
}
}
#endif
+
+ // Build prefixes.
+ for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
+ if (const char *const *P = getInfo(i).Prefixes) {
+ for (; *P != 0; ++P) {
+ PrefixesUnion.insert(*P);
+ }
+ }
+ }
+
+ // Build prefix chars.
+ for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(),
+ E = PrefixesUnion.end(); I != E; ++I) {
+ StringRef Prefix = I->getKey();
+ for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end();
+ C != CE; ++C)
+ if (std::find(PrefixChars.begin(), PrefixChars.end(), *C)
+ == PrefixChars.end())
+ PrefixChars.push_back(*C);
+ }
}
OptTable::~OptTable() {
- for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
- delete Options[i];
- delete[] Options;
}
-Option *OptTable::CreateOption(unsigned id) const {
- const Info &info = getInfo(id);
- const OptionGroup *Group =
- cast_or_null<OptionGroup>(getOption(info.GroupID));
- const Option *Alias = getOption(info.AliasID);
-
- Option *Opt = 0;
- switch (info.Kind) {
- case Option::InputClass:
- Opt = new InputOption(id); break;
- case Option::UnknownClass:
- Opt = new UnknownOption(id); break;
- case Option::GroupClass:
- Opt = new OptionGroup(id, info.Name, Group); break;
- case Option::FlagClass:
- Opt = new FlagOption(id, info.Name, Group, Alias); break;
- case Option::JoinedClass:
- Opt = new JoinedOption(id, info.Name, Group, Alias); break;
- case Option::SeparateClass:
- Opt = new SeparateOption(id, info.Name, Group, Alias); break;
- case Option::CommaJoinedClass:
- Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
- case Option::MultiArgClass:
- Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
- case Option::JoinedOrSeparateClass:
- Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
- case Option::JoinedAndSeparateClass:
- Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
- }
+const Option OptTable::getOption(OptSpecifier Opt) const {
+ unsigned id = Opt.getID();
+ if (id == 0)
+ return Option(0, 0);
+ assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
+ return Option(&getInfo(id), this);
+}
- if (info.Flags & DriverOption)
- Opt->setDriverOption(true);
- if (info.Flags & LinkerInput)
- Opt->setLinkerInput(true);
- if (info.Flags & NoArgumentUnused)
- Opt->setNoArgumentUnused(true);
- if (info.Flags & NoForward)
- Opt->setNoForward(true);
- if (info.Flags & RenderAsInput)
- Opt->setNoOptAsInput(true);
- if (info.Flags & RenderJoined) {
- assert((info.Kind == Option::JoinedOrSeparateClass ||
- info.Kind == Option::SeparateClass) && "Invalid option.");
- Opt->setRenderStyle(Option::RenderJoinedStyle);
- }
- if (info.Flags & RenderSeparate) {
- assert((info.Kind == Option::JoinedOrSeparateClass ||
- info.Kind == Option::JoinedClass) && "Invalid option.");
- Opt->setRenderStyle(Option::RenderSeparateStyle);
- }
- if (info.Flags & Unsupported)
- Opt->setUnsupported(true);
- if (info.Flags & CC1Option)
- Opt->setIsCC1Option(true);
+static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) {
+ if (Arg == "-")
+ return true;
+ for (llvm::StringSet<>::const_iterator I = Prefixes.begin(),
+ E = Prefixes.end(); I != E; ++I)
+ if (Arg.startswith(I->getKey()))
+ return false;
+ return true;
+}
- return Opt;
+/// \returns Matched size. 0 means no match.
+static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
+ for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
+ StringRef Prefix(*Pre);
+ if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
+ return Prefix.size() + StringRef(I->Name).size();
+ }
+ return 0;
}
Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
unsigned Prev = Index;
const char *Str = Args.getArgString(Index);
- // Anything that doesn't start with '-' is an input, as is '-' itself.
- if (Str[0] != '-' || Str[1] == '\0')
- return new Arg(TheInputOption, Index++, Str);
+ // Anything that doesn't start with PrefixesUnion is an input, as is '-'
+ // itself.
+ if (isInput(PrefixesUnion, Str))
+ return new Arg(getOption(TheInputOptionID), Str, Index++, Str);
const Info *Start = OptionInfos + FirstSearchableIndex;
const Info *End = OptionInfos + getNumOptions();
+ StringRef Name = StringRef(Str).ltrim(PrefixChars);
// Search for the first next option which could be a prefix.
- Start = std::lower_bound(Start, End, Str);
+ Start = std::lower_bound(Start, End, Name.data());
// Options are stored in sorted order, with '\0' at the end of the
// alphabet. Since the only options which can accept a string must
@@ -210,15 +208,16 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
// blanking on the simplest way to make it fast. We can solve this
// problem when we move to TableGen.
for (; Start != End; ++Start) {
+ unsigned ArgSize = 0;
// Scan for first option which is a proper prefix.
for (; Start != End; ++Start)
- if (memcmp(Str, Start->Name, strlen(Start->Name)) == 0)
+ if ((ArgSize = matchOption(Start, Str)))
break;
if (Start == End)
break;
// See if this option matches.
- if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index))
+ if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
return A;
// Otherwise, see if this argument was missing values.
@@ -226,7 +225,7 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
return 0;
}
- return new Arg(TheUnknownOption, Index++, Str);
+ return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
}
InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
@@ -266,10 +265,11 @@ InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
}
static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
- std::string Name = Opts.getOptionName(Id);
+ const Option O = Opts.getOption(Id);
+ std::string Name = O.getPrefixedName();
// Add metavar, if used.
- switch (Opts.getOptionKind(Id)) {
+ switch (O.getKind()) {
case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
llvm_unreachable("Invalid option with help text.");
@@ -346,7 +346,8 @@ static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
}
void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
- const char *Title, bool ShowHidden) const {
+ const char *Title, unsigned short FlagsToInclude,
+ unsigned short FlagsToExclude) const {
OS << "OVERVIEW: " << Title << "\n";
OS << '\n';
OS << "USAGE: " << Name << " [options] <inputs>\n";
@@ -365,7 +366,8 @@ void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
if (getOptionKind(Id) == Option::GroupClass)
continue;
- if (!ShowHidden && isOptionHelpHidden(Id))
+ if ((FlagsToInclude && !(getInfo(Id).Flags & FlagsToInclude)) ||
+ getInfo(Id).Flags & FlagsToExclude)
continue;
if (const char *Text = getOptionHelpText(Id)) {
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index 03360ea2d89a..9a34df59036a 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -13,46 +13,20 @@
#include "clang/Driver/ArgList.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/Twine.h"
#include <cassert>
#include <algorithm>
using namespace clang::driver;
-Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name,
- const OptionGroup *_Group, const Option *_Alias)
- : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias),
- Unsupported(false), LinkerInput(false), NoOptAsInput(false),
- DriverOption(false), NoArgumentUnused(false), NoForward(false) {
+Option::Option(const OptTable::Info *info, const OptTable *owner)
+ : Info(info), Owner(owner) {
// Multi-level aliases are not supported, and alias options cannot
// have groups. This just simplifies option tracking, it is not an
// inherent limitation.
- assert((!Alias || (!Alias->Alias && !Group)) &&
+ assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
+ !getGroup().isValid())) &&
"Multi-level aliases and aliases with groups are unsupported.");
-
- // Initialize rendering options based on the class.
- switch (Kind) {
- case GroupClass:
- case InputClass:
- case UnknownClass:
- RenderStyle = RenderValuesStyle;
- break;
-
- case JoinedClass:
- case JoinedAndSeparateClass:
- RenderStyle = RenderJoinedStyle;
- break;
-
- case CommaJoinedClass:
- RenderStyle = RenderCommaJoinedStyle;
- break;
-
- case FlagClass:
- case SeparateClass:
- case MultiArgClass:
- case JoinedOrSeparateClass:
- RenderStyle = RenderSeparateStyle;
- break;
- }
}
Option::~Option() {
@@ -60,7 +34,7 @@ Option::~Option() {
void Option::dump() const {
llvm::errs() << "<";
- switch (Kind) {
+ switch (getKind()) {
#define P(N) case N: llvm::errs() << #N; break
P(GroupClass);
P(InputClass);
@@ -75,206 +49,153 @@ void Option::dump() const {
#undef P
}
- llvm::errs() << " Name:\"" << Name << '"';
+ llvm::errs() << " Prefixes:[";
+ for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
+ llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
+ }
+ llvm::errs() << ']';
- if (Group) {
+ llvm::errs() << " Name:\"" << getName() << '"';
+
+ const Option Group = getGroup();
+ if (Group.isValid()) {
llvm::errs() << " Group:";
- Group->dump();
+ Group.dump();
}
- if (Alias) {
+ const Option Alias = getAlias();
+ if (Alias.isValid()) {
llvm::errs() << " Alias:";
- Alias->dump();
+ Alias.dump();
}
- if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this))
- llvm::errs() << " NumArgs:" << MOA->getNumArgs();
+ if (getKind() == MultiArgClass)
+ llvm::errs() << " NumArgs:" << getNumArgs();
llvm::errs() << ">\n";
}
bool Option::matches(OptSpecifier Opt) const {
// Aliases are never considered in matching, look through them.
- if (Alias)
- return Alias->matches(Opt);
+ const Option Alias = getAlias();
+ if (Alias.isValid())
+ return Alias.matches(Opt);
// Check exact match.
- if (ID == Opt)
+ if (getID() == Opt.getID())
return true;
- if (Group)
- return Group->matches(Opt);
+ const Option Group = getGroup();
+ if (Group.isValid())
+ return Group.matches(Opt);
return false;
}
-OptionGroup::OptionGroup(OptSpecifier ID, const char *Name,
- const OptionGroup *Group)
- : Option(Option::GroupClass, ID, Name, Group, 0) {
-}
-
-Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const {
- llvm_unreachable("accept() should never be called on an OptionGroup");
-}
-
-InputOption::InputOption(OptSpecifier ID)
- : Option(Option::InputClass, ID, "<input>", 0, 0) {
-}
-
-Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const {
- llvm_unreachable("accept() should never be called on an InputOption");
-}
-
-UnknownOption::UnknownOption(OptSpecifier ID)
- : Option(Option::UnknownClass, ID, "<unknown>", 0, 0) {
-}
-
-Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const {
- llvm_unreachable("accept() should never be called on an UnknownOption");
-}
-
-FlagOption::FlagOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias)
- : Option(Option::FlagClass, ID, Name, Group, Alias) {
-}
-
-Arg *FlagOption::accept(const ArgList &Args, unsigned &Index) const {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
- return 0;
-
- return new Arg(getUnaliasedOption(), Index++);
-}
-
-JoinedOption::JoinedOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias)
- : Option(Option::JoinedClass, ID, Name, Group, Alias) {
-}
-
-Arg *JoinedOption::accept(const ArgList &Args, unsigned &Index) const {
- // Always matches.
- const char *Value = Args.getArgString(Index) + getName().size();
- return new Arg(getUnaliasedOption(), Index++, Value);
-}
-
-CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group,
- const Option *Alias)
- : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) {
-}
-
-Arg *CommaJoinedOption::accept(const ArgList &Args,
- unsigned &Index) const {
- // Always matches.
- const char *Str = Args.getArgString(Index) + getName().size();
- Arg *A = new Arg(getUnaliasedOption(), Index++);
+Arg *Option::accept(const ArgList &Args,
+ unsigned &Index,
+ unsigned ArgSize) const {
+ const Option &UnaliasedOption = getUnaliasedOption();
+ StringRef Spelling;
+ // If the option was an alias, get the spelling from the unaliased one.
+ if (getID() == UnaliasedOption.getID()) {
+ Spelling = StringRef(Args.getArgString(Index), ArgSize);
+ } else {
+ Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
+ Twine(UnaliasedOption.getName()));
+ }
- // Parse out the comma separated values.
- const char *Prev = Str;
- for (;; ++Str) {
- char c = *Str;
+ switch (getKind()) {
+ case FlagClass:
+ if (ArgSize != strlen(Args.getArgString(Index)))
+ return 0;
- if (!c || c == ',') {
- if (Prev != Str) {
- char *Value = new char[Str - Prev + 1];
- memcpy(Value, Prev, Str - Prev);
- Value[Str - Prev] = '\0';
- A->getValues().push_back(Value);
+ return new Arg(UnaliasedOption, Spelling, Index++);
+ case JoinedClass: {
+ const char *Value = Args.getArgString(Index) + ArgSize;
+ return new Arg(UnaliasedOption, Spelling, Index++, Value);
+ }
+ case CommaJoinedClass: {
+ // Always matches.
+ const char *Str = Args.getArgString(Index) + ArgSize;
+ Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
+
+ // Parse out the comma separated values.
+ const char *Prev = Str;
+ for (;; ++Str) {
+ char c = *Str;
+
+ if (!c || c == ',') {
+ if (Prev != Str) {
+ char *Value = new char[Str - Prev + 1];
+ memcpy(Value, Prev, Str - Prev);
+ Value[Str - Prev] = '\0';
+ A->getValues().push_back(Value);
+ }
+
+ if (!c)
+ break;
+
+ Prev = Str + 1;
}
-
- if (!c)
- break;
-
- Prev = Str + 1;
}
- }
- A->setOwnsValues(true);
-
- return A;
-}
-
-SeparateOption::SeparateOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias)
- : Option(Option::SeparateClass, ID, Name, Group, Alias) {
-}
-
-Arg *SeparateOption::accept(const ArgList &Args, unsigned &Index) const {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
- return 0;
-
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
-}
-
-MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias,
- unsigned _NumArgs)
- : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) {
- assert(NumArgs > 1 && "Invalid MultiArgOption!");
-}
-
-Arg *MultiArgOption::accept(const ArgList &Args, unsigned &Index) const {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
- return 0;
-
- Index += 1 + NumArgs;
- if (Index > Args.getNumInputArgStrings())
- return 0;
+ A->setOwnsValues(true);
- Arg *A = new Arg(getUnaliasedOption(), Index - 1 - NumArgs,
- Args.getArgString(Index - NumArgs));
- for (unsigned i = 1; i != NumArgs; ++i)
- A->getValues().push_back(Args.getArgString(Index - NumArgs + i));
- return A;
-}
-
-JoinedOrSeparateOption::JoinedOrSeparateOption(OptSpecifier ID,
- const char *Name,
- const OptionGroup *Group,
- const Option *Alias)
- : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) {
-}
-
-Arg *JoinedOrSeparateOption::accept(const ArgList &Args,
- unsigned &Index) const {
- // If this is not an exact match, it is a joined arg.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index))) {
- const char *Value = Args.getArgString(Index) + getName().size();
- return new Arg(this, Index++, Value);
+ return A;
}
+ case SeparateClass:
+ // Matches iff this is an exact match.
+ // FIXME: Avoid strlen.
+ if (ArgSize != strlen(Args.getArgString(Index)))
+ return 0;
+
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ return new Arg(UnaliasedOption, Spelling,
+ Index - 2, Args.getArgString(Index - 1));
+ case MultiArgClass: {
+ // Matches iff this is an exact match.
+ // FIXME: Avoid strlen.
+ if (ArgSize != strlen(Args.getArgString(Index)))
+ return 0;
+
+ Index += 1 + getNumArgs();
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
+ Args.getArgString(Index - getNumArgs()));
+ for (unsigned i = 1; i != getNumArgs(); ++i)
+ A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
+ return A;
+ }
+ case JoinedOrSeparateClass: {
+ // If this is not an exact match, it is a joined arg.
+ // FIXME: Avoid strlen.
+ if (ArgSize != strlen(Args.getArgString(Index))) {
+ const char *Value = Args.getArgString(Index) + ArgSize;
+ return new Arg(*this, Spelling, Index++, Value);
+ }
- // Otherwise it must be separate.
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
-}
-
-JoinedAndSeparateOption::JoinedAndSeparateOption(OptSpecifier ID,
- const char *Name,
- const OptionGroup *Group,
- const Option *Alias)
- : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) {
-}
-
-Arg *JoinedAndSeparateOption::accept(const ArgList &Args,
- unsigned &Index) const {
- // Always matches.
-
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
+ // Otherwise it must be separate.
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
- return new Arg(getUnaliasedOption(), Index - 2,
- Args.getArgString(Index-2)+getName().size(),
- Args.getArgString(Index-1));
+ return new Arg(UnaliasedOption, Spelling,
+ Index - 2, Args.getArgString(Index - 1));
+ }
+ case JoinedAndSeparateClass:
+ // Always matches.
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ return new Arg(UnaliasedOption, Spelling, Index - 2,
+ Args.getArgString(Index - 2) + ArgSize,
+ Args.getArgString(Index - 1));
+ default:
+ llvm_unreachable("Invalid option kind!");
+ }
}
diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h
new file mode 100644
index 000000000000..ecb396ea06cf
--- /dev/null
+++ b/lib/Driver/SanitizerArgs.h
@@ -0,0 +1,106 @@
+//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
+#define CLANG_LIB_DRIVER_SANITIZERARGS_H_
+
+#include "clang/Driver/ArgList.h"
+
+namespace clang {
+namespace driver {
+
+class SanitizerArgs {
+ /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
+ /// bit positions within \c Kind.
+ enum SanitizeOrdinal {
+#define SANITIZER(NAME, ID) SO_##ID,
+#include "clang/Basic/Sanitizers.def"
+ SO_Count
+ };
+
+ /// Bugs to catch at runtime.
+ enum SanitizeKind {
+#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS,
+#include "clang/Basic/Sanitizers.def"
+ NeedsAsanRt = Address,
+ NeedsTsanRt = Thread,
+ NeedsUbsanRt = Undefined
+ };
+ unsigned Kind;
+
+ public:
+ SanitizerArgs() : Kind(0) {}
+ /// 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 sanitizesVptr() const { return Kind & Vptr; }
+
+ void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
+ if (!Kind)
+ return;
+ llvm::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));
+ }
+
+ 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.
+ static unsigned parse(const char *Value) {
+ return 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());
+ }
+
+ /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
+ /// invalid components.
+ static unsigned parse(const Driver &D, const Arg *A) {
+ unsigned Kind = 0;
+ for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
+ if (unsigned K = parse(A->getValue(I)))
+ Kind |= K;
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << A->getValue(I);
+ }
+ return Kind;
+ }
+
+ /// 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
+ /// "-fsanitize=alignment".
+ static std::string describeSanitizeArg(const ArgList &Args, const Arg *A,
+ unsigned Mask) {
+ if (!A->getOption().matches(options::OPT_fsanitize_EQ))
+ return A->getAsString(Args);
+
+ for (unsigned I = 0, N = A->getNumValues(); I != N; ++I)
+ if (parse(A->getValue(I)) & Mask)
+ return std::string("-fsanitize=") + A->getValue(I);
+
+ llvm_unreachable("arg didn't provide expected value");
+ }
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 48ed044c8f5c..de8ed1d1c5e7 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -14,6 +14,7 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -32,13 +33,32 @@ const Driver &ToolChain::getDriver() const {
return D;
}
+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
+ // an inverse of the darwin::getArchTypeForDarwinArchName() function, but the
+ // only interesting special case is powerpc.
+ switch (Triple.getArch()) {
+ case llvm::Triple::ppc:
+ return "ppc";
+ case llvm::Triple::ppc64:
+ return "ppc64";
+ default:
+ return Triple.getArchName();
+ }
+}
+
+bool ToolChain::IsUnwindTablesDefault() const {
+ return false;
+}
+
std::string ToolChain::GetFilePath(const char *Name) const {
return D.GetFilePath(Name, *this);
}
-std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const {
- return D.GetProgramPath(Name, *this, WantFile);
+std::string ToolChain::GetProgramPath(const char *Name) const {
+ return D.GetProgramPath(Name, *this);
}
types::ID ToolChain::LookupTypeForExtension(const char *Ext) const {
@@ -66,13 +86,13 @@ static const char *getARMTargetCPU(const ArgList &Args,
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue(Args);
+ return A->getValue();
}
StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
- MArch = A->getValue(Args);
+ MArch = A->getValue();
} else {
// Otherwise, use the Arch from the triple.
MArch = Triple.getArchName();
@@ -91,6 +111,8 @@ static const char *getARMTargetCPU(const ArgList &Args,
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
.Cases("armv7", "armv7a", "armv7-a", "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")
.Case("ep9312", "ep9312")
@@ -119,10 +141,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", "v7")
+ .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
.Case("cortex-m3", "v7m")
.Case("cortex-m4", "v7m")
.Case("cortex-m0", "v6m")
+ .Case("cortex-a9-mp", "v7f")
+ .Case("swift", "v7s")
.Default("");
}
@@ -142,7 +166,7 @@ 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 == "v7" && getTriple().isOSDarwin());
+ bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin());
std::string ArchName = "arm";
// Assembly files should start in ARM mode.
@@ -180,7 +204,7 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
const ArgList &Args) const
{
if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) {
- StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue();
if (Value == "compiler-rt")
return ToolChain::RLT_CompilerRT;
if (Value == "libgcc")
@@ -194,7 +218,7 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
- StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue();
if (Value == "libc++")
return ToolChain::CST_Libcxx;
if (Value == "libstdc++")
@@ -273,3 +297,24 @@ void ToolChain::AddCCKextLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-lcc_kext");
}
+
+bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Check if -ffast-math or -funsafe-math is enabled.
+ Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations);
+
+ if (!A || A->getOption().getID() == options::OPT_fno_fast_math ||
+ A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations)
+ return false;
+
+ // If crtfastmath.o exists add it to the arguments.
+ std::string Path = GetFilePath("crtfastmath.o");
+ if (Path == "crtfastmath.o") // Not found.
+ return false;
+
+ CmdArgs.push_back(Args.MakeArgString(Path));
+ return true;
+}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 01c66239a121..a2ccb35ed264 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -31,6 +31,8 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
+#include "SanitizerArgs.h"
+
#include <cstdlib> // ::getenv
#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
@@ -80,17 +82,11 @@ bool Darwin::HasNativeLLVMSupport() const {
/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
- if (isTargetIPhoneOS()) {
+ if (isTargetIPhoneOS())
return ObjCRuntime(ObjCRuntime::iOS, TargetVersion);
- } else if (TargetSimulatorVersionFromDefines != VersionTuple()) {
- return ObjCRuntime(ObjCRuntime::iOS, TargetSimulatorVersionFromDefines);
- } else {
- if (isNonFragile) {
- return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
- } else {
- return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
- }
- }
+ if (isNonFragile)
+ return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
+ return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
}
/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
@@ -111,6 +107,9 @@ static const char *GetArmArchForMArch(StringRef Value) {
.Cases("armv7a", "armv7-a", "armv7")
.Cases("armv7r", "armv7-r", "armv7")
.Cases("armv7m", "armv7-m", "armv7")
+ .Cases("armv7f", "armv7-f", "armv7f")
+ .Cases("armv7k", "armv7-k", "armv7k")
+ .Cases("armv7s", "armv7-s", "armv7s")
.Default(0);
}
@@ -122,7 +121,10 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Case("xscale", "xscale")
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s",
"arm1176jzf-s", "cortex-m0", "armv6")
- .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "armv7")
+ .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15",
+ "armv7")
+ .Case("cortex-a9-mp", "armv7f")
+ .Case("swift", "armv7s")
.Default(0);
}
@@ -134,11 +136,11 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
case llvm::Triple::thumb:
case llvm::Triple::arm: {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- if (const char *Arch = GetArmArchForMArch(A->getValue(Args)))
+ if (const char *Arch = GetArmArchForMArch(A->getValue()))
return Arch;
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- if (const char *Arch = GetArmArchForMCpu(A->getValue(Args)))
+ if (const char *Arch = GetArmArchForMCpu(A->getValue()))
return Arch;
return "arm";
@@ -175,24 +177,11 @@ void Generic_ELF::anchor() {}
Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const {
Action::ActionClass Key = JA.getKind();
- bool useClang = false;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) {
- useClang = true;
- // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI.
- if (!getDriver().shouldForceClangUse() &&
- Inputs.size() == 1 &&
- types::isCXX(Inputs[0]->getType()) &&
- getTriple().isOSDarwin() &&
- getTriple().getArch() == llvm::Triple::x86 &&
- (C.getArgs().getLastArg(options::OPT_fapple_kext) ||
- C.getArgs().getLastArg(options::OPT_mkernel)))
- useClang = false;
- }
-
- // FIXME: This seems like a hacky way to choose clang frontend.
- if (useClang)
+ // 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,
@@ -245,30 +234,6 @@ DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple)
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
-
- // For fallback, we need to know how to find the GCC cc1 executables, so we
- // also add the GCC libexec paths. This is legacy code that can be removed
- // once fallback is no longer useful.
- AddGCCLibexecPath(DarwinVersion[0]);
- AddGCCLibexecPath(DarwinVersion[0] - 2);
- AddGCCLibexecPath(DarwinVersion[0] - 1);
- AddGCCLibexecPath(DarwinVersion[0] + 1);
- AddGCCLibexecPath(DarwinVersion[0] + 2);
-}
-
-void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) {
- std::string ToolChainDir = "i686-apple-darwin";
- ToolChainDir += llvm::utostr(darwinVersion);
- ToolChainDir += "/4.2.1";
-
- std::string Path = getDriver().Dir;
- Path += "/../llvm-gcc-4.2/libexec/gcc/";
- Path += ToolChainDir;
- getProgramPaths().push_back(Path);
-
- Path = "/usr/llvm-gcc-4.2/libexec/gcc/";
- Path += ToolChainDir;
- getProgramPaths().push_back(Path);
}
void DarwinClang::AddLinkARCArgs(const ArgList &Args,
@@ -287,9 +252,6 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
s += "iphonesimulator";
else if (isTargetIPhoneOS())
s += "iphoneos";
- // FIXME: Remove this once we depend fully on -mios-simulator-version-min.
- else if (TargetSimulatorVersionFromDefines != VersionTuple())
- s += "iphonesimulator";
else
s += "macosx";
s += ".a";
@@ -320,13 +282,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
break;
default:
getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
- << Args.getLastArg(options::OPT_rtlib_EQ)->getValue(Args) << "darwin";
+ << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "darwin";
return;
}
// Darwin doesn't support real static executables, don't link any runtime
// libraries with -static.
- if (Args.hasArg(options::OPT_static))
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext) ||
+ Args.hasArg(options::OPT_mkernel))
return;
// Reject -static-libgcc for now, we can deal with this when and if someone
@@ -351,15 +315,16 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
+ SanitizerArgs Sanitize(getDriver(), Args);
+
// Add ASAN runtime library, if required. Dynamic libraries and bundles
// should not be linked with the runtime library.
- if (Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false)) {
+ if (Sanitize.needsAsanRt()) {
if (Args.hasArg(options::OPT_dynamiclib) ||
Args.hasArg(options::OPT_bundle)) return;
if (isTargetIPhoneOS()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
- << "-faddress-sanitizer";
+ << "-fsanitize=address";
} else {
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a");
@@ -410,67 +375,28 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
-static inline StringRef SimulatorVersionDefineName() {
- return "__IPHONE_OS_VERSION_MIN_REQUIRED";
-}
-
-/// \brief Parse the simulator version define:
-/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9])
-// and return the grouped values as integers, e.g:
-// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
-// will return Major=4, Minor=2, Micro=1.
-static bool GetVersionFromSimulatorDefine(StringRef define,
- unsigned &Major, unsigned &Minor,
- unsigned &Micro) {
- assert(define.startswith(SimulatorVersionDefineName()));
- StringRef name, version;
- llvm::tie(name, version) = define.split('=');
- if (version.empty())
- return false;
- std::string verstr = version.str();
- char *end;
- unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10);
- if (*end != '\0')
- return false;
- Major = num / 10000;
- num = num % 10000;
- Minor = num / 100;
- Micro = num % 100;
- return true;
-}
-
void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
const OptTable &Opts = getDriver().getOpts();
+ // 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 (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)) {
+ Args.append(Args.MakeSeparateArg(
+ 0, Opts.getOption(options::OPT_isysroot), env));
+ }
+ }
+ }
+
Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
Arg *iOSSimVersion = Args.getLastArg(
options::OPT_mios_simulator_version_min_EQ);
- // FIXME: HACK! When compiling for the simulator we don't get a
- // '-miphoneos-version-min' to help us know whether there is an ARC runtime
- // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
- // define passed in command-line.
- if (!iOSVersion && !iOSSimVersion) {
- for (arg_iterator it = Args.filtered_begin(options::OPT_D),
- ie = Args.filtered_end(); it != ie; ++it) {
- StringRef define = (*it)->getValue(Args);
- if (define.startswith(SimulatorVersionDefineName())) {
- unsigned Major = 0, Minor = 0, Micro = 0;
- if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
- Major < 10 && Minor < 100 && Micro < 100) {
- TargetSimulatorVersionFromDefines = VersionTuple(Major, Minor, Micro);
- }
- // When using the define to indicate the simulator, we force
- // 10.6 macosx target.
- const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- OSXVersion = Args.MakeJoinedArg(0, O, "10.6");
- Args.append(OSXVersion);
- break;
- }
- }
- }
-
if (OSXVersion && (iOSVersion || iOSSimVersion)) {
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
@@ -500,7 +426,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (iOSTarget.empty()) {
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
StringRef first, second;
- StringRef isysroot = A->getValue(Args);
+ StringRef isysroot = A->getValue();
llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS"));
if (second != "")
iOSTarget = second.substr(0,3);
@@ -510,7 +436,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// If no OSX or iOS target has been specified and we're compiling for armv7,
// go ahead as assume we're targeting iOS.
if (OSXTarget.empty() && iOSTarget.empty() &&
- getDarwinArchName(Args) == "armv7")
+ (getDarwinArchName(Args) == "armv7" ||
+ getDarwinArchName(Args) == "armv7s"))
iOSTarget = iOSVersionMin;
// Handle conflicting deployment targets
@@ -536,21 +463,21 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
if (!OSXTarget.empty()) {
- const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget);
Args.append(OSXVersion);
} else if (!iOSTarget.empty()) {
- const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
+ const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget);
Args.append(iOSVersion);
} else if (!iOSSimTarget.empty()) {
- const Option *O = Opts.getOption(
+ const Option O = Opts.getOption(
options::OPT_mios_simulator_version_min_EQ);
iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget);
Args.append(iOSSimVersion);
} else {
// Otherwise, assume we are targeting OS X.
- const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin);
Args.append(OSXVersion);
}
@@ -568,7 +495,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
bool HadExtra;
if (OSXVersion) {
assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor,
+ if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major != 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
@@ -576,7 +503,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
} else {
const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
assert(Version && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor,
+ if (!Driver::GetReleaseVersion(Version->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major >= 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
@@ -614,7 +541,7 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
// Check in the sysroot first.
bool Exists;
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- llvm::sys::Path P(A->getValue(Args));
+ llvm::sys::Path P(A->getValue());
P.appendComponent("usr");
P.appendComponent("lib");
P.appendComponent("libstdc++.dylib");
@@ -655,7 +582,14 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
llvm::sys::Path P(getDriver().ResourceDir);
P.appendComponent("lib");
P.appendComponent("darwin");
- P.appendComponent("libclang_rt.cc_kext.a");
+
+ // Use the newer cc_kext for iOS ARM after 6.0.
+ if (!isTargetIPhoneOS() || isTargetIOSSimulator() ||
+ !isIPhoneOSVersionLT(6, 0)) {
+ P.appendComponent("libclang_rt.cc_kext.a");
+ } else {
+ P.appendComponent("libclang_rt.cc_kext_ios5.a");
+ }
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build.
@@ -683,15 +617,15 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
if (A->getOption().matches(options::OPT_Xarch__)) {
// Skip this argument unless the architecture matches either the toolchain
// triple arch, or the arch being bound.
- //
- // FIXME: Canonicalize name.
- StringRef XarchArch = A->getValue(Args, 0);
- if (!(XarchArch == getArchName() ||
- (BoundArch && XarchArch == BoundArch)))
+ llvm::Triple::ArchType XarchArch =
+ tools::darwin::getArchTypeForDarwinArchName(A->getValue(0));
+ if (!(XarchArch == getArch() ||
+ (BoundArch && XarchArch ==
+ tools::darwin::getArchTypeForDarwinArchName(BoundArch))))
continue;
Arg *OriginalArg = A;
- unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(Args, 1));
+ unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
unsigned Prev = Index;
Arg *XarchArg = Opts.ParseOneArg(Args, Index);
@@ -707,7 +641,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
<< A->getAsString(Args);
continue;
- } else if (XarchArg->getOption().isDriverOption()) {
+ } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
<< A->getAsString(Args);
continue;
@@ -721,12 +655,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// Linker input arguments require custom handling. The problem is that we
// have already constructed the phase actions, so we can not treat them as
// "input arguments".
- if (A->getOption().isLinkerInput()) {
+ if (A->getOption().hasFlag(options::LinkerInput)) {
// Convert the argument into individual Zlinker_input_args.
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
DAL->AddSeparateArg(OriginalArg,
Opts.getOption(options::OPT_Zlinker_input),
- A->getValue(Args, i));
+ A->getValue(i));
}
continue;
@@ -749,7 +683,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
case options::OPT_dependency_file:
DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF),
- A->getValue(Args));
+ A->getValue());
break;
case options::OPT_gfull:
@@ -805,8 +739,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// how the driver driver works.
if (BoundArch) {
StringRef Name = BoundArch;
- const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ);
- const Option *MArch = Opts.getOption(options::OPT_march_EQ);
+ const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ);
+ const Option MArch = Opts.getOption(options::OPT_march_EQ);
// This code must be kept in sync with LLVM's getArchTypeForDarwinArch,
// which defines the list of which architectures we accept.
@@ -864,6 +798,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddJoinedArg(0, MArch, "armv6k");
else if (Name == "armv7")
DAL->AddJoinedArg(0, MArch, "armv7a");
+ else if (Name == "armv7f")
+ DAL->AddJoinedArg(0, MArch, "armv7f");
+ else if (Name == "armv7k")
+ DAL->AddJoinedArg(0, MArch, "armv7k");
+ else if (Name == "armv7s")
+ DAL->AddJoinedArg(0, MArch, "armv7s");
else
llvm_unreachable("invalid Darwin arch");
@@ -875,6 +815,25 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
if (BoundArch)
AddDeploymentTarget(*DAL);
+ // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext.
+ // FIXME: It would be far better to avoid inserting those -static arguments,
+ // but we can't check the deployment target in the translation code until
+ // it is set here.
+ if (isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) {
+ for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
+ Arg *A = *it;
+ ++it;
+ if (A->getOption().getID() != options::OPT_mkernel &&
+ A->getOption().getID() != options::OPT_fapple_kext)
+ continue;
+ assert(it != ie && "unexpected argument translation");
+ A = *it;
+ assert(A->getOption().getID() == options::OPT_static &&
+ "missing expected -static argument");
+ it = DAL->getArgs().erase(it);
+ }
+ }
+
// Validate the C++ standard library choice.
CXXStdlibType Type = GetCXXStdlibType(*DAL);
if (Type == ToolChain::CST_Libcxx) {
@@ -882,13 +841,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
StringRef where;
// Complain about targetting iOS < 5.0 in any way.
- if (TargetSimulatorVersionFromDefines != VersionTuple()) {
- if (TargetSimulatorVersionFromDefines < VersionTuple(5, 0))
- where = "iOS 5.0";
- } else if (isTargetIPhoneOS()) {
- if (isIPhoneOSVersionLT(5, 0))
- where = "iOS 5.0";
- }
+ if (isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))
+ where = "iOS 5.0";
if (where != StringRef()) {
getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment)
@@ -900,9 +854,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
}
bool Darwin::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86_64;
}
bool Darwin::UseDwarfDebugFlags() const {
@@ -917,19 +869,17 @@ bool Darwin::UseSjLjExceptions() const {
getTriple().getArch() == llvm::Triple::thumb);
}
-const char *Darwin::GetDefaultRelocationModel() const {
- return "pic";
+bool Darwin::isPICDefault() const {
+ return true;
}
-const char *Darwin::GetForcedPicModel() const {
- if (getArchName() == "x86_64")
- return "pic";
- return 0;
+bool Darwin::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
}
bool Darwin::SupportsProfiling() const {
// Profiling instrumentation is only supported on x86.
- return getArchName() == "i386" || getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64;
}
bool Darwin::SupportsObjCGC() const {
@@ -937,8 +887,10 @@ bool Darwin::SupportsObjCGC() const {
return !isTargetIPhoneOS();
}
-bool Darwin::SupportsObjCARC() const {
- return isTargetIPhoneOS() || !isMacosxVersionLT(10, 6);
+void Darwin::CheckObjCARC() const {
+ if (isTargetIPhoneOS() || !isMacosxVersionLT(10, 6))
+ return;
+ getDriver().Diag(diag::err_arc_unsupported_on_toolchain);
}
std::string
@@ -1013,7 +965,7 @@ bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
static StringRef getGCCToolchainDir(const ArgList &Args) {
const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain);
if (A)
- return A->getValue(Args);
+ return A->getValue();
return GCC_INSTALL_PREFIX;
}
@@ -1072,7 +1024,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
if (!llvm::sys::fs::exists(LibDir))
continue;
for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k)
- ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]);
+ ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
+ CandidateTripleAliases[k]);
}
for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) {
const std::string LibDir
@@ -1081,7 +1034,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
continue;
for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke;
++k)
- ScanLibDirForGCCTriple(TargetArch, LibDir,
+ ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
CandidateMultiarchTripleAliases[k],
/*NeedsMultiarchSuffix=*/true);
}
@@ -1136,7 +1089,10 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
static const char *const MIPSLibDirs[] = { "/lib" };
static const char *const MIPSTriples[] = { "mips-linux-gnu" };
static const char *const MIPSELLibDirs[] = { "/lib" };
- static const char *const MIPSELTriples[] = { "mipsel-linux-gnu" };
+ static const char *const MIPSELTriples[] = {
+ "mipsel-linux-gnu",
+ "mipsel-linux-android"
+ };
static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" };
static const char *const MIPS64Triples[] = { "mips64-linux-gnu" };
@@ -1264,8 +1220,32 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
MultiarchTripleAliases.push_back(MultiarchTriple.str());
}
+// FIXME: There is the same routine in the Tools.cpp.
+static bool hasMipsN32ABIArg(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef("n32"));
+}
+
+static StringRef getTargetMultiarchSuffix(llvm::Triple::ArchType TargetArch,
+ const ArgList &Args) {
+ if (TargetArch == llvm::Triple::x86_64 ||
+ TargetArch == llvm::Triple::ppc64)
+ return "/64";
+
+ if (TargetArch == llvm::Triple::mips64 ||
+ TargetArch == llvm::Triple::mips64el) {
+ if (hasMipsN32ABIArg(Args))
+ return "/n32";
+ else
+ return "/64";
+ }
+
+ return "/32";
+}
+
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
- llvm::Triple::ArchType TargetArch, const std::string &LibDir,
+ llvm::Triple::ArchType TargetArch, const ArgList &Args,
+ const std::string &LibDir,
StringRef CandidateTriple, bool NeedsMultiarchSuffix) {
// There are various different suffixes involving the triple we
// check for. We also record what is necessary to walk from each back
@@ -1274,6 +1254,10 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
"/gcc/" + CandidateTriple.str(),
"/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
+ // The Freescale PPC SDK has the gcc libraries in
+ // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well.
+ "/" + CandidateTriple.str(),
+
// Ubuntu has a strange mis-matched pair of triples that this happens to
// match.
// FIXME: It may be worthwhile to generalize this and look for a second
@@ -1283,6 +1267,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
const std::string InstallSuffixes[] = {
"/../../..",
"/../../../..",
+ "/../..",
"/../../../.."
};
// Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
@@ -1307,11 +1292,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
// *if* there is a subdirectory of the right name with crtbegin.o in it,
// we use that. If not, and if not a multiarch triple, we look for
// crtbegin.o without the subdirectory.
- StringRef MultiarchSuffix
- = (TargetArch == llvm::Triple::x86_64 ||
- TargetArch == llvm::Triple::ppc64 ||
- TargetArch == llvm::Triple::mips64 ||
- TargetArch == llvm::Triple::mips64el) ? "/64" : "/32";
+ StringRef MultiarchSuffix = getTargetMultiarchSuffix(TargetArch, Args);
if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) {
GCCMultiarchSuffix = MultiarchSuffix.str();
} else {
@@ -1392,18 +1373,17 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
}
bool Generic_GCC::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86_64;
}
-const char *Generic_GCC::GetDefaultRelocationModel() const {
- return "static";
+bool Generic_GCC::isPICDefault() const {
+ return false;
}
-const char *Generic_GCC::GetForcedPicModel() const {
- return 0;
+bool Generic_GCC::isPICDefaultForced() const {
+ return false;
}
+
/// Hexagon Toolchain
Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple)
@@ -1457,21 +1437,14 @@ Tool &Hexagon_TC::SelectTool(const Compilation &C,
return *T;
}
-bool Hexagon_TC::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+bool Hexagon_TC::isPICDefault() const {
+ return false;
}
-const char *Hexagon_TC::GetDefaultRelocationModel() const {
- return "static";
+bool Hexagon_TC::isPICDefaultForced() const {
+ return false;
}
-const char *Hexagon_TC::GetForcedPicModel() const {
- return 0;
-} // 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.
@@ -1495,16 +1468,12 @@ bool TCEToolChain::IsMathErrnoDefault() const {
return true;
}
-bool TCEToolChain::IsUnwindTablesDefault() const {
+bool TCEToolChain::isPICDefault() const {
return false;
}
-const char *TCEToolChain::GetDefaultRelocationModel() const {
- return "static";
-}
-
-const char *TCEToolChain::GetForcedPicModel() const {
- return 0;
+bool TCEToolChain::isPICDefaultForced() const {
+ return false;
}
Tool &TCEToolChain::SelectTool(const Compilation &C,
@@ -1613,19 +1582,43 @@ void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
DriverArgs.hasArg(options::OPT_nostdincxx))
return;
- std::string Triple = getTriple().str();
- if (Triple.substr(0, 5) == "amd64")
- Triple.replace(0, 5, "x86_64");
-
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2");
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2/backward");
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2/" + Triple);
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++");
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++/backward");
+ StringRef Triple = getTriple().str();
+ if (Triple.startswith("amd64"))
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++/x86_64" +
+ Triple.substr(5));
+ else
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++/" +
+ Triple);
+ break;
+ }
}
void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-lstdc++");
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lcxxrt");
+ // Include supc++ to provide Unwind until provided by libcxx.
+ CmdArgs.push_back("-lgcc");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back("-lstdc++");
+ break;
+ }
}
/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
@@ -2020,6 +2013,46 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) {
if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str());
}
+static bool isMipsArch(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips ||
+ Arch == llvm::Triple::mipsel ||
+ Arch == llvm::Triple::mips64 ||
+ Arch == llvm::Triple::mips64el;
+}
+
+static bool isMipsR2Arch(llvm::Triple::ArchType Arch,
+ const ArgList &Args) {
+ if (Arch != llvm::Triple::mips &&
+ Arch != llvm::Triple::mipsel)
+ return false;
+
+ Arg *A = Args.getLastArg(options::OPT_march_EQ,
+ options::OPT_mcpu_EQ,
+ options::OPT_mips_CPUs_Group);
+
+ if (!A)
+ return false;
+
+ if (A->getOption().matches(options::OPT_mips_CPUs_Group))
+ return A->getOption().matches(options::OPT_mips32r2);
+
+ return A->getValue() == StringRef("mips32r2");
+}
+
+static StringRef getMultilibDir(const llvm::Triple &Triple,
+ const ArgList &Args) {
+ if (!isMipsArch(Triple.getArch()))
+ return Triple.isArch32Bit() ? "lib32" : "lib64";
+
+ // lib32 directory has a special meaning on MIPS targets.
+ // It contains N32 ABI binaries. Use this folder if produce
+ // code for N32 ABI only.
+ if (hasMipsN32ABIArg(Args))
+ return "lib32";
+
+ return Triple.isArch32Bit() ? "lib" : "lib64";
+}
+
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
llvm::Triple::ArchType Arch = Triple.getArch();
@@ -2043,19 +2076,14 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
- const bool IsMips = Arch == llvm::Triple::mips ||
- Arch == llvm::Triple::mipsel ||
- Arch == llvm::Triple::mips64 ||
- Arch == llvm::Triple::mips64el;
-
- const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI;
+ const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android;
// Do not use 'gnu' hash style for Mips targets because .gnu.hash
// and the MIPS ABI require .dynsym to be sorted in different ways.
// .gnu.hash needs symbols to be grouped by hash code whereas the MIPS
// ABI requires a mapping between the GOT and the symbol table.
// Android loader does not support .gnu.hash.
- if (!IsMips && !IsAndroid) {
+ if (!isMipsArch(Arch) && !IsAndroid) {
if (IsRedhat(Distro) || IsOpenSuse(Distro) ||
(IsUbuntu(Distro) && Distro >= UbuntuMaverick))
ExtraOpts.push_back("--hash-style=gnu");
@@ -2084,16 +2112,23 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// to the link paths.
path_list &Paths = getFilePaths();
- const std::string Multilib = Triple.isArch32Bit() ? "lib32" : "lib64";
+ const std::string Multilib = getMultilibDir(Triple, Args);
const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot);
// Add the multilib suffixed paths where they are available.
if (GCCInstallation.isValid()) {
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath = GCCInstallation.getParentLibPath();
- addPathIfExists((GCCInstallation.getInstallPath() +
- GCCInstallation.getMultiarchSuffix()),
- Paths);
+
+ if (IsAndroid && isMipsR2Arch(Triple.getArch(), Args))
+ addPathIfExists(GCCInstallation.getInstallPath() +
+ GCCInstallation.getMultiarchSuffix() +
+ "/mips-r2",
+ Paths);
+ else
+ addPathIfExists((GCCInstallation.getInstallPath() +
+ GCCInstallation.getMultiarchSuffix()),
+ Paths);
// If the GCC installation we found is inside of the sysroot, we want to
// prefer libraries installed in the parent prefix of the GCC installation.
@@ -2108,6 +2143,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
addPathIfExists(LibPath + "/../" + Multilib, Paths);
}
+ // On Android, libraries in the parent prefix of the GCC installation are
+ // preferred to the ones under sysroot.
+ if (IsAndroid) {
+ addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
+ }
}
addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
@@ -2326,16 +2366,25 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef LibDir = GCCInstallation.getParentLibPath();
StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef Version = GCCInstallation.getVersion().Text;
- if (!addLibStdCXXIncludePaths(LibDir + "/../include/c++/" + Version,
- (GCCInstallation.getTriple().str() +
- GCCInstallation.getMultiarchSuffix()),
- DriverArgs, CC1Args)) {
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+
+ 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.
- addLibStdCXXIncludePaths(InstallDir + "/include/g++-v4",
- (GCCInstallation.getTriple().str() +
- GCCInstallation.getMultiarchSuffix()),
- DriverArgs, CC1Args);
+ InstallDir.str() + "/include/g++-v4",
+ // Android standalone toolchain has C++ headers in yet another place.
+ LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.str(),
+ // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++,
+ // without a subdirectory corresponding to the gcc version.
+ LibDir.str() + "/../include/c++",
+ };
+
+ for (unsigned i = 0; i < llvm::array_lengthof(IncludePathCandidates); ++i) {
+ if (addLibStdCXXIncludePaths(IncludePathCandidates[i], (TripleStr +
+ GCCInstallation.getMultiarchSuffix()),
+ DriverArgs, CC1Args))
+ break;
}
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 95a11beea158..4c267e8a8bfc 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -111,6 +111,7 @@ protected:
SmallVectorImpl<StringRef> &MultiarchTripleAliases);
void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
+ const ArgList &Args,
const std::string &LibDir,
StringRef CandidateTriple,
bool NeedsMultiarchSuffix = false);
@@ -128,8 +129,8 @@ public:
const ActionList &Inputs) const;
virtual bool IsUnwindTablesDefault() const;
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
protected:
/// \name ToolChain Implementation Helper Functions
@@ -155,9 +156,8 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
- virtual bool IsUnwindTablesDefault() const;
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
};
/// Darwin - The base Darwin tool chain.
@@ -185,11 +185,6 @@ private:
/// The OS version we are targeting.
mutable VersionTuple TargetVersion;
-protected:
- // FIXME: Remove this once there is a proper way to detect an ARC runtime
- // for the simulator.
- mutable VersionTuple TargetSimulatorVersionFromDefines;
-
private:
/// The default macosx-version-min of this tool chain; empty until
/// initialized.
@@ -243,9 +238,7 @@ public:
}
bool isTargetMacOS() const {
- return !isTargetIOSSimulator() &&
- !isTargetIPhoneOS() &&
- TargetSimulatorVersionFromDefines == VersionTuple();
+ return !isTargetIOSSimulator() && !isTargetIPhoneOS();
}
bool isTargetInitialized() const { return TargetInitialized; }
@@ -325,6 +318,10 @@ public:
return true;
}
+ virtual bool IsEncodeExtendedBlockSignatureDefault() const {
+ return true;
+ }
+
virtual bool IsObjCNonFragileABIDefault() const {
// Non-fragile ABI is default for everything but i386.
return getTriple().getArch() != llvm::Triple::x86;
@@ -347,14 +344,14 @@ public:
virtual RuntimeLibType GetDefaultRuntimeLibType() const {
return ToolChain::RLT_CompilerRT;
}
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
virtual bool SupportsProfiling() const;
virtual bool SupportsObjCGC() const;
- virtual bool SupportsObjCARC() const;
+ virtual void CheckObjCARC() const;
virtual bool UseDwarfDebugFlags() const;
@@ -365,9 +362,6 @@ public:
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
-private:
- void AddGCCLibexecPath(unsigned darwinVersion);
-
public:
DarwinClang(const Driver &D, const llvm::Triple& Triple);
@@ -399,7 +393,7 @@ public:
std::string ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const;
- virtual const char *GetDefaultRelocationModel() const { return "pic"; }
+ virtual bool isPICDefault() const { return false; };
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
@@ -540,9 +534,8 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
bool IsMathErrnoDefault() const;
- bool IsUnwindTablesDefault() const;
- const char* GetDefaultRelocationModel() const;
- const char* GetForcedPicModel() const;
+ bool isPICDefault() const;
+ bool isPICDefaultForced() const;
private:
mutable llvm::DenseMap<unsigned, Tool*> Tools;
@@ -564,8 +557,8 @@ public:
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index ed67f7b9a1e4..e37959be4efa 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -33,6 +33,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "InputInfo.h"
+#include "SanitizerArgs.h"
#include "ToolChains.h"
using namespace clang::driver;
@@ -93,9 +94,15 @@ static void addDirectoryList(const ArgList &Args,
const char *ArgName,
const char *EnvVar) {
const char *DirList = ::getenv(EnvVar);
+ bool CombinedArg = false;
+
if (!DirList)
return; // Nothing to do.
+ StringRef Name(ArgName);
+ if (Name.equals("-I") || Name.equals("-L"))
+ CombinedArg = true;
+
StringRef Dirs(DirList);
if (Dirs.empty()) // Empty string should not add '.'.
return;
@@ -103,21 +110,37 @@ static void addDirectoryList(const ArgList &Args,
StringRef::size_type Delim;
while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) {
if (Delim == 0) { // Leading colon.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ }
} else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim)));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ }
}
Dirs = Dirs.substr(Delim + 1);
}
if (Dirs.empty()) { // Trailing colon.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ }
} else { // Add the last path.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs));
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs));
+ }
}
}
@@ -200,6 +223,12 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(ProfileRT));
}
+static bool forwardToGCC(const Option &O) {
+ return !O.hasFlag(options::NoForward) &&
+ !O.hasFlag(options::DriverOption) &&
+ !O.hasFlag(options::LinkerInput);
+}
+
void Clang::AddPreprocessingOptions(Compilation &C,
const Driver &D,
const ArgList &Args,
@@ -219,11 +248,11 @@ void Clang::AddPreprocessingOptions(Compilation &C,
(A = Args.getLastArg(options::OPT_MMD))) {
// Determine the output location.
const char *DepFile;
- if (Output.getType() == types::TY_Dependencies) {
- DepFile = Output.getFilename();
- } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
- DepFile = MF->getValue(Args);
+ if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
+ DepFile = MF->getValue();
C.addFailureResultFile(DepFile);
+ } 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 = "-";
@@ -242,7 +271,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
// when we are only generating a dependency file.
Arg *OutputOpt = Args.getLastArg(options::OPT_o);
if (OutputOpt && Output.getType() != types::TY_Dependencies) {
- DepTarget = OutputOpt->getValue(Args);
+ DepTarget = OutputOpt->getValue();
} else {
// Otherwise derive from the base input.
//
@@ -282,7 +311,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
if (A->getOption().matches(options::OPT_MQ)) {
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(A->getValue(Args), Quoted);
+ QuoteTarget(A->getValue(), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
// -MT flag - no change
@@ -310,7 +339,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
bool FoundPTH = false;
bool FoundPCH = false;
- llvm::sys::Path P(A->getValue(Args));
+ llvm::sys::Path P(A->getValue());
bool Exists;
if (UsePCH) {
P.appendSuffix("pch");
@@ -442,10 +471,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", "v7")
+ .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
.Case("cortex-m3", "v7m")
.Case("cortex-m4", "v7m")
.Case("cortex-m0", "v6m")
+ .Case("cortex-a9-mp", "v7f")
+ .Case("swift", "v7s")
.Default("");
}
@@ -458,7 +489,7 @@ static std::string getARMTargetCPU(const ArgList &Args,
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef MCPU = A->getValue(Args);
+ StringRef MCPU = A->getValue();
// Handle -mcpu=native.
if (MCPU == "native")
return llvm::sys::getHostCPUName();
@@ -469,7 +500,7 @@ static std::string getARMTargetCPU(const ArgList &Args,
StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
- MArch = A->getValue(Args);
+ MArch = A->getValue();
} else {
// Otherwise, use the Arch from the triple.
MArch = Triple.getArchName();
@@ -500,6 +531,8 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
.Cases("armv7", "armv7a", "armv7-a", "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")
.Case("ep9312", "ep9312")
@@ -531,7 +564,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
// frontend target.
static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args,
ArgStringList &CmdArgs) {
- StringRef FPU = A->getValue(Args);
+ StringRef FPU = A->getValue();
// Set the target features based on the FPU.
if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
@@ -569,14 +602,15 @@ static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args,
// Handle -mfpmath=.
static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
ArgStringList &CmdArgs, StringRef CPU) {
- StringRef FPMath = A->getValue(Args);
+ StringRef FPMath = A->getValue();
// Set the target features based on the FPMath.
if (FPMath == "neon") {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+neonfp");
- if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp")
+ if (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" ||
@@ -603,7 +637,7 @@ static StringRef getARMFloatABI(const Driver &D,
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
else {
- FloatABI = A->getValue(Args);
+ FloatABI = A->getValue();
if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") {
D.Diag(diag::err_drv_invalid_mfloat_abi)
<< A->getAsString(Args);
@@ -643,7 +677,7 @@ static StringRef getARMFloatABI(const Driver &D,
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
break;
- case llvm::Triple::ANDROIDEABI: {
+ case llvm::Triple::Android: {
std::string ArchName =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
if (StringRef(ArchName).startswith("v7"))
@@ -669,18 +703,29 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs,
bool KernelOrKext) const {
const Driver &D = getToolChain().getDriver();
- llvm::Triple Triple = getToolChain().getTriple();
+ // Get the effective triple, which takes into account the deployment target.
+ std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
+ llvm::Triple Triple(TripleStr);
+ std::string CPUName = getARMTargetCPU(Args, Triple);
// Select the ABI to use.
//
// FIXME: Support -meabi.
const char *ABIName = 0;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
- ABIName = A->getValue(Args);
+ ABIName = A->getValue();
+ } else if (Triple.isOSDarwin()) {
+ // The backend is hardwired to assume AAPCS for M-class processors, ensure
+ // the frontend matches that.
+ if (StringRef(CPUName).startswith("cortex-m")) {
+ ABIName = "aapcs";
+ } else {
+ ABIName = "apcs-gnu";
+ }
} else {
// Select the default based on the platform.
switch(Triple.getEnvironment()) {
- case llvm::Triple::ANDROIDEABI:
+ case llvm::Triple::Android:
case llvm::Triple::GNUEABI:
case llvm::Triple::GNUEABIHF:
ABIName = "aapcs-linux";
@@ -697,7 +742,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Set the CPU based on -march= and -mcpu=.
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(getARMTargetCPU(Args, Triple)));
+ CmdArgs.push_back(Args.MakeArgString(CPUName));
// Determine floating point ABI from the options & target defaults.
StringRef FloatABI = getARMFloatABI(D, Args, Triple);
@@ -754,8 +799,10 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-long-calls");
+ if (Triple.getOS() != llvm::Triple::IOS || Triple.isOSVersionLT(6)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-long-calls");
+ }
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-strict-align");
@@ -777,44 +824,18 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-no-implicit-float");
}
-// Get default architecture.
-static const char* getMipsArchFromCPU(StringRef CPUName) {
- if (CPUName == "mips32" || CPUName == "mips32r2")
- return "mips";
-
- assert((CPUName == "mips64" || CPUName == "mips64r2") &&
- "Unexpected cpu name.");
-
- return "mips64";
-}
-
-// Check that ArchName is a known Mips architecture name.
-static bool checkMipsArchName(StringRef ArchName) {
- return ArchName == "mips" ||
- ArchName == "mipsel" ||
- ArchName == "mips64" ||
- ArchName == "mips64el";
-}
-
-// Get default target cpu.
-static const char* getMipsCPUFromArch(StringRef ArchName) {
- if (ArchName == "mips" || ArchName == "mipsel")
+// Translate MIPS CPU name alias option to CPU name.
+static StringRef getMipsCPUFromAlias(const Arg &A) {
+ if (A.getOption().matches(options::OPT_mips32))
return "mips32";
-
- assert((ArchName == "mips64" || ArchName == "mips64el") &&
- "Unexpected arch name.");
-
- return "mips64";
-}
-
-// Get default ABI.
-static const char* getMipsABIFromArch(StringRef ArchName) {
- if (ArchName == "mips" || ArchName == "mipsel")
- return "o32";
-
- assert((ArchName == "mips64" || ArchName == "mips64el") &&
- "Unexpected arch name.");
- return "n64";
+ if (A.getOption().matches(options::OPT_mips32r2))
+ return "mips32r2";
+ if (A.getOption().matches(options::OPT_mips64))
+ return "mips64";
+ if (A.getOption().matches(options::OPT_mips64r2))
+ return "mips64r2";
+ llvm_unreachable("Unexpected option");
+ return "";
}
// Get CPU and ABI names. They are not independent
@@ -823,26 +844,53 @@ static void getMipsCPUAndABI(const ArgList &Args,
const ToolChain &TC,
StringRef &CPUName,
StringRef &ABIName) {
- StringRef ArchName;
-
- // Select target cpu and architecture.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- CPUName = A->getValue(Args);
- ArchName = getMipsArchFromCPU(CPUName);
- }
- else {
- ArchName = Args.MakeArgString(TC.getArchName());
- if (!checkMipsArchName(ArchName))
- TC.getDriver().Diag(diag::err_drv_invalid_arch_name) << ArchName;
+ const char *DefMips32CPU = "mips32";
+ const char *DefMips64CPU = "mips64";
+
+ if (Arg *A = Args.getLastArg(options::OPT_march_EQ,
+ options::OPT_mcpu_EQ,
+ options::OPT_mips_CPUs_Group)) {
+ if (A->getOption().matches(options::OPT_mips_CPUs_Group))
+ CPUName = getMipsCPUFromAlias(*A);
else
- CPUName = getMipsCPUFromArch(ArchName);
+ CPUName = A->getValue();
}
-
- // Select the ABI to use.
+
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
- ABIName = A->getValue(Args);
- else
- ABIName = getMipsABIFromArch(ArchName);
+ ABIName = A->getValue();
+
+ // Setup default CPU and ABI names.
+ if (CPUName.empty() && ABIName.empty()) {
+ switch (TC.getTriple().getArch()) {
+ default:
+ llvm_unreachable("Unexpected triple arch name");
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ CPUName = DefMips32CPU;
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ CPUName = DefMips64CPU;
+ break;
+ }
+ }
+
+ if (!ABIName.empty()) {
+ // Deduce CPU name from ABI name.
+ CPUName = llvm::StringSwitch<const char *>(ABIName)
+ .Cases("o32", "eabi", DefMips32CPU)
+ .Cases("n32", "n64", DefMips64CPU)
+ .Default("");
+ }
+ else if (!CPUName.empty()) {
+ // Deduce ABI name from CPU name.
+ ABIName = llvm::StringSwitch<const char *>(CPUName)
+ .Cases("mips32", "mips32r2", "o32")
+ .Cases("mips64", "mips64r2", "n64")
+ .Default("");
+ }
+
+ // FIXME: Warn on inconsistent cpu and abi usage.
}
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
@@ -859,7 +907,7 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) {
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
else {
- FloatABI = A->getValue(Args);
+ FloatABI = A->getValue();
if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") {
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
FloatABI = "hard";
@@ -941,12 +989,19 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
AddTargetFeature(Args, CmdArgs,
options::OPT_mdspr2, options::OPT_mno_dspr2,
"dspr2");
+
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v));
+ A->claim();
+ }
}
/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
static std::string getPPCTargetCPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPUName = A->getValue(Args);
+ StringRef CPUName = A->getValue();
if (CPUName == "native") {
std::string CPU = llvm::sys::getHostCPUName();
@@ -978,6 +1033,8 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("970", "970")
.Case("G5", "g5")
.Case("a2", "a2")
+ .Case("e500mc", "e500mc")
+ .Case("e5500", "e5500")
.Case("power6", "pwr6")
.Case("power7", "pwr7")
.Case("powerpc", "ppc")
@@ -1015,7 +1072,7 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -1054,6 +1111,8 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
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) ||
@@ -1068,7 +1127,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue(Args)) == "native") {
+ if (StringRef(A->getValue()) == "native") {
// FIXME: Reject attempts to use -march=native unless the target matches
// the host.
//
@@ -1078,7 +1137,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (!CPU.empty() && CPU != "generic")
CPUName = Args.MakeArgString(CPU);
} else
- CPUName = A->getValue(Args);
+ CPUName = A->getValue();
}
// Select the default CPU if none was given (or detection failed).
@@ -1118,7 +1177,9 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "pentium4";
+ // All x86 devices running Android have core2 as their common
+ // denominator. This makes a better choice than pentium4.
+ CPUName = isAndroid ? "core2" : "pentium4";
}
}
@@ -1141,8 +1202,8 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
(*it)->claim();
// Skip over "-m".
- assert(Name.startswith("-m") && "Invalid feature name.");
- Name = Name.substr(2);
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
bool IsNegative = Name.startswith("no-");
if (IsNegative)
@@ -1174,7 +1235,7 @@ static Arg* getLastHexagonArchArg (const ArgList &Args)
A->claim();
}
else if ((*it)->getOption().matches(options::OPT_m_Joined)){
- StringRef Value = (*it)->getValue(Args,0);
+ StringRef Value = (*it)->getValue(0);
if (Value.startswith("v")) {
A = *it;
A->claim();
@@ -1191,7 +1252,7 @@ static StringRef getHexagonTargetCPU(const ArgList &Args)
// Select the default CPU (v4) if none was given or detection failed.
if ((A = getLastHexagonArchArg (Args))) {
- WhichHexagon = A->getValue(Args);
+ WhichHexagon = A->getValue();
if (WhichHexagon == "")
return "v4";
else
@@ -1216,7 +1277,7 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_G,
options::OPT_msmall_data_threshold_EQ)) {
std::string SmallDataThreshold="-small-data-threshold=";
- SmallDataThreshold += A->getValue(Args);
+ SmallDataThreshold += A->getValue();
CmdArgs.push_back ("-mllvm");
CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
A->claim();
@@ -1392,25 +1453,80 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
+SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
+ Kind = 0;
+
+ const Arg *AsanArg, *TsanArg, *UbsanArg;
+ 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 {
+ continue;
+ }
+
+ (*I)->claim();
+
+ Kind |= Add;
+ Kind &= ~Remove;
+
+ if (Add & NeedsAsanRt) AsanArg = *I;
+ if (Add & NeedsTsanRt) TsanArg = *I;
+ if (Add & NeedsUbsanRt) UbsanArg = *I;
+
+ // 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;
+ }
+
+ // 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)
+ 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);
+}
+
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- if (!Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false))
- return;
- if(TC.getTriple().getEnvironment() == llvm::Triple::ANDROIDEABI) {
+ if(TC.getTriple().getEnvironment() == llvm::Triple::Android) {
if (!Args.hasArg(options::OPT_shared)) {
if (!Args.hasArg(options::OPT_pie))
TC.getDriver().Diag(diag::err_drv_asan_android_requires_pie);
- // For an executable, we add a .preinit_array stub.
- CmdArgs.push_back("-u");
- CmdArgs.push_back("__asan_preinit");
- CmdArgs.push_back("-lasan");
}
- CmdArgs.push_back("-lasan_preload");
- CmdArgs.push_back("-ldl");
+ SmallString<128> LibAsan(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(LibAsan, "lib", "linux",
+ (Twine("libclang_rt.asan-") +
+ TC.getArchName() + "-android.so"));
+ CmdArgs.push_back(Args.MakeArgString(LibAsan));
} else {
if (!Args.hasArg(options::OPT_shared)) {
// LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library
@@ -1431,9 +1547,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
/// This needs to be called before we add the C run-time (malloc, etc).
static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- if (!Args.hasFlag(options::OPT_fthread_sanitizer,
- options::OPT_fno_thread_sanitizer, false))
- return;
if (!Args.hasArg(options::OPT_shared)) {
// LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library
// resource directory.
@@ -1448,6 +1561,22 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
}
}
+/// 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");
+ }
+}
+
static bool shouldUseFramePointer(const ArgList &Args,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
@@ -1516,7 +1645,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
- StringRef Value = A->getValue(Args, i);
+ StringRef Value = A->getValue(i);
if (Value == "-force_cpusubtype_ALL") {
// Do nothing, this is the default and we don't support anything else.
@@ -1600,8 +1729,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-analyzer-eagerly-assume");
- CmdArgs.push_back("-analyzer-ipa=inlining");
-
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
@@ -1627,7 +1754,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// reasons.
CmdArgs.push_back("-analyzer-output");
if (Arg *A = Args.getLastArg(options::OPT__analyzer_output))
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("plist");
@@ -1642,67 +1769,90 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CheckCodeGenerationOptions(D, Args);
- // Perform argument translation for LLVM backend. This
- // takes some care in reconciling with llvm-gcc. The
- // issue is that llvm-gcc translates these options based on
- // the values in cc1, whereas we are processing based on
- // the driver arguments.
-
- // This comes from the default translation the driver + cc1
- // would do to enable flag_pic.
-
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic,
- options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- bool PICDisabled = false;
- bool PICEnabled = false;
- bool PICForPIE = false;
- if (LastPICArg) {
- PICForPIE = (LastPICArg->getOption().matches(options::OPT_fPIE) ||
- LastPICArg->getOption().matches(options::OPT_fpie));
- PICEnabled = (PICForPIE ||
- LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic));
- PICDisabled = !PICEnabled;
+ // For the PIC and PIE flag options, this logic is different from the legacy
+ // logic in very old versions of GCC, as that logic was just a bug no one had
+ // ever fixed. This logic is both more rational and consistent with GCC's new
+ // logic now that the bugs are fixed. The last argument relating to either
+ // PIC or PIE wins, and no other argument is used. If the last argument is
+ // any flavor of the '-fno-...' arguments, both PIC and PIE are disabled. Any
+ // PIE option implicitly enables PIC at the same level.
+ bool PIE = false;
+ bool PIC = getToolChain().isPICDefault();
+ bool IsPICLevelTwo = PIC;
+ if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie)) {
+ Option O = A->getOption();
+ if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
+ O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) {
+ PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie);
+ PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic);
+ IsPICLevelTwo = O.matches(options::OPT_fPIE) ||
+ O.matches(options::OPT_fPIC);
+ } else {
+ PIE = PIC = false;
+ }
}
+ // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness
+ // is forced, then neither PIC nor PIE flags will have no effect.
+ if (getToolChain().isPICDefaultForced()) {
+ PIE = false;
+ PIC = getToolChain().isPICDefault();
+ IsPICLevelTwo = PIC;
+ }
+
+ // Inroduce a Darwin-specific hack. If the default is PIC but the flags
+ // specified while enabling PIC enabled level 1 PIC, just force it back to
+ // level 2 PIC instead. This matches the behavior of Darwin GCC (based on my
+ // informal testing).
+ if (PIC && getToolChain().getTriple().isOSDarwin())
+ IsPICLevelTwo |= getToolChain().isPICDefault();
+
// 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.
- if (Args.hasArg(options::OPT_mkernel))
- PICDisabled = true;
+ llvm::Triple Triple(TripleStr);
+ if ((Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext)) &&
+ (Triple.getOS() != llvm::Triple::IOS ||
+ Triple.isOSVersionLT(6)))
+ PIC = PIE = false;
if (Args.hasArg(options::OPT_static))
- PICDisabled = true;
- bool DynamicNoPIC = Args.hasArg(options::OPT_mdynamic_no_pic);
-
- // Select the relocation model.
- const char *Model = getToolChain().GetForcedPicModel();
- if (!Model) {
- if (DynamicNoPIC)
- Model = "dynamic-no-pic";
- else if (PICDisabled)
- Model = "static";
- else if (PICEnabled)
- Model = "pic";
- else
- Model = getToolChain().GetDefaultRelocationModel();
- }
- StringRef ModelStr = Model ? Model : "";
- if (Model && ModelStr != "pic") {
- CmdArgs.push_back("-mrelocation-model");
- CmdArgs.push_back(Model);
- }
+ PIC = PIE = false;
- // Infer the __PIC__ and __PIE__ values.
- if (ModelStr == "pic" && PICForPIE) {
- CmdArgs.push_back("-pie-level");
- CmdArgs.push_back((LastPICArg &&
- LastPICArg->getOption().matches(options::OPT_fPIE)) ?
- "2" : "1");
- } else if (ModelStr == "pic" || ModelStr == "dynamic-no-pic") {
- CmdArgs.push_back("-pic-level");
- CmdArgs.push_back(((ModelStr != "dynamic-no-pic" && LastPICArg &&
- LastPICArg->getOption().matches(options::OPT_fPIC)) ||
- getToolChain().getTriple().isOSDarwin()) ? "2" : "1");
+ if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
+ // This is a very special mode. It trumps the other modes, almost no one
+ // uses it, and it isn't even valid on any OS but Darwin.
+ if (!getToolChain().getTriple().isOSDarwin())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << getToolChain().getTriple().str();
+
+ // FIXME: Warn when this flag trumps some other PIC or PIE flag.
+
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back("dynamic-no-pic");
+
+ // Only a forced PIC mode can cause the actual compile to have PIC defines
+ // etc., no flags are sufficient. This behavior was selected to closely
+ // match that of llvm-gcc and Apple GCC before that.
+ if (getToolChain().isPICDefault() && getToolChain().isPICDefaultForced()) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back("2");
+ }
+ } else {
+ // Currently, LLVM only knows about PIC vs. static; the PIE differences are
+ // handled in Clang's IRGen by the -pie-level flag.
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(PIC ? "pic" : "static");
+
+ if (PIC) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(IsPICLevelTwo ? "2" : "1");
+ if (PIE) {
+ CmdArgs.push_back("-pie-level");
+ CmdArgs.push_back(IsPICLevelTwo ? "2" : "1");
+ }
+ }
}
if (!Args.hasFlag(options::OPT_fmerge_all_constants,
@@ -1713,7 +1863,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
CmdArgs.push_back("-mregparm");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
@@ -1741,25 +1891,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// flag disables them after the flag enabling them, enable the codegen
// optimization. This is complicated by several "umbrella" flags.
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_ffinite_math_only,
options::OPT_fno_finite_math_only,
options::OPT_fhonor_infinities,
options::OPT_fno_honor_infinities))
- if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_finite_math_only &&
A->getOption().getID() != options::OPT_fhonor_infinities)
CmdArgs.push_back("-menable-no-infs");
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_ffinite_math_only,
options::OPT_fno_finite_math_only,
options::OPT_fhonor_nans,
options::OPT_fno_honor_nans))
- if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_finite_math_only &&
A->getOption().getID() != options::OPT_fhonor_nans)
CmdArgs.push_back("-menable-no-nans");
// -fmath-errno is the default on some platforms, e.g. BSD-derived OSes.
bool MathErrno = getToolChain().IsMathErrnoDefault();
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_fmath_errno,
options::OPT_fno_math_errno))
MathErrno = A->getOption().getID() == options::OPT_fmath_errno;
@@ -1772,38 +1927,46 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// madness.
bool AssociativeMath = false;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_fassociative_math,
options::OPT_fno_associative_math))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_fno_associative_math)
AssociativeMath = true;
bool ReciprocalMath = false;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_freciprocal_math,
options::OPT_fno_reciprocal_math))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_fno_reciprocal_math)
ReciprocalMath = true;
bool SignedZeros = true;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_fsigned_zeros,
options::OPT_fno_signed_zeros))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_fsigned_zeros)
SignedZeros = false;
bool TrappingMath = true;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_ftrapping_math,
options::OPT_fno_trapping_math))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_ftrapping_math)
TrappingMath = false;
if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
@@ -1813,16 +1976,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Validate and pass through -fp-contract option.
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_ffp_contract)) {
if (A->getOption().getID() == options::OPT_ffp_contract) {
- StringRef Val = A->getValue(Args);
+ StringRef Val = A->getValue();
if (Val == "fast" || Val == "on" || Val == "off") {
CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
}
- } else { // A is OPT_ffast_math
+ } else if (A->getOption().getID() == options::OPT_ffast_math) {
// If fast-math is set then set the fp-contract mode to fast.
CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast"));
}
@@ -1833,10 +1997,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// preprocessor macros. This is distinct from enabling any optimizations as
// these options induce language changes which must survive serialization
// and deserialization, etc.
- if (Args.hasArg(options::OPT_ffast_math))
- CmdArgs.push_back("-ffast-math");
- if (Args.hasArg(options::OPT_ffinite_math_only))
- CmdArgs.push_back("-ffinite-math-only");
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math))
+ if (A->getOption().matches(options::OPT_ffast_math))
+ CmdArgs.push_back("-ffast-math");
+ if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math))
+ if (A->getOption().matches(options::OPT_ffinite_math_only))
+ CmdArgs.push_back("-ffinite-math-only");
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
@@ -1885,7 +2051,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// FIXME: Handle -mtune=.
@@ -1893,7 +2059,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
CmdArgs.push_back("-mcode-model");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// Add target specific cpu and features flags.
@@ -1937,7 +2103,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Pass the linker version in use.
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
CmdArgs.push_back("-target-linker-version");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// -mno-omit-leaf-frame-pointer is the default on Darwin.
@@ -1991,6 +2157,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
Args.ClaimAllArgs(options::OPT_g_flags_Group);
+ if (Args.hasArg(options::OPT_gcolumn_info))
+ CmdArgs.push_back("-dwarf-column-info");
Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
@@ -2008,7 +2176,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
C.getArgs().hasArg(options::OPT_S)) {
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-file");
- CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+ SmallString<128> absFilename(Output.getFilename());
+ llvm::sys::fs::make_absolute(absFilename);
+ CmdArgs.push_back(Args.MakeArgString(absFilename));
}
}
@@ -2047,7 +2217,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case options::OPT_ccc_arcmt_migrate:
CmdArgs.push_back("-arcmt-migrate");
CmdArgs.push_back("-mt-migrate-directory");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
@@ -2062,7 +2232,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
<< A->getAsString(Args) << "-ccc-arcmt-migrate";
}
CmdArgs.push_back("-mt-migrate-directory");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
options::OPT_objcmt_migrate_subscripting)) {
@@ -2094,7 +2264,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (A->getOption().matches(options::OPT_O4))
CmdArgs.push_back("-O3");
else if (A->getOption().matches(options::OPT_O) &&
- A->getValue(Args)[0] == '\0')
+ A->getValue()[0] == '\0')
CmdArgs.push_back("-O2");
else
A->render(Args, CmdArgs);
@@ -2132,8 +2302,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// eventually we want to do all the standard defaulting here instead of
// splitting it between the driver and clang -cc1.
if (!types::isCXX(InputType))
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
+ else if (getToolChain().getTriple().getOS() == llvm::Triple::Win32)
+ CmdArgs.push_back("-std=c++11");
+
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
@@ -2182,18 +2355,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
options::OPT_ftemplate_depth_EQ)) {
CmdArgs.push_back("-ftemplate-depth");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
CmdArgs.push_back("-fconstexpr-depth");
- CmdArgs.push_back(A->getValue(Args));
+ 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()) {
- StringRef bytes = A->getValue(Args);
+ StringRef bytes = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
} else
CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
@@ -2202,50 +2375,50 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fbounds_checking,
options::OPT_fbounds_checking_EQ)) {
if (A->getNumValues()) {
- StringRef val = A->getValue(Args);
+ 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))
+ if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
CmdArgs.push_back("-fconstant-string-class");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
CmdArgs.push_back("-ftabstop");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
CmdArgs.push_back("-ferror-limit");
if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("19");
if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
CmdArgs.push_back("-fmacro-backtrace-limit");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
CmdArgs.push_back("-ftemplate-backtrace-limit");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
CmdArgs.push_back("-fconstexpr-backtrace-limit");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
} else {
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
@@ -2255,7 +2428,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) {
CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
@@ -2268,7 +2441,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-ffreestanding");
// Forward -f (flag) options which we can pass directly.
- Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
@@ -2278,6 +2450,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
+ SanitizerArgs Sanitize(D, Args);
+ Sanitize.addArgs(Args, CmdArgs);
+
// Report and error for -faltivec on anything other then PowerPC.
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
@@ -2288,14 +2463,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
- if (Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false))
- CmdArgs.push_back("-faddress-sanitizer");
-
- if (Args.hasFlag(options::OPT_fthread_sanitizer,
- options::OPT_fno_thread_sanitizer, false))
- CmdArgs.push_back("-fthread-sanitizer");
-
// -flax-vector-conversions is default.
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
options::OPT_fno_lax_vector_conversions))
@@ -2316,7 +2483,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
CmdArgs.push_back("-ftrapv-handler");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
@@ -2337,6 +2504,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_pthread);
+
// -stack-protector=0 is default.
unsigned StackProtectorLevel = 0;
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
@@ -2355,6 +2523,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel)));
}
+ // --param ssp-buffer-size=
+ for (arg_iterator it = Args.filtered_begin(options::OPT__param),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ StringRef Str((*it)->getValue());
+ if (Str.startswith("ssp-buffer-size=")) {
+ if (StackProtectorLevel) {
+ CmdArgs.push_back("-stack-protector-buffer-size");
+ // FIXME: Verify the argument is a valid integer.
+ CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16)));
+ }
+ (*it)->claim();
+ }
+ }
+
// Translate -mstackrealign
if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
false)) {
@@ -2370,6 +2552,10 @@ 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)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-strict-align");
+ }
// Forward -f options with positive and negative forms; we translate
// these by hand.
@@ -2427,9 +2613,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti) ||
- KernelOrKext)
+ KernelOrKext) {
CmdArgs.push_back("-fno-rtti");
+ // -fno-rtti cannot usefully be combined with -fsanitize=vptr.
+ if (Sanitize.sanitizesVptr()) {
+ std::string NoRttiArg =
+ Args.getLastArg(options::OPT_mkernel,
+ options::OPT_fapple_kext,
+ options::OPT_fno_rtti)->getAsString(Args);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=vptr" << NoRttiArg;
+ }
+ }
+
// -fshort-enums=0 is default for all architectures except Hexagon.
if (Args.hasFlag(options::OPT_fshort_enums,
options::OPT_fno_short_enums,
@@ -2537,12 +2734,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fobjc-default-synthesize-properties");
}
+ // -fencode-extended-block-signature=1 is default.
+ if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) {
+ CmdArgs.push_back("-fencode-extended-block-signature");
+ }
+
// Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
// NOTE: This logic is duplicated in ToolChains.cpp.
bool ARC = isObjCAutoRefCount(Args);
if (ARC) {
- if (!getToolChain().SupportsObjCARC())
- D.Diag(diag::err_arc_unsupported);
+ getToolChain().CheckObjCARC();
CmdArgs.push_back("-fobjc-arc");
@@ -2629,7 +2830,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fno-pack-struct doesn't apply to -fpack-struct=.
if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
std::string PackStructStr = "-fpack-struct=";
- PackStructStr += A->getValue(Args);
+ PackStructStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(PackStructStr));
} else if (Args.hasFlag(options::OPT_fpack_struct,
options::OPT_fno_pack_struct, false)) {
@@ -2678,13 +2879,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
CmdArgs.push_back("-fdiagnostics-show-category");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(
@@ -2776,9 +2977,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Handle serialized diagnostics.
if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
CmdArgs.push_back("-serialize-diagnostic-file");
- CmdArgs.push_back(Args.MakeArgString(A->getValue(Args)));
+ CmdArgs.push_back(Args.MakeArgString(A->getValue()));
}
+ if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
+ CmdArgs.push_back("-fretain-comments-from-system-headers");
+
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
@@ -2788,7 +2992,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We translate this by hand to the -cc1 argument, since nightly test uses
// it and developers have been trained to spell it with -mllvm.
- if (StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns")
+ if (StringRef((*it)->getValue(0)) == "-disable-llvm-optzns")
CmdArgs.push_back("-disable-llvm-optzns");
else
(*it)->render(Args, CmdArgs);
@@ -2807,7 +3011,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
const InputInfo &II = *it;
CmdArgs.push_back("-x");
- CmdArgs.push_back(types::getTypeName(II.getType()));
+ if (Args.hasArg(options::OPT_rewrite_objc))
+ CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
+ else
+ CmdArgs.push_back(types::getTypeName(II.getType()));
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else
@@ -2894,7 +3101,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if (runtimeArg &&
runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) {
ObjCRuntime runtime;
- StringRef value = runtimeArg->getValue(args);
+ StringRef value = runtimeArg->getValue();
if (runtime.tryParse(value)) {
getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime)
<< value;
@@ -2912,7 +3119,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
unsigned objcABIVersion = 1;
// If -fobjc-abi-version= is present, use that to set the version.
if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
- StringRef value = abiArg->getValue(args);
+ StringRef value = abiArg->getValue();
if (value == "1")
objcABIVersion = 1;
else if (value == "2")
@@ -2940,7 +3147,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if (Arg *abiArg = args.getLastArg(
options::OPT_fobjc_nonfragile_abi_version_EQ)) {
- StringRef value = abiArg->getValue(args);
+ StringRef value = abiArg->getValue();
if (value == "1")
nonFragileABIVersion = 1;
else if (value == "2")
@@ -2993,7 +3200,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
// Legacy behaviour is to target the gnustep runtime if we are i
// non-fragile mode or the GCC runtime in fragile mode.
if (isNonFragile)
- runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple());
+ runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1,6));
else
runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple());
}
@@ -3116,7 +3323,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
Arg *A = *it;
- if (A->getOption().hasForwardToGCC()) {
+ if (forwardToGCC(A->getOption())) {
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
A->getOption().matches(options::OPT_g_Group))
@@ -3134,17 +3341,17 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
RenderExtraToolArgs(JA, CmdArgs);
// If using a driver driver, force the arch.
- const std::string &Arch = getToolChain().getArchName();
+ llvm::Triple::ArchType Arch = getToolChain().getArch();
if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
// FIXME: Remove these special cases.
- if (Arch == "powerpc")
+ if (Arch == llvm::Triple::ppc)
CmdArgs.push_back("ppc");
- else if (Arch == "powerpc64")
+ else if (Arch == llvm::Triple::ppc64)
CmdArgs.push_back("ppc64");
else
- CmdArgs.push_back(Args.MakeArgString(Arch));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName()));
}
// Try to force gcc to match the tool chain we want, if we recognize
@@ -3152,9 +3359,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: The triple class should directly provide the information we want
// here.
- if (Arch == "i386" || Arch == "powerpc")
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
CmdArgs.push_back("-m32");
- else if (Arch == "x86_64" || Arch == "powerpc64")
+ else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86_64)
CmdArgs.push_back("-m64");
if (Output.isFilename()) {
@@ -3341,7 +3548,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
Arg *A = *it;
- if (A->getOption().hasForwardToGCC()) {
+ if (forwardToGCC(A->getOption())) {
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
A->getOption().matches(options::OPT_g_Group))
@@ -3409,6 +3616,37 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// Hexagon tools end.
+llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
+ // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for
+ // archs which Darwin doesn't use.
+
+ // The matching this routine does is fairly pointless, since it is neither the
+ // complete architecture list, nor a reasonable subset. The problem is that
+ // historically the driver driver accepts this and also ties its -march=
+ // handling to the architecture name, so we need to be careful before removing
+ // support for it.
+
+ // This code must be kept in sync with Clang's Darwin specific argument
+ // translation.
+
+ return llvm::StringSwitch<llvm::Triple::ArchType>(Str)
+ .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc)
+ .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc)
+ .Case("ppc64", llvm::Triple::ppc64)
+ .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86)
+ .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
+ 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)
+ .Case("r600", llvm::Triple::r600)
+ .Case("nvptx", llvm::Triple::nvptx)
+ .Case("nvptx64", llvm::Triple::nvptx64)
+ .Case("amdil", llvm::Triple::amdil)
+ .Case("spir", llvm::Triple::spir)
+ .Default(llvm::Triple::UnknownArch);
+}
const char *darwin::CC1::getCC1Name(types::ID Type) const {
switch (Type) {
@@ -3457,7 +3695,7 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
std::string Res;
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
- std::string Str(OutputOpt->getValue(Args));
+ std::string Str(OutputOpt->getValue());
Res = Str.substr(0, Str.rfind('.'));
} else {
Res = darwin::CC1::getBaseInputStem(Args, Inputs);
@@ -3546,6 +3784,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
.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)
@@ -3555,6 +3794,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
.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)
@@ -3619,7 +3859,10 @@ void darwin::CC1::AddCC1Args(const ArgList &Args,
CheckCodeGenerationOptions(D, Args);
// Derived from cc1 spec.
- if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) &&
+ 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");
@@ -3672,7 +3915,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
Args.hasArg(options::OPT_o)) {
Arg *OutputOpt = Args.getLastArg(options::OPT_o);
CmdArgs.push_back("-auxbase-strip");
- CmdArgs.push_back(OutputOpt->getValue(Args));
+ CmdArgs.push_back(OutputOpt->getValue());
} else {
CmdArgs.push_back("-auxbase");
CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs));
@@ -3811,7 +4054,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
Args.AddLastArg(CmdArgs, options::OPT_P);
// FIXME: Handle %I properly.
- if (getToolChain().getArchName() == "x86_64") {
+ if (getToolChain().getArch() == llvm::Triple::x86_64) {
CmdArgs.push_back("-imultilib");
CmdArgs.push_back("x86_64");
}
@@ -3837,7 +4080,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
(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));
+ CmdArgs.push_back(OutputOpt->getValue());
}
}
@@ -4073,9 +4316,11 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-force_cpusubtype_ALL");
if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 &&
- (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext)))
+ (((Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext)) &&
+ (!getDarwinToolChain().isTargetIPhoneOS() ||
+ getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) ||
+ Args.hasArg(options::OPT_static)))
CmdArgs.push_back("-static");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -4110,16 +4355,29 @@ void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
CmdArgs.push_back("-force_cpusubtype_ALL");
}
+bool darwin::Link::NeedsTempPath(const InputInfoList &Inputs) const {
+ // We only need to generate a temp path for LTO if we aren't compiling object
+ // files. When compiling source files, we run 'dsymutil' after linking. We
+ // don't run 'dsymutil' when compiling object files.
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it)
+ if (it->getType() != types::TY_Object)
+ return true;
+
+ return false;
+}
+
void darwin::Link::AddLinkArgs(Compilation &C,
const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const {
const Driver &D = getToolChain().getDriver();
const toolchains::Darwin &DarwinTC = getDarwinToolChain();
unsigned Version[3] = { 0, 0, 0 };
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0],
+ if (!Driver::GetReleaseVersion(A->getValue(), Version[0],
Version[1], Version[2], HadExtra) ||
HadExtra)
D.Diag(diag::err_drv_invalid_version_number)
@@ -4140,7 +4398,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (StringRef(A->getValue(Args, i)) == "-kext")
+ if (StringRef(A->getValue(i)) == "-kext")
UsesLdClassic = true;
}
}
@@ -4151,7 +4409,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
// If we are using LTO, then automatically create a temporary file path for
// the linker to use, so that it's lifetime will extend past a possible
// dsymutil step.
- if (Version[0] >= 116 && D.IsUsingLTO(Args)) {
+ if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) {
const char *TmpPath = C.getArgs().MakeArgString(
D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)));
C.addTempFile(TmpPath);
@@ -4286,7 +4544,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
} else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
CmdArgs.push_back("-syslibroot");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
@@ -4338,7 +4596,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// I'm not sure why this particular decomposition exists in gcc, but
// we follow suite for ease of comparison.
- AddLinkArgs(C, Args, CmdArgs);
+ AddLinkArgs(C, Args, CmdArgs, Inputs);
Args.AddAllArgs(CmdArgs, options::OPT_d_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -4423,7 +4681,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
} else if (getDarwinToolChain().isTargetIPhoneOS()) {
if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
CmdArgs.push_back("-lcrt1.o");
- else
+ else if (getDarwinToolChain().isIPhoneOSVersionLT(6, 0))
CmdArgs.push_back("-lcrt1.3.1.o");
} else {
if (getDarwinToolChain().isMacosxVersionLT(10, 5))
@@ -4451,11 +4709,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
- // If we're building a dynamic lib with -faddress-sanitizer, unresolved
- // symbols may appear. Mark all of them as dynamic_lookup.
- // Linking executables is handled in lib/Driver/ToolChains.cpp.
- if (Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false)) {
+ SanitizerArgs Sanitize(getToolChain().getDriver(), Args);
+ // If we're building a dynamic lib with -fsanitize=address, or
+ // -fsanitize=undefined, 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 (Args.hasArg(options::OPT_dynamiclib) ||
Args.hasArg(options::OPT_bundle)) {
CmdArgs.push_back("-undefined");
@@ -4474,14 +4733,14 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
!Args.hasArg(options::OPT_nodefaultlibs)) {
// Avoid linking compatibility stubs on i386 mac.
if (!getDarwinToolChain().isTargetMacOS() ||
- getDarwinToolChain().getArchName() != "i386") {
+ getDarwinToolChain().getArch() != llvm::Triple::x86) {
// If we don't have ARC or subscripting runtime support, link in the
// runtime stubs. We have to do this *before* adding any of the normal
// linker inputs so that its initializer gets run first.
ObjCRuntime runtime =
getDarwinToolChain().getDefaultObjCRuntime(/*nonfragile*/ true);
// We use arclite library for both ARC and subscripting support.
- if ((!runtime.hasARC() && isObjCAutoRefCount(Args)) ||
+ if ((!runtime.hasNativeARC() && isObjCAutoRefCount(Args)) ||
!runtime.hasSubscripting())
getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
}
@@ -4937,14 +5196,21 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// the default system libraries. Just mimic this for now.
CmdArgs.push_back("-lgcc");
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (!Args.hasArg(options::OPT_shared) &&
+ Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lc_p");
else
CmdArgs.push_back("-lc");
}
+
CmdArgs.push_back("-lgcc");
}
@@ -5056,8 +5322,14 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (!Args.hasArg(options::OPT_shared) &&
+ Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lc_p");
@@ -5108,17 +5380,48 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArchName() == "i386")
+ if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
-
- if (getToolChain().getArchName() == "powerpc")
+ else if (getToolChain().getArch() == llvm::Triple::ppc)
CmdArgs.push_back("-a32");
+ else if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mipsel ||
+ getToolChain().getArch() == llvm::Triple::mips64 ||
+ getToolChain().getArch() == llvm::Triple::mips64el) {
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName);
- // Set byte order explicitly
- if (getToolChain().getArchName() == "mips")
- CmdArgs.push_back("-EB");
- else if (getToolChain().getArchName() == "mipsel")
- CmdArgs.push_back("-EL");
+ 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());
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (LastPICArg &&
+ (LastPICArg->getOption().matches(options::OPT_fPIC) ||
+ LastPICArg->getOption().matches(options::OPT_fpic) ||
+ LastPICArg->getOption().matches(options::OPT_fPIE) ||
+ LastPICArg->getOption().matches(options::OPT_fpie))) {
+ CmdArgs.push_back("-KPIC");
+ }
+ }
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
@@ -5142,7 +5445,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
+ const toolchains::FreeBSD& ToolChain =
+ static_cast<const toolchains::FreeBSD&>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@@ -5156,6 +5461,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
@@ -5168,8 +5476,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
- if (getToolChain().getTriple().getOSMajorVersion() >= 9) {
- llvm::Triple::ArchType Arch = getToolChain().getArch();
+ if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
+ llvm::Triple::ArchType Arch = ToolChain.getArch();
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
CmdArgs.push_back("--hash-style=both");
@@ -5180,12 +5488,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArchName() == "i386") {
+ if (ToolChain.getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386_fbsd");
}
- if (getToolChain().getArchName() == "powerpc") {
+ if (ToolChain.getArch() == llvm::Triple::ppc) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32ppc_fbsd");
}
@@ -5199,29 +5507,33 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
+ const char *crt1 = NULL;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("gcrt1.o")));
- else {
- const char *crt = Args.hasArg(options::OPT_pie) ? "Scrt1.o" : "crt1.o";
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath(crt)));
- }
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtbegin.o")));
- } else {
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtbeginS.o")));
+ crt1 = "gcrt1.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crt1 = "Scrt1.o";
+ else
+ crt1 = "crt1.o";
}
+ if (crt1)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin = NULL;
+ if (Args.hasArg(options::OPT_static))
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- const ToolChain::path_list Paths = getToolChain().getFilePaths();
+ const ToolChain::path_list Paths = ToolChain.getFilePaths();
for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
i != e; ++i)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
@@ -5232,12 +5544,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_r);
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
@@ -5290,20 +5602,17 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "crtend.o")));
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "crtendS.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "crtn.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(ToolChain.GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5320,9 +5629,9 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--32");
// Set byte order explicitly
- if (getToolChain().getArchName() == "mips")
+ if (getToolChain().getArch() == llvm::Triple::mips)
CmdArgs.push_back("-EB");
- else if (getToolChain().getArchName() == "mipsel")
+ else if (getToolChain().getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("-EL");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5547,7 +5856,7 @@ 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::ANDROIDEABI;
+ bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_static_libgcc);
if (!D.CCCIsCXX)
@@ -5570,6 +5879,11 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
CmdArgs.push_back("-lgcc");
}
+static bool hasMipsN32ABIArg(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef("n32"));
+}
+
void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -5578,8 +5892,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const toolchains::Linux& ToolChain =
static_cast<const toolchains::Linux&>(getToolChain());
const Driver &D = ToolChain.getDriver();
- const bool isAndroid = ToolChain.getTriple().getEnvironment() ==
- llvm::Triple::ANDROIDEABI;
+ const bool isAndroid =
+ ToolChain.getTriple().getEnvironment() == llvm::Triple::Android;
ArgStringList CmdArgs;
@@ -5626,10 +5940,18 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf32btsmip");
else if (ToolChain.getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("elf32ltsmip");
- else if (ToolChain.getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("elf64btsmip");
- else if (ToolChain.getArch() == llvm::Triple::mips64el)
- CmdArgs.push_back("elf64ltsmip");
+ else if (ToolChain.getArch() == llvm::Triple::mips64) {
+ if (hasMipsN32ABIArg(Args))
+ CmdArgs.push_back("elf32btsmipn32");
+ else
+ CmdArgs.push_back("elf64btsmip");
+ }
+ else if (ToolChain.getArch() == llvm::Triple::mips64el) {
+ if (hasMipsN32ABIArg(Args))
+ CmdArgs.push_back("elf32ltsmipn32");
+ else
+ CmdArgs.push_back("elf64ltsmip");
+ }
else
CmdArgs.push_back("elf_x86_64");
@@ -5641,8 +5963,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-static");
} else if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-shared");
- if ((ToolChain.getArch() == llvm::Triple::arm
- || ToolChain.getArch() == llvm::Triple::thumb) && isAndroid) {
+ if (isAndroid) {
CmdArgs.push_back("-Bsymbolic");
}
}
@@ -5667,8 +5988,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("/lib/ld.so.1");
else if (ToolChain.getArch() == llvm::Triple::mips64 ||
- ToolChain.getArch() == llvm::Triple::mips64el)
- CmdArgs.push_back("/lib64/ld.so.1");
+ ToolChain.getArch() == llvm::Triple::mips64el) {
+ if (hasMipsN32ABIArg(Args))
+ CmdArgs.push_back("/lib32/ld.so.1");
+ else
+ CmdArgs.push_back("/lib64/ld.so.1");
+ }
else if (ToolChain.getArch() == llvm::Triple::ppc)
CmdArgs.push_back("/lib/ld.so.1");
else if (ToolChain.getArch() == llvm::Triple::ppc64)
@@ -5699,11 +6024,16 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *crtbegin;
if (Args.hasArg(options::OPT_static))
crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ else if (Args.hasArg(options::OPT_shared))
crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
else
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+
+ // Add crtfastmath.o if available and fast math is enabled.
+ ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
@@ -5728,6 +6058,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+ SanitizerArgs Sanitize(D, Args);
+
+ // Call this before we add the C++ ABI library.
+ if (Sanitize.needsUbsanRt())
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs);
+
if (D.CCCIsCXX &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5742,8 +6078,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// Call this before we add the C run-time.
- addAsanRTLinux(getToolChain(), Args, CmdArgs);
- addTsanRTLinux(getToolChain(), Args, CmdArgs);
+ 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)) {
@@ -5766,8 +6104,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostartfiles)) {
const char *crtend;
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ if (Args.hasArg(options::OPT_shared))
crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
else
crtend = isAndroid ? "crtend_android.o" : "crtend.o";
@@ -5873,7 +6213,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on DragonFly/pc64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArchName() == "i386")
+ if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5917,7 +6257,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on DragonFly/pc64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArchName() == "i386") {
+ if (getToolChain().getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 999c57a2b63a..5898c660a499 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -202,6 +202,8 @@ namespace hexagon {
namespace darwin {
+ llvm::Triple::ArchType getArchTypeForDarwinArchName(StringRef Str);
+
class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
virtual void anchor();
protected:
@@ -288,8 +290,9 @@ namespace darwin {
};
class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool {
+ bool NeedsTempPath(const InputInfoList &Inputs) const;
void AddLinkArgs(Compilation &C, const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ ArgStringList &CmdArgs, const InputInfoList &Inputs) const;
public:
Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {}
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 9d8fcfd6bb44..862025ed9a1a 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -94,20 +94,6 @@ bool types::isAcceptedByClang(ID Id) {
}
}
-bool types::isOnlyAcceptedByClang(ID Id) {
- switch (Id) {
- default:
- return false;
-
- case TY_AST:
- case TY_LLVM_IR:
- case TY_LLVM_BC:
- case TY_RewrittenObjC:
- case TY_RewrittenLegacyObjC:
- return true;
- }
-}
-
bool types::isObjC(ID Id) {
switch (Id) {
default:
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index 6827034ef4ca..de2d5352b716 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -81,19 +81,15 @@ bool Windows::IsIntegratedAssemblerDefault() const {
}
bool Windows::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86_64;
}
-const char *Windows::GetDefaultRelocationModel() const {
- return "static";
+bool Windows::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
}
-const char *Windows::GetForcedPicModel() const {
- if (getArchName() == "x86_64")
- return "pic";
- return 0;
+bool Windows::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
}
// FIXME: This probably should goto to some platform utils place.
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index d15b7a75e8f0..de96fee41618 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -920,6 +920,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_ARCExtendBlockObject:
case CK_NonAtomicToAtomic:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
return false;
}
}
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 0f0d8352046d..882d400c4292 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -58,7 +58,7 @@ namespace {
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool TraverseDecl(Decl *D) {
- if (filterMatches(D)) {
+ if (D != NULL && filterMatches(D)) {
Out.changeColor(llvm::raw_ostream::BLUE) <<
(Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
Out.resetColor();
@@ -66,6 +66,7 @@ namespace {
D->dump(Out);
else
D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
+ Out << "\n";
// Don't traverse child nodes to avoid output duplication.
return true;
}
@@ -89,8 +90,6 @@ namespace {
class ASTDeclNodeLister : public ASTConsumer,
public RecursiveASTVisitor<ASTDeclNodeLister> {
- typedef RecursiveASTVisitor<ASTDeclNodeLister> base;
-
public:
ASTDeclNodeLister(raw_ostream *Out = NULL)
: Out(Out ? *Out : llvm::outs()) {}
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index 9feb3de4f0db..31b1df43df79 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -41,8 +41,9 @@ void ASTMergeAction::ExecuteAction() {
DiagIDs(CI.getDiagnostics().getDiagnosticIDs());
for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(),
- /*ShouldOwnClient=*/false));
+ Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(),
+ CI.getDiagnostics().getClient(),
+ /*ShouldOwnClient=*/false));
ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
CI.getFileSystemOpts(), false);
if (!Unit)
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 42a67720c353..5576854a7d8b 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -27,6 +27,7 @@
#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"
@@ -180,6 +181,14 @@ void OnDiskData::Cleanup() {
CleanPreambleFile();
}
+struct ASTUnit::ASTWriterData {
+ SmallString<128> Buffer;
+ llvm::BitstreamWriter Stream;
+ ASTWriter Writer;
+
+ ASTWriterData() : Stream(Buffer), Writer(Stream) { }
+};
+
void ASTUnit::clearFileLevelDecls() {
for (FileDeclsTy::iterator
I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I)
@@ -495,8 +504,8 @@ class ASTInfoCollector : public ASTReaderListener {
ASTContext &Context;
LangOptions &LangOpt;
HeaderSearch &HSI;
+ IntrusiveRefCntPtr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
- std::string &Predefines;
unsigned &Counter;
unsigned NumHeaderInfos;
@@ -504,54 +513,38 @@ class ASTInfoCollector : public ASTReaderListener {
bool InitializedLanguage;
public:
ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
- HeaderSearch &HSI,
+ HeaderSearch &HSI,
+ IntrusiveRefCntPtr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target,
- std::string &Predefines,
unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target),
- Predefines(Predefines), Counter(Counter), NumHeaderInfos(0),
+ : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI),
+ TargetOpts(TargetOpts), Target(Target),
+ Counter(Counter), NumHeaderInfos(0),
InitializedLanguage(false) {}
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
if (InitializedLanguage)
return false;
LangOpt = LangOpts;
-
- // Initialize the preprocessor.
- PP.Initialize(*Target);
-
- // Initialize the ASTContext
- Context.InitBuiltinTypes(*Target);
-
InitializedLanguage = true;
+
+ updated();
return false;
}
- virtual bool ReadTargetTriple(StringRef Triple) {
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
// If we've already initialized the target, don't do it again.
if (Target)
return false;
- // FIXME: This is broken, we should store the TargetOptions in the AST file.
- TargetOptions TargetOpts;
- TargetOpts.ABI = "";
- TargetOpts.CXXABI = "";
- TargetOpts.CPU = "";
- TargetOpts.Features.clear();
- TargetOpts.Triple = Triple;
- Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts);
- return false;
- }
+ this->TargetOpts = new TargetOptions(TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
+ *this->TargetOpts);
- virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- StringRef OriginalFileName,
- std::string &SuggestedPredefines,
- FileManager &FileMgr) {
- Predefines = Buffers[0].Data;
- for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
- Predefines += Buffers[I].Data;
- }
+ updated();
return false;
}
@@ -559,9 +552,27 @@ public:
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
}
- virtual void ReadCounter(unsigned Value) {
+ virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) {
Counter = Value;
}
+
+private:
+ void updated() {
+ if (!Target || !InitializedLanguage)
+ return;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Target->setForcedLangOptions(LangOpt);
+
+ // Initialize the preprocessor.
+ PP.Initialize(*Target);
+
+ // Initialize the ASTContext
+ Context.InitBuiltinTypes(*Target);
+ }
};
class StoredDiagnosticConsumer : public DiagnosticConsumer {
@@ -621,8 +632,10 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
StoredDiags.push_back(StoredDiagnostic(Level, Info));
}
-const std::string &ASTUnit::getOriginalSourceFileName() {
- return OriginalSourceFile;
+ASTDeserializationListener *ASTUnit::getDeserializationListener() {
+ if (WriterData)
+ return &WriterData->Writer;
+ return 0;
}
llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
@@ -638,11 +651,11 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticOptions DiagOpts;
DiagnosticConsumer *Client = 0;
if (CaptureDiagnostics)
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
- Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin,
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
+ ArgEnd-ArgBegin,
ArgBegin, Client,
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/false);
@@ -679,7 +692,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
UserFilesAreVolatile);
- AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
+ AST->HSOpts = new HeaderSearchOptions();
+
+ AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
+ AST->getFileManager(),
AST->getDiagnostics(),
AST->ASTFileLangOpts,
/*Target=*/0));
@@ -734,12 +750,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Gather Info for preprocessor construction later on.
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
- std::string Predefines;
unsigned Counter;
OwningPtr<ASTReader> Reader;
- AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts,
+ AST->PP = new Preprocessor(new PreprocessorOptions(),
+ AST->getDiagnostics(), AST->ASTFileLangOpts,
/*Target=*/0, AST->getSourceManager(), HeaderInfo,
*AST,
/*IILookup=*/0,
@@ -757,10 +773,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
/*DelayInitialization=*/true);
ASTContext &Context = *AST->Ctx;
+ bool disableValid = false;
+ if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
+ disableValid = true;
Reader.reset(new ASTReader(PP, Context,
/*isysroot=*/"",
- /*DisableValidation=*/false,
- /*DisableStatCache=*/false,
+ /*DisableValidation=*/disableValid,
AllowPCHWithCompilerErrors));
// Recover resources if we crash before exiting this method.
@@ -769,21 +787,25 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
AST->ASTFileLangOpts, HeaderInfo,
- AST->Target, Predefines, Counter));
+ AST->TargetOpts, AST->Target,
+ Counter));
- switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) {
+ switch (Reader->ReadAST(Filename, serialization::MK_MainFile,
+ ASTReader::ARR_None)) {
case ASTReader::Success:
break;
case ASTReader::Failure:
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate:
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
return NULL;
}
AST->OriginalSourceFile = Reader->getOriginalSourceFile();
- PP.setPredefines(Reader->getSuggestedPredefines());
PP.setCounterValue(Counter);
// Attach the AST reader to the AST context as an external AST
@@ -897,6 +919,10 @@ public:
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
handleTopLevelDecl(*it);
}
+
+ virtual ASTDeserializationListener *GetASTDeserializationListener() {
+ return Unit.getDeserializationListener();
+ }
};
class TopLevelDeclTrackerAction : public ASTFrontendAction {
@@ -1047,14 +1073,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
CCInvocation(new CompilerInvocation(*Invocation));
Clang->setInvocation(CCInvocation.getPtr());
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
@@ -1070,9 +1095,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1217,7 +1242,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// command line (to another file) or directly through the compiler invocation
// (to a memory buffer).
llvm::MemoryBuffer *Buffer = 0;
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
+ llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile());
if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
// Check whether there is a file-file remapping of the main file
for (PreprocessorOptions::remapped_file_iterator
@@ -1267,7 +1292,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// If the main source file was not remapped, load it now.
if (!Buffer) {
- Buffer = getBufferForFile(FrontendOpts.Inputs[0].File);
+ Buffer = getBufferForFile(FrontendOpts.Inputs[0].getFile());
if (!Buffer)
return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
@@ -1429,7 +1454,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// buffer size we reserved when creating the preamble.
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
- FrontendOpts.Inputs[0].File);
+ FrontendOpts.Inputs[0].getFile());
}
}
@@ -1482,7 +1507,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Save the preamble text for later; we'll need to compare against it for
// subsequent reparses.
- StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File;
+ StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].getFile();
Preamble.assign(FileMgr->getFile(MainFilename),
NewPreamble.first->getBufferStart(),
NewPreamble.first->getBufferStart()
@@ -1492,7 +1517,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
delete PreambleBuffer;
PreambleBuffer
= llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
- FrontendOpts.Inputs[0].File);
+ FrontendOpts.Inputs[0].getFile());
memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
NewPreamble.first->getBufferStart(), Preamble.size());
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
@@ -1500,7 +1525,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
// Remap the main source file to the preamble buffer.
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
+ llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile());
PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
// Tell the compiler invocation to generate a temporary precompiled header.
@@ -1518,15 +1543,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
CICleanup(Clang.get());
Clang->setInvocation(&*PreambleInvocation);
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing all of the diagnostics produced.
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
@@ -1544,9 +1568,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not support here!");
// Clear out old caches and data.
@@ -1633,7 +1657,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
- FrontendOpts.Inputs[0].File);
+ FrontendOpts.Inputs[0].getFile());
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
@@ -1664,7 +1688,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
}
StringRef ASTUnit::getMainFileName() const {
- return Invocation->getFrontendOpts().Inputs[0].File;
+ return Invocation->getFrontendOpts().Inputs[0].getFile();
}
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
@@ -1733,9 +1757,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
CI->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
- // Save the target features.
- AST->TargetFeatures = CI->getTargetOpts().Features;
-
// Create the compiler instance to use for building the AST.
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
@@ -1744,14 +1765,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
CICleanup(Clang.get());
Clang->setInvocation(CI);
- AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
Clang->setDiagnostics(&AST->getDiagnostics());
// Create the target instance.
- Clang->getTargetOpts().Features = AST->TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget())
@@ -1765,9 +1785,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not supported here!");
// Configure the various subsystems.
@@ -1840,9 +1860,6 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
Invocation->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
- // Save the target features.
- TargetFeatures = Invocation->getTargetOpts().Features;
-
llvm::MemoryBuffer *OverrideMainBuffer = 0;
if (PrecompilePreamble) {
PreambleRebuildCounter = 2;
@@ -1909,12 +1926,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool AllowPCHWithCompilerErrors,
bool SkipFunctionBodies,
bool UserFilesAreVolatile,
+ bool ForSerialization,
OwningPtr<ASTUnit> *ErrAST) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin,
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
+ ArgEnd - ArgBegin,
ArgBegin);
}
@@ -1972,6 +1990,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
+ if (ForSerialization)
+ AST->WriterData.reset(new ASTWriterData());
CI = 0; // Zero out now to ease cleanup during crash recovery.
// Recover resources if we crash before exiting this method.
@@ -2002,7 +2022,6 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
// Remap files.
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
- PPOpts.DisableStatCache = true;
for (PreprocessorOptions::remapped_file_buffer_iterator
R = PPOpts.remapped_file_buffer_begin(),
REnd = PPOpts.remapped_file_buffer_end();
@@ -2238,7 +2257,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
// Adjust priority based on similar type classes.
unsigned Priority = C->Priority;
- CXCursorKind CursorKind = C->Kind;
CodeCompletionString *Completion = C->Completion;
if (!Context.getPreferredType().isNull()) {
if (C->Kind == CXCursor_MacroDefinition) {
@@ -2272,12 +2290,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(),
CCP_CodePattern, C->Availability);
Builder.AddTypedTextChunk(C->Completion->getTypedText());
- CursorKind = CXCursor_NotImplemented;
Priority = CCP_CodePattern;
Completion = Builder.TakeString();
}
- AllResults.push_back(Result(Completion, Priority, CursorKind,
+ AllResults.push_back(Result(Completion, Priority, C->Kind,
C->Availability));
}
@@ -2341,7 +2358,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
CICleanup(Clang.get());
Clang->setInvocation(&*CCInvocation);
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics produced.
Clang->setDiagnostics(&Diag);
@@ -2351,7 +2368,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
StoredDiagnostics);
// Create the target instance.
- Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
@@ -2367,9 +2383,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not support here!");
@@ -2398,8 +2414,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
= new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts);
Clang->setCodeCompletionConsumer(AugmentedConsumer);
- Clang->getFrontendOpts().SkipFunctionBodies = true;
-
// If we have a precompiled preamble, try to use it. We only allow
// the use of the precompiled preamble if we're if the completion
// point is within the main file, after the end of the precompiled
@@ -2420,7 +2434,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.
- PreprocessorOpts.DisableStatCache = true;
StoredDiagnostics.insert(StoredDiagnostics.end(),
stored_diag_begin(),
stored_diag_afterDriver_begin());
@@ -2438,8 +2451,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
}
- // Disable the preprocessing record
- PreprocessorOpts.DetailedRecord = false;
+ // Disable the preprocessing record if modules are not enabled.
+ if (!Clang->getLangOpts().Modules)
+ PreprocessorOpts.DetailedRecord = false;
OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
@@ -2457,7 +2471,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
}
-CXSaveError ASTUnit::Save(StringRef File) {
+bool ASTUnit::Save(StringRef File) {
// Write to a temporary file and later rename it to the actual file, to avoid
// possible race conditions.
SmallString<128> TempPath;
@@ -2466,7 +2480,7 @@ CXSaveError ASTUnit::Save(StringRef File) {
int fd;
if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
/*makeAbsolute=*/false))
- return CXSaveError_Unknown;
+ return true;
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
// unconditionally create a stat cache when we parse the file?
@@ -2476,32 +2490,43 @@ CXSaveError ASTUnit::Save(StringRef File) {
Out.close();
if (Out.has_error()) {
Out.clear_error();
- return CXSaveError_Unknown;
+ return true;
}
if (llvm::sys::fs::rename(TempPath.str(), File)) {
bool exists;
llvm::sys::fs::remove(TempPath.str(), exists);
- return CXSaveError_Unknown;
+ return true;
}
- return CXSaveError_None;
+ return false;
+}
+
+static bool serializeUnit(ASTWriter &Writer,
+ SmallVectorImpl<char> &Buffer,
+ Sema &S,
+ bool hasErrors,
+ raw_ostream &OS) {
+ Writer.WriteAST(S, std::string(), 0, "", hasErrors);
+
+ // Write the generated bitstream to "Out".
+ if (!Buffer.empty())
+ OS.write(Buffer.data(), Buffer.size());
+
+ return false;
}
bool ASTUnit::serialize(raw_ostream &OS) {
bool hasErrors = getDiagnostics().hasErrorOccurred();
+ if (WriterData)
+ return serializeUnit(WriterData->Writer, WriterData->Buffer,
+ getSema(), hasErrors, OS);
+
SmallString<128> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
- // FIXME: Handle modules
- Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors);
-
- // Write the generated bitstream to "Out".
- if (!Buffer.empty())
- OS.write((char *)&Buffer.front(), Buffer.size());
-
- return false;
+ return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS);
}
typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap;
@@ -2761,6 +2786,85 @@ SourceLocation ASTUnit::getStartOfMainFileID() {
return SourceMgr->getLocForStartOfFile(FID);
}
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ASTUnit::getLocalPreprocessingEntities() const {
+ if (isMainFileAST()) {
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ return Reader->getModulePreprocessedEntities(Mod);
+ }
+
+ if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
+ return std::make_pair(PPRec->local_begin(), PPRec->local_end());
+
+ return std::make_pair(PreprocessingRecord::iterator(),
+ PreprocessingRecord::iterator());
+}
+
+bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) {
+ if (isMainFileAST()) {
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ ASTReader::ModuleDeclIterator MDI, MDE;
+ llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod);
+ for (; MDI != MDE; ++MDI) {
+ if (!Fn(context, *MDI))
+ return false;
+ }
+
+ return true;
+ }
+
+ for (ASTUnit::top_level_iterator TL = top_level_begin(),
+ TLEnd = top_level_end();
+ TL != TLEnd; ++TL) {
+ if (!Fn(context, *TL))
+ return false;
+ }
+
+ return true;
+}
+
+namespace {
+struct PCHLocatorInfo {
+ serialization::ModuleFile *Mod;
+ PCHLocatorInfo() : Mod(0) {}
+};
+}
+
+static bool PCHLocator(serialization::ModuleFile &M, void *UserData) {
+ PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData);
+ switch (M.Kind) {
+ case serialization::MK_Module:
+ return true; // skip dependencies.
+ case serialization::MK_PCH:
+ Info.Mod = &M;
+ return true; // found it.
+ case serialization::MK_Preamble:
+ return false; // look in dependencies.
+ case serialization::MK_MainFile:
+ return false; // look in dependencies.
+ }
+
+ return true;
+}
+
+const FileEntry *ASTUnit::getPCHFile() {
+ if (!Reader)
+ return 0;
+
+ PCHLocatorInfo Info;
+ Reader->getModuleManager().visit(PCHLocator, &Info);
+ if (Info.Mod)
+ return Info.Mod->File;
+
+ return 0;
+}
+
+bool ASTUnit::isModuleFile() {
+ return isMainFileAST() && !ASTFileLangOpts.CurrentModule.empty();
+}
+
void ASTUnit::PreambleData::countLines() const {
NumLines = 0;
if (empty())
diff --git a/lib/Frontend/ChainedDiagnosticConsumer.cpp b/lib/Frontend/ChainedDiagnosticConsumer.cpp
index c1d3db873f1f..d77fd180ea0d 100644
--- a/lib/Frontend/ChainedDiagnosticConsumer.cpp
+++ b/lib/Frontend/ChainedDiagnosticConsumer.cpp
@@ -1,4 +1,4 @@
-//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -*- C++ -*-===//
+//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -----------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index dbb06bd23cdc..2d586400ec46 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -39,14 +39,18 @@ 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,
+ ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader.
PP.setPredefines(Reader->getSuggestedPredefines());
return Reader.take();
case ASTReader::Failure:
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate:
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
break;
}
return 0;
@@ -63,7 +67,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
assert(!includes.empty() && "No '-chain-include' in options!");
OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
- InputKind IK = CI.getFrontendOpts().Inputs[0].Kind;
+ InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
SmallVector<std::string, 4> serialBufNames;
@@ -82,14 +86,14 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
CInvok->getPreprocessorOpts().Macros.clear();
CInvok->getFrontendOpts().Inputs.clear();
- CInvok->getFrontendOpts().Inputs.push_back(FrontendInputFile(includes[i],
- IK));
+ FrontendInputFile InputFile(includes[i], IK);
+ CInvok->getFrontendOpts().Inputs.push_back(InputFile);
TextDiagnosticPrinter *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient));
+ new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
Clang->setInvocation(CInvok.take());
@@ -108,6 +112,8 @@ 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());
@@ -141,7 +147,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
Clang->getASTContext().setExternalSource(Reader);
}
- if (!Clang->InitializeSourceManager(includes[i]))
+ if (!Clang->InitializeSourceManager(InputFile))
return 0;
ParseAST(Clang->getSema());
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 6de153107f3b..22a74fcc35d9 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -52,6 +52,7 @@ CompilerInstance::CompilerInstance()
}
CompilerInstance::~CompilerInstance() {
+ assert(OutputFiles.empty() && "Still output files in flight?");
}
void CompilerInstance::setInvocation(CompilerInvocation *Value) {
@@ -88,19 +89,18 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
CompletionConsumer.reset(Value);
- getFrontendOpts().SkipFunctionBodies = Value != 0;
}
// Diagnostics
-static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
+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));
+ 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;
+ << DiagOpts->DumpBuildInformation << ErrorInfo;
return;
}
@@ -115,20 +115,20 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
-static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
+static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
const CodeGenOptions *CodeGenOpts,
DiagnosticsEngine &Diags) {
std::string ErrorInfo;
bool OwnsStream = false;
raw_ostream *OS = &llvm::errs();
- if (DiagOpts.DiagnosticLogFile != "-") {
+ if (DiagOpts->DiagnosticLogFile != "-") {
// Create the output stream.
llvm::raw_fd_ostream *FileOS(
- new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(),
+ new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(),
ErrorInfo, llvm::raw_fd_ostream::F_Append));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
- << DiagOpts.DumpBuildInformation << ErrorInfo;
+ << DiagOpts->DumpBuildInformation << ErrorInfo;
} else {
FileOS->SetUnbuffered();
FileOS->SetUseAtomicWrites(true);
@@ -145,7 +145,7 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
-static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts,
+static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
DiagnosticsEngine &Diags,
StringRef OutputFile) {
std::string ErrorInfo;
@@ -171,13 +171,13 @@ void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient) {
- Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client,
+ Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client,
ShouldOwnClient, ShouldCloneClient,
&getCodeGenOpts());
}
IntrusiveRefCntPtr<DiagnosticsEngine>
-CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
+CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
@@ -185,7 +185,7 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
const CodeGenOptions *CodeGenOpts) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(new DiagnosticsEngine(DiagID));
+ Diags(new DiagnosticsEngine(DiagID, Opts));
// Create the diagnostic client for reporting errors or for
// implementing -verify.
@@ -198,22 +198,22 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
// Chain in -verify checker, if requested.
- if (Opts.VerifyDiagnostics)
+ if (Opts->VerifyDiagnostics)
Diags->setClient(new VerifyDiagnosticConsumer(*Diags));
// Chain in -diagnostic-log-file dumper, if requested.
- if (!Opts.DiagnosticLogFile.empty())
+ if (!Opts->DiagnosticLogFile.empty())
SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
- if (!Opts.DumpBuildInformation.empty())
+ if (!Opts->DumpBuildInformation.empty())
SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
- if (!Opts.DiagnosticSerializationFile.empty())
+ if (!Opts->DiagnosticSerializationFile.empty())
SetupSerializedDiagnostics(Opts, *Diags,
- Opts.DiagnosticSerializationFile);
+ Opts->DiagnosticSerializationFile);
// Configure our handling of diagnostics.
- ProcessWarningOptions(*Diags, Opts);
+ ProcessWarningOptions(*Diags, *Opts);
return Diags;
}
@@ -241,11 +241,13 @@ void CompilerInstance::createPreprocessor() {
PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
// Create the Preprocessor.
- HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(),
+ HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(),
+ getFileManager(),
getDiagnostics(),
getLangOpts(),
&getTarget());
- PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(),
+ PP = new Preprocessor(&getPreprocessorOpts(),
+ getDiagnostics(), getLangOpts(), &getTarget(),
getSourceManager(), *HeaderInfo, *this, PTHMgr,
/*OwnsHeaderSearch=*/true);
@@ -306,14 +308,12 @@ void CompilerInstance::createASTContext() {
void CompilerInstance::createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
- bool DisableStatCache,
bool AllowPCHWithCompilerErrors,
void *DeserializationListener){
OwningPtr<ExternalASTSource> Source;
bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
DisablePCHValidation,
- DisableStatCache,
AllowPCHWithCompilerErrors,
getPreprocessor(), getASTContext(),
DeserializationListener,
@@ -326,7 +326,6 @@ ExternalASTSource *
CompilerInstance::createPCHExternalASTSource(StringRef Path,
const std::string &Sysroot,
bool DisablePCHValidation,
- bool DisableStatCache,
bool AllowPCHWithCompilerErrors,
Preprocessor &PP,
ASTContext &Context,
@@ -335,14 +334,15 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- DisablePCHValidation, DisableStatCache,
+ DisablePCHValidation,
AllowPCHWithCompilerErrors));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
- : serialization::MK_PCH)) {
+ : serialization::MK_PCH,
+ ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
// predefines buffer will be empty.
@@ -353,7 +353,10 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
// Unrecoverable failure: don't even try to process the input file.
break;
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate:
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
// No suitable PCH file could be found. Return an error.
break;
}
@@ -586,19 +589,29 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
// Initialization Utilities
-bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
- SrcMgr::CharacteristicKind Kind){
- return InitializeSourceManager(InputFile, Kind, getDiagnostics(),
+bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input){
+ return InitializeSourceManager(Input, getDiagnostics(),
getFileManager(), getSourceManager(),
getFrontendOpts());
}
-bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
- SrcMgr::CharacteristicKind Kind,
+bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
const FrontendOptions &Opts) {
+ SrcMgr::CharacteristicKind
+ Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+
+ if (Input.isBuffer()) {
+ SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind);
+ assert(!SourceMgr.getMainFileID().isInvalid() &&
+ "Couldn't establish MainFileID!");
+ return true;
+ }
+
+ StringRef InputFile = Input.getFile();
+
// Figure out where to get and map in the main file.
if (InputFile != "-") {
const FileEntry *File = FileMgr.getFile(InputFile);
@@ -607,6 +620,19 @@ bool CompilerInstance::InitializeSourceManager(StringRef 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
+ // file. Detect them here, read them with the more generic MemoryBuffer
+ // function, and simply override their contents as we do for STDIN.
+ if (File->isNamedPipe()) {
+ OwningPtr<llvm::MemoryBuffer> MB;
+ if (llvm::error_code ec = llvm::MemoryBuffer::getFile(InputFile, MB)) {
+ Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message();
+ return false;
+ }
+ SourceMgr.overrideFileContents(File, MB.take());
+ }
} else {
OwningPtr<llvm::MemoryBuffer> SB;
if (llvm::MemoryBuffer::getSTDIN(SB)) {
@@ -746,7 +772,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
// Someone else is responsible for building the module. Wait for them to
// finish.
Locked.waitForUnlock();
- break;
+ return;
}
ModuleMap &ModMap
@@ -836,6 +862,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
// FIXME: Even though we're executing under crash protection, it would still
// be nice to do this with RemoveFileOnSignal when we can. However, that
// doesn't make sense for all clients, so clean this up manually.
+ Instance.clearOutputFiles(/*EraseFiles=*/true);
if (!TempModuleMapFileName.empty())
llvm::sys::Path(TempModuleMapFileName).eraseFromDisk();
}
@@ -939,13 +966,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
ModuleManager = new ASTReader(getPreprocessor(), *Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation,
- PPOpts.DisableStatCache);
+ PPOpts.DisablePCHValidation);
if (hasASTConsumer()) {
ModuleManager->setDeserializationListener(
getASTConsumer().GetASTDeserializationListener());
getASTContext().setASTMutationListener(
getASTConsumer().GetASTMutationListener());
+ getPreprocessor().setPPMutationListener(
+ getASTConsumer().GetPPMutationListener());
}
OwningPtr<ExternalASTSource> Source;
Source.reset(ModuleManager);
@@ -957,12 +985,39 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// 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)) {
+ serialization::MK_Module,
+ ARRFlags)) {
case ASTReader::Success:
break;
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate: {
+ // The module file is out-of-date. Rebuild it.
+ getFileManager().invalidateCache(ModuleFile);
+ 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) {
+ KnownModules[Path[0].first] = 0;
+ return 0;
+ }
+
+ // Okay, we've rebuilt and now loaded the module.
+ break;
+ }
+
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
KnownModules[Path[0].first] = 0;
@@ -980,6 +1035,9 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
Module = PP->getHeaderSearchInfo().getModuleMap()
.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;
@@ -1079,9 +1137,12 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
// implicit import declaration to capture it in the AST.
if (IsInclusionDirective && hasASTContext()) {
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
- TU->addDecl(ImportDecl::CreateImplicit(getASTContext(), TU,
- ImportLoc, Module,
- Path.back().second));
+ ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+ ImportLoc, Module,
+ Path.back().second);
+ TU->addDecl(ImportD);
+ if (Consumer)
+ Consumer->HandleImplicitImportDecl(ImportD);
}
LastModuleImportLoc = ImportLoc;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index d39679caf13e..b9c198b11191 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -11,6 +11,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
@@ -20,6 +21,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -35,917 +37,21 @@ using namespace clang;
//===----------------------------------------------------------------------===//
CompilerInvocationBase::CompilerInvocationBase()
- : LangOpts(new LangOptions()) {}
+ : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()),
+ DiagnosticOpts(new DiagnosticOptions()),
+ HeaderSearchOpts(new HeaderSearchOptions()),
+ PreprocessorOpts(new PreprocessorOptions()) {}
CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X)
: RefCountedBase<CompilerInvocation>(),
- LangOpts(new LangOptions(*X.getLangOpts())) {}
+ LangOpts(new LangOptions(*X.getLangOpts())),
+ TargetOpts(new TargetOptions(X.getTargetOpts())),
+ DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())),
+ HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
+ PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {}
//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-static const char *getAnalysisStoreName(AnalysisStores Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis store!");
-#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
- case NAME##Model: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis constraints!");
-#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
- case NAME##Model: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis client!");
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \
- case PD_##NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis purge mode!");
-#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
- case NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisIPAModeName(AnalysisIPAMode Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis ipa mode!");
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
- case NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *
- getAnalysisInliningModeName(AnalysisInliningMode Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis inlining mode!");
-#define ANALYSIS_INLINE_SELECTION(NAME, CMDFLAG, DESC) \
- case NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Serialization (to args)
-//===----------------------------------------------------------------------===//
-
-namespace {
- /// ToArgsList - Helper class to create a list of std::strings.
- class ToArgsList {
- std::vector<std::string> &Res;
- public:
- explicit ToArgsList(std::vector<std::string> &Res) : Res(Res) {}
-
- void push_back(StringRef Str) {
- // Avoid creating a temporary string.
- Res.push_back(std::string());
- Res.back().assign(Str.data(), Str.size());
- }
-
- void push_back(StringRef Str1, StringRef Str2) {
- push_back(Str1);
- push_back(Str2);
- }
- };
-}
-
-static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) {
- if (Opts.ShowCheckerHelp)
- Res.push_back("-analyzer-checker-help");
- if (Opts.AnalysisStoreOpt != RegionStoreModel)
- Res.push_back("-analyzer-store",
- getAnalysisStoreName(Opts.AnalysisStoreOpt));
- if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel)
- Res.push_back("-analyzer-constraints",
- getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
- if (Opts.AnalysisDiagOpt != PD_HTML)
- Res.push_back("-analyzer-output",
- getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
- if (Opts.AnalysisPurgeOpt != PurgeStmt)
- Res.push_back("-analyzer-purge",
- getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt));
- if (!Opts.AnalyzeSpecificFunction.empty())
- Res.push_back("-analyze-function", Opts.AnalyzeSpecificFunction);
- if (Opts.IPAMode != Inlining)
- Res.push_back("-analyzer-ipa", getAnalysisIPAModeName(Opts.IPAMode));
- if (Opts.InliningMode != NoRedundancy)
- Res.push_back("-analyzer-inlining-mode",
- getAnalysisInliningModeName(Opts.InliningMode));
-
- if (Opts.AnalyzeAll)
- Res.push_back("-analyzer-opt-analyze-headers");
- if (Opts.AnalyzerDisplayProgress)
- Res.push_back("-analyzer-display-progress");
- if (Opts.AnalyzeNestedBlocks)
- Res.push_back("-analyzer-opt-analyze-nested-blocks");
- if (Opts.EagerlyAssume)
- Res.push_back("-analyzer-eagerly-assume");
- if (Opts.TrimGraph)
- Res.push_back("-trim-egraph");
- if (Opts.VisualizeEGDot)
- Res.push_back("-analyzer-viz-egraph-graphviz");
- if (Opts.VisualizeEGUbi)
- Res.push_back("-analyzer-viz-egraph-ubigraph");
- if (Opts.NoRetryExhausted)
- Res.push_back("-analyzer-disable-retry-exhausted");
-
- for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) {
- const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i];
- if (opt.second)
- Res.push_back("-analyzer-disable-checker");
- else
- Res.push_back("-analyzer-checker");
- Res.push_back(opt.first);
- }
-}
-
-static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) {
- switch (Opts.DebugInfo) {
- case CodeGenOptions::NoDebugInfo:
- break;
- case CodeGenOptions::DebugLineTablesOnly:
- Res.push_back("-gline-tables-only");
- break;
- case CodeGenOptions::LimitedDebugInfo:
- Res.push_back("-g");
- Res.push_back("-flimit-debug-info");
- break;
- case CodeGenOptions::FullDebugInfo:
- Res.push_back("-g");
- Res.push_back("-fno-limit-debug-info");
- break;
- }
- if (Opts.DisableLLVMOpts)
- Res.push_back("-disable-llvm-optzns");
- if (Opts.DisableRedZone)
- Res.push_back("-disable-red-zone");
- if (Opts.DisableTailCalls)
- Res.push_back("-mdisable-tail-calls");
- if (!Opts.DebugCompilationDir.empty())
- Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir);
- if (!Opts.DwarfDebugFlags.empty())
- Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags);
- if (Opts.EmitGcovArcs)
- Res.push_back("-femit-coverage-data");
- if (Opts.EmitGcovNotes)
- Res.push_back("-femit-coverage-notes");
- if (Opts.EmitOpenCLArgMetadata)
- Res.push_back("-cl-kernel-arg-info");
- if (!Opts.MergeAllConstants)
- Res.push_back("-fno-merge-all-constants");
- if (Opts.NoCommon)
- Res.push_back("-fno-common");
- if (Opts.ForbidGuardVariables)
- Res.push_back("-fforbid-guard-variables");
- if (Opts.UseRegisterSizedBitfieldAccess)
- Res.push_back("-fuse-register-sized-bitfield-access");
- if (Opts.NoImplicitFloat)
- Res.push_back("-no-implicit-float");
- if (Opts.OmitLeafFramePointer)
- Res.push_back("-momit-leaf-frame-pointer");
- if (Opts.OptimizeSize) {
- assert(Opts.OptimizationLevel == 2 && "Invalid options!");
- Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz");
- } else if (Opts.OptimizationLevel != 0)
- Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel));
- if (!Opts.MainFileName.empty())
- Res.push_back("-main-file-name", Opts.MainFileName);
- if (Opts.NoInfsFPMath)
- Res.push_back("-menable-no-infinities");
- if (Opts.NoNaNsFPMath)
- Res.push_back("-menable-no-nans");
- // SimplifyLibCalls is only derived.
- // TimePasses is only derived.
- // UnitAtATime is unused.
- // Inlining is only derived.
-
- // UnrollLoops is derived, but also accepts an option, no
- // harm in pushing it back here.
- if (Opts.UnrollLoops)
- Res.push_back("-funroll-loops");
- if (Opts.DataSections)
- Res.push_back("-fdata-sections");
- if (Opts.FunctionSections)
- Res.push_back("-ffunction-sections");
- if (Opts.AsmVerbose)
- Res.push_back("-masm-verbose");
- if (!Opts.CodeModel.empty())
- Res.push_back("-mcode-model", Opts.CodeModel);
- if (Opts.CUDAIsDevice)
- Res.push_back("-fcuda-is-device");
- if (!Opts.CXAAtExit)
- Res.push_back("-fno-use-cxa-atexit");
- if (Opts.CXXCtorDtorAliases)
- Res.push_back("-mconstructor-aliases");
- if (Opts.ObjCAutoRefCountExceptions)
- Res.push_back("-fobjc-arc-eh");
- if (!Opts.DebugPass.empty()) {
- Res.push_back("-mdebug-pass", Opts.DebugPass);
- }
- if (Opts.DisableFPElim)
- Res.push_back("-mdisable-fp-elim");
- if (!Opts.FloatABI.empty())
- Res.push_back("-mfloat-abi", Opts.FloatABI);
- if (!Opts.LimitFloatPrecision.empty())
- Res.push_back("-mlimit-float-precision", Opts.LimitFloatPrecision);
- if (Opts.NoZeroInitializedInBSS)
- Res.push_back("-mno-zero-initialized-bss");
- switch (Opts.getObjCDispatchMethod()) {
- case CodeGenOptions::Legacy:
- break;
- case CodeGenOptions::Mixed:
- Res.push_back("-fobjc-dispatch-method=mixed");
- break;
- case CodeGenOptions::NonLegacy:
- Res.push_back("-fobjc-dispatch-method=non-legacy");
- break;
- }
- if (Opts.BoundsChecking > 0)
- Res.push_back("-fbounds-checking=" + llvm::utostr(Opts.BoundsChecking));
- if (Opts.NumRegisterParameters)
- Res.push_back("-mregparm", llvm::utostr(Opts.NumRegisterParameters));
- if (Opts.NoGlobalMerge)
- Res.push_back("-mno-global-merge");
- if (Opts.NoExecStack)
- Res.push_back("-mnoexecstack");
- if (Opts.RelaxAll)
- Res.push_back("-mrelax-all");
- if (Opts.SaveTempLabels)
- Res.push_back("-msave-temp-labels");
- if (Opts.NoDwarf2CFIAsm)
- Res.push_back("-fno-dwarf2-cfi-asm");
- if (Opts.NoDwarfDirectoryAsm)
- Res.push_back("-fno-dwarf-directory-asm");
- if (Opts.SoftFloat)
- Res.push_back("-msoft-float");
- if (Opts.StrictEnums)
- Res.push_back("-fstrict-enums");
- if (Opts.UnwindTables)
- Res.push_back("-munwind-tables");
- if (Opts.RelocationModel != "pic")
- Res.push_back("-mrelocation-model", Opts.RelocationModel);
- if (!Opts.VerifyModule)
- Res.push_back("-disable-llvm-verifier");
- for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i)
- Res.push_back("-backend-option", Opts.BackendOptions[i]);
-
- switch (Opts.DefaultTLSModel) {
- case CodeGenOptions::GeneralDynamicTLSModel:
- break;
- case CodeGenOptions::LocalDynamicTLSModel:
- Res.push_back("-ftls-model=local-dynamic");
- break;
- case CodeGenOptions::InitialExecTLSModel:
- Res.push_back("-ftls-model=initial-exec");
- break;
- case CodeGenOptions::LocalExecTLSModel:
- Res.push_back("-ftls-model=local-exec");
- break;
- }
-}
-
-static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
- ToArgsList &Res) {
- if (Opts.IncludeSystemHeaders)
- Res.push_back("-sys-header-deps");
- if (Opts.ShowHeaderIncludes)
- Res.push_back("-H");
- if (!Opts.HeaderIncludeOutputFile.empty())
- Res.push_back("-header-include-file", Opts.HeaderIncludeOutputFile);
- if (Opts.UsePhonyTargets)
- Res.push_back("-MP");
- if (!Opts.OutputFile.empty())
- Res.push_back("-dependency-file", Opts.OutputFile);
- for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i)
- Res.push_back("-MT", Opts.Targets[i]);
-}
-
-static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
- ToArgsList &Res) {
- if (Opts.IgnoreWarnings)
- Res.push_back("-w");
- if (Opts.NoRewriteMacros)
- Res.push_back("-Wno-rewrite-macros");
- if (Opts.Pedantic)
- Res.push_back("-pedantic");
- if (Opts.PedanticErrors)
- Res.push_back("-pedantic-errors");
- if (!Opts.ShowColumn)
- Res.push_back("-fno-show-column");
- if (!Opts.ShowLocation)
- Res.push_back("-fno-show-source-location");
- if (!Opts.ShowCarets)
- Res.push_back("-fno-caret-diagnostics");
- if (!Opts.ShowFixits)
- Res.push_back("-fno-diagnostics-fixit-info");
- if (Opts.ShowSourceRanges)
- Res.push_back("-fdiagnostics-print-source-range-info");
- if (Opts.ShowParseableFixits)
- Res.push_back("-fdiagnostics-parseable-fixits");
- if (Opts.ShowColors)
- Res.push_back("-fcolor-diagnostics");
- if (Opts.VerifyDiagnostics)
- Res.push_back("-verify");
- if (Opts.ShowOptionNames)
- Res.push_back("-fdiagnostics-show-option");
- if (Opts.ShowCategories == 1)
- Res.push_back("-fdiagnostics-show-category=id");
- else if (Opts.ShowCategories == 2)
- Res.push_back("-fdiagnostics-show-category=name");
- switch (Opts.Format) {
- case DiagnosticOptions::Clang:
- Res.push_back("-fdiagnostics-format=clang"); break;
- case DiagnosticOptions::Msvc:
- Res.push_back("-fdiagnostics-format=msvc"); break;
- case DiagnosticOptions::Vi:
- Res.push_back("-fdiagnostics-format=vi"); break;
- }
- if (Opts.ErrorLimit)
- Res.push_back("-ferror-limit", llvm::utostr(Opts.ErrorLimit));
- if (!Opts.DiagnosticLogFile.empty())
- Res.push_back("-diagnostic-log-file", Opts.DiagnosticLogFile);
- if (Opts.MacroBacktraceLimit
- != DiagnosticOptions::DefaultMacroBacktraceLimit)
- Res.push_back("-fmacro-backtrace-limit",
- llvm::utostr(Opts.MacroBacktraceLimit));
- if (Opts.TemplateBacktraceLimit
- != DiagnosticOptions::DefaultTemplateBacktraceLimit)
- Res.push_back("-ftemplate-backtrace-limit",
- llvm::utostr(Opts.TemplateBacktraceLimit));
- if (Opts.ConstexprBacktraceLimit
- != DiagnosticOptions::DefaultConstexprBacktraceLimit)
- Res.push_back("-fconstexpr-backtrace-limit",
- llvm::utostr(Opts.ConstexprBacktraceLimit));
-
- if (Opts.TabStop != DiagnosticOptions::DefaultTabStop)
- Res.push_back("-ftabstop", llvm::utostr(Opts.TabStop));
- if (Opts.MessageLength)
- Res.push_back("-fmessage-length", llvm::utostr(Opts.MessageLength));
- if (!Opts.DumpBuildInformation.empty())
- Res.push_back("-dump-build-information", Opts.DumpBuildInformation);
- for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i)
- Res.push_back("-W" + Opts.Warnings[i]);
-}
-
-static const char *getInputKindName(InputKind Kind) {
- switch (Kind) {
- case IK_None: break;
- case IK_AST: return "ast";
- case IK_Asm: return "assembler-with-cpp";
- case IK_C: return "c";
- case IK_CXX: return "c++";
- case IK_LLVM_IR: return "ir";
- case IK_ObjC: return "objective-c";
- case IK_ObjCXX: return "objective-c++";
- case IK_OpenCL: return "cl";
- case IK_CUDA: return "cuda";
- case IK_PreprocessedC: return "cpp-output";
- case IK_PreprocessedCXX: return "c++-cpp-output";
- case IK_PreprocessedObjC: return "objective-c-cpp-output";
- case IK_PreprocessedObjCXX:return "objective-c++-cpp-output";
- }
-
- llvm_unreachable("Unexpected language kind!");
-}
-
-static const char *getActionName(frontend::ActionKind Kind) {
- switch (Kind) {
- case frontend::PluginAction:
- llvm_unreachable("Invalid kind!");
-
- case frontend::ASTDeclList: return "-ast-list";
- case frontend::ASTDump: return "-ast-dump";
- case frontend::ASTDumpXML: return "-ast-dump-xml";
- case frontend::ASTPrint: return "-ast-print";
- case frontend::ASTView: return "-ast-view";
- case frontend::DumpRawTokens: return "-dump-raw-tokens";
- case frontend::DumpTokens: return "-dump-tokens";
- case frontend::EmitAssembly: return "-S";
- case frontend::EmitBC: return "-emit-llvm-bc";
- case frontend::EmitHTML: return "-emit-html";
- case frontend::EmitLLVM: return "-emit-llvm";
- case frontend::EmitLLVMOnly: return "-emit-llvm-only";
- case frontend::EmitCodeGenOnly: return "-emit-codegen-only";
- case frontend::EmitObj: return "-emit-obj";
- case frontend::FixIt: return "-fixit";
- case frontend::GenerateModule: return "-emit-module";
- case frontend::GeneratePCH: return "-emit-pch";
- case frontend::GeneratePTH: return "-emit-pth";
- case frontend::InitOnly: return "-init-only";
- case frontend::ParseSyntaxOnly: return "-fsyntax-only";
- case frontend::PrintDeclContext: return "-print-decl-contexts";
- case frontend::PrintPreamble: return "-print-preamble";
- case frontend::PrintPreprocessedInput: return "-E";
- case frontend::RewriteMacros: return "-rewrite-macros";
- case frontend::RewriteObjC: return "-rewrite-objc";
- case frontend::RewriteTest: return "-rewrite-test";
- case frontend::RunAnalysis: return "-analyze";
- case frontend::MigrateSource: return "-migrate";
- case frontend::RunPreprocessorOnly: return "-Eonly";
- }
-
- llvm_unreachable("Unexpected language kind!");
-}
-
-static void FileSystemOptsToArgs(const FileSystemOptions &Opts, ToArgsList &Res){
- if (!Opts.WorkingDir.empty())
- Res.push_back("-working-directory", Opts.WorkingDir);
-}
-
-static void CodeCompleteOptionsToArgs(const CodeCompleteOptions &Opts,
- ToArgsList &Res) {
- if (Opts.IncludeMacros)
- Res.push_back("-code-completion-macros");
- if (Opts.IncludeCodePatterns)
- Res.push_back("-code-completion-patterns");
- if (!Opts.IncludeGlobals)
- Res.push_back("-no-code-completion-globals");
- if (Opts.IncludeBriefComments)
- Res.push_back("-code-completion-brief-comments");
-}
-
-static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) {
- if (Opts.DisableFree)
- Res.push_back("-disable-free");
- if (Opts.RelocatablePCH)
- Res.push_back("-relocatable-pch");
- if (Opts.ShowHelp)
- Res.push_back("-help");
- if (Opts.ShowStats)
- Res.push_back("-print-stats");
- if (Opts.ShowTimers)
- Res.push_back("-ftime-report");
- if (Opts.ShowVersion)
- Res.push_back("-version");
- if (Opts.FixWhatYouCan)
- Res.push_back("-fix-what-you-can");
- if (Opts.FixOnlyWarnings)
- Res.push_back("-fix-only-warnings");
- if (Opts.FixAndRecompile)
- Res.push_back("-fixit-recompile");
- if (Opts.FixToTemporaries)
- Res.push_back("-fixit-to-temporary");
- switch (Opts.ARCMTAction) {
- case FrontendOptions::ARCMT_None:
- break;
- case FrontendOptions::ARCMT_Check:
- Res.push_back("-arcmt-check");
- break;
- case FrontendOptions::ARCMT_Modify:
- Res.push_back("-arcmt-modify");
- break;
- case FrontendOptions::ARCMT_Migrate:
- Res.push_back("-arcmt-migrate");
- break;
- }
- CodeCompleteOptionsToArgs(Opts.CodeCompleteOpts, Res);
- if (!Opts.MTMigrateDir.empty())
- Res.push_back("-mt-migrate-directory", Opts.MTMigrateDir);
- if (!Opts.ARCMTMigrateReportOut.empty())
- Res.push_back("-arcmt-migrate-report-output", Opts.ARCMTMigrateReportOut);
- if (Opts.ARCMTMigrateEmitARCErrors)
- Res.push_back("-arcmt-migrate-emit-errors");
-
- if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals)
- Res.push_back("-objcmt-migrate-literals");
- if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting)
- Res.push_back("-objcmt-migrate-subscripting");
-
- bool NeedLang = false;
- for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
- if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) !=
- Opts.Inputs[i].Kind)
- NeedLang = true;
- if (NeedLang)
- Res.push_back("-x", getInputKindName(Opts.Inputs[0].Kind));
- for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) {
- assert((!NeedLang || Opts.Inputs[i].Kind == Opts.Inputs[0].Kind) &&
- "Unable to represent this input vector!");
- Res.push_back(Opts.Inputs[i].File);
- }
-
- if (!Opts.OutputFile.empty())
- Res.push_back("-o", Opts.OutputFile);
- if (!Opts.CodeCompletionAt.FileName.empty())
- Res.push_back("-code-completion-at",
- Opts.CodeCompletionAt.FileName + ":" +
- llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
- llvm::utostr(Opts.CodeCompletionAt.Column));
- if (Opts.ProgramAction != frontend::PluginAction)
- Res.push_back(getActionName(Opts.ProgramAction));
- if (!Opts.ActionName.empty()) {
- Res.push_back("-plugin", Opts.ActionName);
- for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i)
- Res.push_back("-plugin-arg-" + Opts.ActionName, Opts.PluginArgs[i]);
- }
- if (!Opts.ASTDumpFilter.empty())
- Res.push_back("-ast-dump-filter", Opts.ASTDumpFilter);
- for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i)
- Res.push_back("-load", Opts.Plugins[i]);
- for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
- Res.push_back("-add-plugin", Opts.AddPluginActions[i]);
- for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai)
- Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i],
- Opts.AddPluginArgs[i][ai]);
- }
- for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i)
- Res.push_back("-ast-merge", Opts.ASTMergeFiles[i]);
- for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i)
- Res.push_back("-mllvm", Opts.LLVMArgs[i]);
- if (!Opts.OverrideRecordLayoutsFile.empty())
- Res.push_back("-foverride-record-layout=" + Opts.OverrideRecordLayoutsFile);
-}
-
-static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
- ToArgsList &Res) {
- if (Opts.Sysroot != "/") {
- Res.push_back("-isysroot");
- Res.push_back(Opts.Sysroot);
- }
-
- /// User specified include entries.
- for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
- const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
- if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
- llvm::report_fatal_error("Invalid option set!");
- if (E.IsUserSupplied) {
- switch (E.Group) {
- case frontend::After:
- Res.push_back("-idirafter");
- break;
-
- case frontend::Quoted:
- Res.push_back("-iquote");
- break;
-
- case frontend::System:
- Res.push_back("-isystem");
- break;
-
- case frontend::IndexHeaderMap:
- Res.push_back("-index-header-map");
- Res.push_back(E.IsFramework? "-F" : "-I");
- break;
-
- case frontend::CSystem:
- Res.push_back("-c-isystem");
- break;
-
- case frontend::CXXSystem:
- Res.push_back("-cxx-isystem");
- break;
-
- case frontend::ObjCSystem:
- Res.push_back("-objc-isystem");
- break;
-
- case frontend::ObjCXXSystem:
- Res.push_back("-objcxx-isystem");
- break;
-
- case frontend::Angled:
- Res.push_back(E.IsFramework ? "-F" : "-I");
- break;
- }
- } else {
- if (E.IsInternal) {
- assert(E.Group == frontend::System && "Unexpected header search group");
- if (E.ImplicitExternC)
- Res.push_back("-internal-externc-isystem");
- else
- Res.push_back("-internal-isystem");
- } else {
- if (E.Group != frontend::Angled && E.Group != frontend::System)
- llvm::report_fatal_error("Invalid option set!");
- Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
- "-iwithprefix");
- }
- }
- Res.push_back(E.Path);
- }
-
- /// User-specified system header prefixes.
- for (unsigned i = 0, e = Opts.SystemHeaderPrefixes.size(); i != e; ++i) {
- if (Opts.SystemHeaderPrefixes[i].IsSystemHeader)
- Res.push_back("-isystem-prefix");
- else
- Res.push_back("-ino-system-prefix");
-
- Res.push_back(Opts.SystemHeaderPrefixes[i].Prefix);
- }
-
- if (!Opts.ResourceDir.empty())
- Res.push_back("-resource-dir", Opts.ResourceDir);
- if (!Opts.ModuleCachePath.empty())
- Res.push_back("-fmodule-cache-path", Opts.ModuleCachePath);
- if (!Opts.UseStandardSystemIncludes)
- Res.push_back("-nostdsysteminc");
- if (!Opts.UseStandardCXXIncludes)
- Res.push_back("-nostdinc++");
- if (Opts.UseLibcxx)
- Res.push_back("-stdlib=libc++");
- if (Opts.Verbose)
- Res.push_back("-v");
-}
-
-static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) {
- LangOptions DefaultLangOpts;
-
- // FIXME: Need to set -std to get all the implicit options.
-
- // FIXME: We want to only pass options relative to the defaults, which
- // requires constructing a target. :(
- //
- // It would be better to push the all target specific choices into the driver,
- // so that everything below that was more uniform.
-
- if (Opts.Trigraphs)
- Res.push_back("-trigraphs");
- // Implicit based on the input kind:
- // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL
- // Implicit based on the input language standard:
- // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
- if (Opts.DollarIdents)
- Res.push_back("-fdollars-in-identifiers");
- if (Opts.GNUMode && !Opts.GNUKeywords)
- Res.push_back("-fno-gnu-keywords");
- if (!Opts.GNUMode && Opts.GNUKeywords)
- Res.push_back("-fgnu-keywords");
- if (Opts.MicrosoftExt)
- Res.push_back("-fms-extensions");
- if (Opts.MicrosoftMode)
- Res.push_back("-fms-compatibility");
- if (Opts.MSCVersion != 0)
- Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion));
- if (Opts.Borland)
- Res.push_back("-fborland-extensions");
- if (Opts.ObjCDefaultSynthProperties)
- Res.push_back("-fobjc-default-synthesize-properties");
- // NoInline is implicit.
- if (!Opts.CXXOperatorNames)
- Res.push_back("-fno-operator-names");
- if (Opts.PascalStrings)
- Res.push_back("-fpascal-strings");
- if (Opts.CatchUndefined)
- Res.push_back("-fcatch-undefined-behavior");
- if (Opts.AddressSanitizer)
- Res.push_back("-faddress-sanitizer");
- if (Opts.ThreadSanitizer)
- Res.push_back("-fthread-sanitizer");
- if (Opts.WritableStrings)
- Res.push_back("-fwritable-strings");
- if (Opts.ConstStrings)
- Res.push_back("-fconst-strings");
- if (!Opts.LaxVectorConversions)
- Res.push_back("-fno-lax-vector-conversions");
- if (Opts.AltiVec)
- Res.push_back("-faltivec");
- if (Opts.Exceptions)
- Res.push_back("-fexceptions");
- if (Opts.ObjCExceptions)
- Res.push_back("-fobjc-exceptions");
- if (Opts.CXXExceptions)
- Res.push_back("-fcxx-exceptions");
- if (Opts.SjLjExceptions)
- Res.push_back("-fsjlj-exceptions");
- if (Opts.TraditionalCPP)
- Res.push_back("-traditional-cpp");
- if (!Opts.RTTI)
- Res.push_back("-fno-rtti");
- if (Opts.MSBitfields)
- Res.push_back("-mms-bitfields");
- if (Opts.Freestanding)
- Res.push_back("-ffreestanding");
- if (Opts.NoBuiltin)
- Res.push_back("-fno-builtin");
- if (!Opts.AssumeSaneOperatorNew)
- Res.push_back("-fno-assume-sane-operator-new");
- if (!Opts.ThreadsafeStatics)
- Res.push_back("-fno-threadsafe-statics");
- if (Opts.POSIXThreads)
- Res.push_back("-pthread");
- if (Opts.Blocks)
- Res.push_back("-fblocks");
- if (Opts.BlocksRuntimeOptional)
- Res.push_back("-fblocks-runtime-optional");
- if (Opts.Modules)
- Res.push_back("-fmodules");
- if (Opts.EmitAllDecls)
- Res.push_back("-femit-all-decls");
- if (Opts.MathErrno)
- Res.push_back("-fmath-errno");
- switch (Opts.getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined: break;
- case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break;
- case LangOptions::SOB_Trapping:
- Res.push_back("-ftrapv");
- if (!Opts.OverflowHandler.empty())
- Res.push_back("-ftrapv-handler", Opts.OverflowHandler);
- break;
- }
- switch (Opts.getFPContractMode()) {
- case LangOptions::FPC_Off: Res.push_back("-ffp-contract=off"); break;
- case LangOptions::FPC_On: Res.push_back("-ffp-contract=on"); break;
- case LangOptions::FPC_Fast: Res.push_back("-ffp-contract=fast"); break;
- }
- if (Opts.HeinousExtensions)
- Res.push_back("-fheinous-gnu-extensions");
- // Optimize is implicit.
- // OptimizeSize is implicit.
- if (Opts.FastMath)
- Res.push_back("-ffast-math");
- if (Opts.Static)
- Res.push_back("-static-define");
- if (Opts.DumpRecordLayoutsSimple)
- Res.push_back("-fdump-record-layouts-simple");
- else if (Opts.DumpRecordLayouts)
- Res.push_back("-fdump-record-layouts");
- if (Opts.DumpVTableLayouts)
- Res.push_back("-fdump-vtable-layouts");
- if (Opts.NoBitFieldTypeAlign)
- Res.push_back("-fno-bitfield-type-alignment");
- if (Opts.PICLevel)
- Res.push_back("-pic-level", llvm::utostr(Opts.PICLevel));
- if (Opts.PIELevel)
- Res.push_back("-pie-level", llvm::utostr(Opts.PIELevel));
- if (Opts.ObjCGCBitmapPrint)
- Res.push_back("-print-ivar-layout");
- if (Opts.NoConstantCFStrings)
- Res.push_back("-fno-constant-cfstrings");
- if (!Opts.AccessControl)
- Res.push_back("-fno-access-control");
- if (!Opts.CharIsSigned)
- Res.push_back("-fno-signed-char");
- if (Opts.ShortWChar)
- Res.push_back("-fshort-wchar");
- if (!Opts.ElideConstructors)
- Res.push_back("-fno-elide-constructors");
- if (Opts.getGC() != LangOptions::NonGC) {
- if (Opts.getGC() == LangOptions::HybridGC) {
- Res.push_back("-fobjc-gc");
- } else {
- assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!");
- Res.push_back("-fobjc-gc-only");
- }
- }
- Res.push_back("-fobjc-runtime=" + Opts.ObjCRuntime.getAsString());
- if (Opts.ObjCAutoRefCount)
- Res.push_back("-fobjc-arc");
- if (Opts.ObjCRuntimeHasWeak)
- Res.push_back("-fobjc-runtime-has-weak");
- if (!Opts.ObjCInferRelatedResultType)
- Res.push_back("-fno-objc-infer-related-result-type");
-
- if (Opts.AppleKext)
- Res.push_back("-fapple-kext");
-
- if (Opts.getVisibilityMode() != DefaultVisibility) {
- Res.push_back("-fvisibility");
- if (Opts.getVisibilityMode() == HiddenVisibility) {
- Res.push_back("hidden");
- } else {
- assert(Opts.getVisibilityMode() == ProtectedVisibility &&
- "Invalid visibility!");
- Res.push_back("protected");
- }
- }
- if (Opts.InlineVisibilityHidden)
- Res.push_back("-fvisibility-inlines-hidden");
-
- if (Opts.getStackProtector() != 0)
- Res.push_back("-stack-protector", llvm::utostr(Opts.getStackProtector()));
- if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth)
- Res.push_back("-ftemplate-depth", llvm::utostr(Opts.InstantiationDepth));
- if (Opts.ConstexprCallDepth != DefaultLangOpts.ConstexprCallDepth)
- Res.push_back("-fconstexpr-depth", llvm::utostr(Opts.ConstexprCallDepth));
- if (!Opts.ObjCConstantStringClass.empty())
- Res.push_back("-fconstant-string-class", Opts.ObjCConstantStringClass);
- if (Opts.FakeAddressSpaceMap)
- Res.push_back("-ffake-address-space-map");
- if (Opts.ParseUnknownAnytype)
- Res.push_back("-funknown-anytype");
- if (Opts.DebuggerSupport)
- Res.push_back("-fdebugger-support");
- if (Opts.DebuggerCastResultToId)
- Res.push_back("-fdebugger-cast-result-to-id");
- if (Opts.DebuggerObjCLiteral)
- Res.push_back("-fdebugger-objc-literal");
- if (Opts.DelayedTemplateParsing)
- Res.push_back("-fdelayed-template-parsing");
- if (Opts.Deprecated)
- Res.push_back("-fdeprecated-macro");
- if (Opts.ApplePragmaPack)
- Res.push_back("-fapple-pragma-pack");
- if (!Opts.CurrentModule.empty())
- Res.push_back("-fmodule-name=" + Opts.CurrentModule);
-}
-
-static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
- ToArgsList &Res) {
- for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
- Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") +
- Opts.Macros[i].first);
- for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
- // FIXME: We need to avoid reincluding the implicit PCH and PTH includes.
- Res.push_back("-include", Opts.Includes[i]);
- }
- for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i)
- Res.push_back("-imacros", Opts.MacroIncludes[i]);
- if (!Opts.UsePredefines)
- Res.push_back("-undef");
- if (Opts.DetailedRecord)
- Res.push_back("-detailed-preprocessing-record");
- if (!Opts.ImplicitPCHInclude.empty())
- Res.push_back("-include-pch", Opts.ImplicitPCHInclude);
- if (!Opts.ImplicitPTHInclude.empty())
- Res.push_back("-include-pth", Opts.ImplicitPTHInclude);
- if (!Opts.TokenCache.empty()) {
- if (Opts.ImplicitPTHInclude.empty())
- Res.push_back("-token-cache", Opts.TokenCache);
- else
- assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
- "Unsupported option combination!");
- }
- for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i)
- Res.push_back("-chain-include", Opts.ChainedIncludes[i]);
- for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) {
- Res.push_back("-remap-file", Opts.RemappedFiles[i].first + ";" +
- Opts.RemappedFiles[i].second);
- }
-}
-
-static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
- ToArgsList &Res) {
- if (!Opts.ShowCPP && !Opts.ShowMacros)
- llvm::report_fatal_error("Invalid option combination!");
-
- if (Opts.ShowCPP && Opts.ShowMacros)
- Res.push_back("-dD");
- else if (!Opts.ShowCPP && Opts.ShowMacros)
- Res.push_back("-dM");
-
- if (!Opts.ShowLineMarkers)
- Res.push_back("-P");
- if (Opts.ShowComments)
- Res.push_back("-C");
- if (Opts.ShowMacroComments)
- Res.push_back("-CC");
-}
-
-static void TargetOptsToArgs(const TargetOptions &Opts,
- ToArgsList &Res) {
- Res.push_back("-triple");
- Res.push_back(Opts.Triple);
- if (!Opts.CPU.empty())
- Res.push_back("-target-cpu", Opts.CPU);
- if (!Opts.ABI.empty())
- Res.push_back("-target-abi", Opts.ABI);
- if (!Opts.LinkerVersion.empty())
- Res.push_back("-target-linker-version", Opts.LinkerVersion);
- if (!Opts.CXXABI.empty())
- Res.push_back("-cxx-abi", Opts.CXXABI);
- for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i)
- Res.push_back("-target-feature", Opts.Features[i]);
-}
-
-void CompilerInvocation::toArgs(std::vector<std::string> &Res) const {
- ToArgsList List(Res);
- AnalyzerOptsToArgs(getAnalyzerOpts(), List);
- CodeGenOptsToArgs(getCodeGenOpts(), List);
- DependencyOutputOptsToArgs(getDependencyOutputOpts(), List);
- DiagnosticOptsToArgs(getDiagnosticOpts(), List);
- FileSystemOptsToArgs(getFileSystemOpts(), List);
- FrontendOptsToArgs(getFrontendOpts(), List);
- HeaderSearchOptsToArgs(getHeaderSearchOpts(), List);
- LangOptsToArgs(*getLangOpts(), List);
- PreprocessorOptsToArgs(getPreprocessorOpts(), List);
- PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), List);
- TargetOptsToArgs(getTargetOpts(), List);
-}
-
-//===----------------------------------------------------------------------===//
-// Deserialization (to args)
+// Deserialization (from args)
//===----------------------------------------------------------------------===//
using namespace clang::driver;
@@ -965,7 +71,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
assert (A->getOption().matches(options::OPT_O));
- llvm::StringRef S(A->getValue(Args));
+ llvm::StringRef S(A->getValue());
if (S == "s" || S == "z" || S.empty())
return 2;
@@ -979,7 +85,7 @@ static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O)) {
- switch (A->getValue(Args)[0]) {
+ switch (A->getValue()[0]) {
default:
return 0;
case 's':
@@ -996,14 +102,14 @@ static void addWarningArgs(ArgList &Args, std::vector<std::string> &Warnings) {
for (arg_iterator I = Args.filtered_begin(OPT_W_Group),
E = Args.filtered_end(); I != E; ++I) {
Arg *A = *I;
- // If the argument is a pure flag, add its name (minus the "-W" at the beginning)
+ // If the argument is a pure flag, add its name (minus the "W" at the beginning)
// to the warning list. Else, add its value (for the OPT_W case).
if (A->getOption().getKind() == Option::FlagClass) {
- Warnings.push_back(A->getOption().getName().substr(2));
+ Warnings.push_back(A->getOption().getName().substr(1));
} else {
for (unsigned Idx = 0, End = A->getNumValues();
Idx < End; ++Idx) {
- StringRef V = A->getValue(Args, Idx);
+ StringRef V = A->getValue(Idx);
// "-Wl," and such are not warning options.
// FIXME: Should be handled by putting these in separate flags.
if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,"))
@@ -1020,11 +126,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
using namespace options;
bool Success = true;
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, NAME##Model)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumStores);
if (Value == NumStores) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1036,11 +142,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, NAME##Model)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumConstraints);
if (Value == NumConstraints) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1052,11 +158,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \
.Case(CMDFLAG, PD_##NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NUM_ANALYSIS_DIAG_CLIENTS);
if (Value == NUM_ANALYSIS_DIAG_CLIENTS) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1068,11 +174,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name)
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
.Case(CMDFLAG, NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumPurgeModes);
if (Value == NumPurgeModes) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1084,11 +190,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name)
#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
.Case(CMDFLAG, NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumIPAModes);
if (Value == NumIPAModes) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1100,11 +206,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
.Case(CMDFLAG, NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumInliningModes);
if (Value == NumInliningModes) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1116,21 +222,21 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
- Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
- Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
+ Opts.visualizeExplodedGraphWithGraphViz =
+ Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
+ Opts.visualizeExplodedGraphWithUbiGraph =
+ Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted);
Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers);
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
Opts.AnalyzeNestedBlocks =
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
- Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
+ Opts.eagerlyAssumeBinOpBifurcation = Args.hasArg(OPT_analyzer_eagerly_assume);
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
- Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
- Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
- Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph);
+ 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,
@@ -1148,12 +254,42 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
bool enable = (A->getOption().getID() == OPT_analyzer_checker);
// We can have a list of comma separated checker names, e.g:
// '-analyzer-checker=cocoa,unix'
- StringRef checkerList = A->getValue(Args);
+ StringRef checkerList = A->getValue();
SmallVector<StringRef, 4> checkers;
checkerList.split(checkers, ",");
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable));
}
+
+ // Go through the analyzer configuration options.
+ for (arg_iterator it = Args.filtered_begin(OPT_analyzer_config),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ A->claim();
+ // We can have a list of comma separated config names, e.g:
+ // '-analyzer-config key1=val1,key2=val2'
+ StringRef configList = A->getValue();
+ SmallVector<StringRef, 4> configVals;
+ configList.split(configVals, ",");
+ for (unsigned i = 0, e = configVals.size(); i != e; ++i) {
+ StringRef key, val;
+ llvm::tie(key, val) = configVals[i].split("=");
+ if (val.empty()) {
+ Diags.Report(SourceLocation(),
+ diag::err_analyzer_config_no_value) << configVals[i];
+ Success = false;
+ break;
+ }
+ if (val.find('=') != StringRef::npos) {
+ Diags.Report(SourceLocation(),
+ diag::err_analyzer_config_multiple_values)
+ << configVals[i];
+ Success = false;
+ break;
+ }
+ Opts.Config[key] = val;
+ }
+ }
return Success;
}
@@ -1179,21 +315,23 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.OptimizationLevel = OptLevel;
// We must always run at least the always inlining pass.
- Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
- : CodeGenOptions::OnlyAlwaysInlining;
+ Opts.setInlining(
+ (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
+ : CodeGenOptions::OnlyAlwaysInlining);
// -fno-inline-functions overrides OptimizationLevel > 1.
Opts.NoInline = Args.hasArg(OPT_fno_inline);
- Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ?
- CodeGenOptions::OnlyAlwaysInlining : Opts.Inlining;
+ Opts.setInlining(Args.hasArg(OPT_fno_inline_functions) ?
+ CodeGenOptions::OnlyAlwaysInlining : Opts.getInlining());
if (Args.hasArg(OPT_gline_tables_only)) {
- Opts.DebugInfo = CodeGenOptions::DebugLineTablesOnly;
+ Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly);
} else if (Args.hasArg(OPT_g_Flag)) {
if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true))
- Opts.DebugInfo = CodeGenOptions::LimitedDebugInfo;
+ Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo);
else
- Opts.DebugInfo = CodeGenOptions::FullDebugInfo;
+ Opts.setDebugInfo(CodeGenOptions::FullDebugInfo);
}
+ Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
@@ -1263,18 +401,21 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
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);
- Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm);
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
+ Opts.SSPBufferSize =
+ Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
if (Arg *A = Args.getLastArg(OPT_mstack_alignment)) {
- StringRef Val = A->getValue(Args);
- Val.getAsInteger(10, Opts.StackAlignment);
+ StringRef Val = A->getValue();
+ unsigned StackAlignment = Opts.StackAlignment;
+ Val.getAsInteger(10, StackAlignment);
+ Opts.StackAlignment = StackAlignment;
}
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
unsigned Method = llvm::StringSwitch<unsigned>(Name)
.Case("legacy", CodeGenOptions::Legacy)
.Case("non-legacy", CodeGenOptions::NonLegacy)
@@ -1284,12 +425,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
Success = false;
} else {
- Opts.ObjCDispatchMethod = Method;
+ Opts.setObjCDispatchMethod(
+ static_cast<CodeGenOptions::ObjCDispatchMethodKind>(Method));
}
}
if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
unsigned Model = llvm::StringSwitch<unsigned>(Name)
.Case("global-dynamic", CodeGenOptions::GeneralDynamicTLSModel)
.Case("local-dynamic", CodeGenOptions::LocalDynamicTLSModel)
@@ -1300,7 +442,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
Success = false;
} else {
- Opts.DefaultTLSModel = static_cast<CodeGenOptions::TLSModel>(Model);
+ Opts.setDefaultTLSModel(static_cast<CodeGenOptions::TLSModel>(Model));
}
}
@@ -1351,9 +493,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
StringRef ShowOverloads =
Args.getLastArgValue(OPT_fshow_overloads_EQ, "all");
if (ShowOverloads == "best")
- Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best;
+ Opts.setShowOverloads(Ovl_Best);
else if (ShowOverloads == "all")
- Opts.ShowOverloads = DiagnosticsEngine::Ovl_All;
+ Opts.setShowOverloads(Ovl_All);
else {
Success = false;
if (Diags)
@@ -1381,11 +523,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
StringRef Format =
Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
if (Format == "clang")
- Opts.Format = DiagnosticOptions::Clang;
+ Opts.setFormat(DiagnosticOptions::Clang);
else if (Format == "msvc")
- Opts.Format = DiagnosticOptions::Msvc;
+ Opts.setFormat(DiagnosticOptions::Msvc);
else if (Format == "vi")
- Opts.Format = DiagnosticOptions::Vi;
+ Opts.setFormat(DiagnosticOptions::Vi);
else {
Success = false;
if (Diags)
@@ -1467,7 +609,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
case OPT_emit_obj:
Opts.ProgramAction = frontend::EmitObj; break;
case OPT_fixit_EQ:
- Opts.FixItSuffix = A->getValue(Args);
+ Opts.FixItSuffix = A->getValue();
// fall-through!
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
@@ -1503,14 +645,14 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
}
if (const Arg* A = Args.getLastArg(OPT_plugin)) {
- Opts.Plugins.push_back(A->getValue(Args,0));
+ Opts.Plugins.push_back(A->getValue(0));
Opts.ProgramAction = frontend::PluginAction;
- Opts.ActionName = A->getValue(Args);
+ Opts.ActionName = A->getValue();
for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
end = Args.filtered_end(); it != end; ++it) {
- if ((*it)->getValue(Args, 0) == Opts.ActionName)
- Opts.PluginArgs.push_back((*it)->getValue(Args, 1));
+ if ((*it)->getValue(0) == Opts.ActionName)
+ Opts.PluginArgs.push_back((*it)->getValue(1));
}
}
@@ -1519,17 +661,17 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
end = Args.filtered_end(); it != end; ++it) {
- if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i])
- Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1));
+ if ((*it)->getValue(0) == Opts.AddPluginActions[i])
+ Opts.AddPluginArgs[i].push_back((*it)->getValue(1));
}
}
if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
Opts.CodeCompletionAt =
- ParsedSourceLocation::FromString(A->getValue(Args));
+ ParsedSourceLocation::FromString(A->getValue());
if (Opts.CodeCompletionAt.FileName.empty())
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
}
Opts.DisableFree = Args.hasArg(OPT_disable_free);
@@ -1595,7 +737,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
InputKind DashX = IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
- DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
+ DashX = llvm::StringSwitch<InputKind>(A->getValue())
.Case("c", IK_C)
.Case("cl", IK_OpenCL)
.Case("cuda", IK_CUDA)
@@ -1619,7 +761,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Default(IK_None);
if (DashX == IK_None)
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
}
// '-' is the default input if none is given.
@@ -1667,7 +809,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc);
Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx);
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
- Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0);
+ Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path);
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
@@ -1686,7 +828,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
frontend::IncludeDirGroup Group
= IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled;
- Opts.AddPath((*it)->getValue(Args), Group, true,
+ Opts.AddPath((*it)->getValue(), Group, true,
/*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
IsIndexHeaderMap = false;
}
@@ -1698,43 +840,43 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
if (A->getOption().matches(OPT_iprefix))
- Prefix = A->getValue(Args);
+ Prefix = A->getValue();
else if (A->getOption().matches(OPT_iwithprefix))
- Opts.AddPath(Prefix.str() + A->getValue(Args),
+ Opts.AddPath(Prefix.str() + A->getValue(),
frontend::System, false, false, false);
else
- Opts.AddPath(Prefix.str() + A->getValue(Args),
+ Opts.AddPath(Prefix.str() + A->getValue(),
frontend::Angled, false, false, false);
}
for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::After, true, false, false);
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false);
for (arg_iterator it = Args.filtered_begin(OPT_isystem,
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::System, true, false,
+ Opts.AddPath((*it)->getValue(), frontend::System, true, 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(Args), frontend::System, true, true,
+ Opts.AddPath((*it)->getValue(), frontend::System, true, 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(Args), frontend::CSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CSystem, true, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true);
+ Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true);
for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false,
+ Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false,
true);
// Add the internal paths from a driver that detects standard include paths.
@@ -1742,7 +884,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
OPT_internal_externc_isystem),
E = Args.filtered_end();
I != E; ++I)
- Opts.AddPath((*I)->getValue(Args), frontend::System,
+ Opts.AddPath((*I)->getValue(), frontend::System,
false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true,
(*I)->getOption().matches(OPT_internal_externc_isystem));
@@ -1751,7 +893,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
OPT_ino_system_prefix),
E = Args.filtered_end();
I != E; ++I)
- Opts.AddSystemHeaderPrefix((*I)->getValue(Args),
+ Opts.AddSystemHeaderPrefix((*I)->getValue(),
(*I)->getOption().matches(OPT_isystem_prefix));
}
@@ -1799,11 +941,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
- Opts.BCPLComment = Std.hasBCPLComments();
+ Opts.LineComment = Std.hasLineComments();
Opts.C99 = Std.isC99();
Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.CPlusPlus1y = Std.isCPlusPlus1y();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUInline = !Std.isC99();
@@ -1838,6 +981,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+ // C++ has wchar_t keyword.
+ Opts.WChar = Opts.CPlusPlus;
+
Opts.GNUKeywords = Opts.GNUMode;
Opts.CXXOperatorNames = Opts.CPlusPlus;
@@ -1853,14 +999,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// FIXME: Cleanup per-file based stuff.
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
- LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+ LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
#define LANGSTANDARD(id, name, desc, features) \
.Case(name, LangStandard::lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(LangStandard::lang_unspecified);
if (LangStd == LangStandard::lang_unspecified)
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
else {
// Valid standard, check to make sure language and standard are compatable.
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
@@ -1901,7 +1047,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// Override the -std option in this case.
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
LangStandard::Kind OpenCLLangStd
- = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+ = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
.Case("CL", LangStandard::lang_opencl)
.Case("CL1.1", LangStandard::lang_opencl11)
.Case("CL1.2", LangStandard::lang_opencl12)
@@ -1909,7 +1055,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (OpenCLLangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
}
else
LangStd = OpenCLLangStd;
@@ -1930,7 +1076,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Opts.ObjC1) {
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
- StringRef value = arg->getValue(Args);
+ StringRef value = arg->getValue();
if (Opts.ObjCRuntime.tryParse(value))
Diags.Report(diag::err_drv_unknown_objc_runtime) << value;
}
@@ -1941,14 +1087,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.setGC(LangOptions::HybridGC);
else if (Args.hasArg(OPT_fobjc_arc)) {
Opts.ObjCAutoRefCount = 1;
- if (!Opts.ObjCRuntime.isNonFragile())
- Diags.Report(diag::err_arc_nonfragile_abi);
+ if (!Opts.ObjCRuntime.allowsARC())
+ Diags.Report(diag::err_arc_unsupported_on_runtime);
+
+ // Only set ObjCARCWeak if ARC is enabled.
+ if (Args.hasArg(OPT_fobjc_runtime_has_weak))
+ Opts.ObjCARCWeak = 1;
+ else
+ Opts.ObjCARCWeak = Opts.ObjCRuntime.allowsWeak();
}
- Opts.ObjCRuntimeHasWeak = Opts.ObjCRuntime.hasWeak();
- if (Args.hasArg(OPT_fobjc_runtime_has_weak))
- Opts.ObjCRuntimeHasWeak = 1;
-
if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
Opts.ObjCInferRelatedResultType = 0;
}
@@ -1990,7 +1138,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
<< Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
- StringRef Val = A->getValue(Args);
+ StringRef Val = A->getValue();
if (Val == "fast")
Opts.setFPContractMode(LangOptions::FPC_Fast);
else if (Val == "on")
@@ -2043,6 +1191,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
+ Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
@@ -2064,7 +1213,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.getLastArgValue(OPT_fconstant_string_class);
Opts.ObjCDefaultSynthProperties =
Args.hasArg(OPT_fobjc_default_synthesize_properties);
- Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
+ Opts.EncodeExtendedBlockSig =
+ Args.hasArg(OPT_fencode_extended_block_signature);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct_EQ, 0, Diags);
Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
@@ -2085,8 +1235,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support);
Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id);
Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
- Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer);
- Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer);
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
@@ -2109,6 +1257,11 @@ 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);
+
unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
switch (SSP) {
default:
@@ -2119,6 +1272,37 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
case 1: Opts.setStackProtector(LangOptions::SSPOn); break;
case 2: Opts.setStackProtector(LangOptions::SSPReq); break;
}
+
+ // Parse -fsanitize= arguments.
+ std::vector<std::string> Sanitizers = Args.getAllArgValues(OPT_fsanitize_EQ);
+ for (unsigned I = 0, N = Sanitizers.size(); I != N; ++I) {
+ // Since the Opts.Sanitize* values are bitfields, it's a little tricky to
+ // efficiently map string values to them. Perform the mapping indirectly:
+ // convert strings to enumerated values, then switch over the enum to set
+ // the right bitfield value.
+ enum Sanitizer {
+#define SANITIZER(NAME, ID) \
+ ID,
+#include "clang/Basic/Sanitizers.def"
+ Unknown
+ };
+ switch (llvm::StringSwitch<unsigned>(Sanitizers[I])
+#define SANITIZER(NAME, ID) \
+ .Case(NAME, ID)
+#include "clang/Basic/Sanitizers.def"
+ .Default(Unknown)) {
+#define SANITIZER(NAME, ID) \
+ case ID: \
+ Opts.Sanitize##ID = true; \
+ break;
+#include "clang/Basic/Sanitizers.def"
+
+ case Unknown:
+ Diags.Report(diag::err_drv_invalid_value)
+ << "-fsanitize=" << Sanitizers[I];
+ break;
+ }
+ }
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
@@ -2128,7 +1312,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
if (const Arg *A = Args.getLastArg(OPT_token_cache))
- Opts.TokenCache = A->getValue(Args);
+ Opts.TokenCache = A->getValue();
else
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
@@ -2139,11 +1323,11 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args));
+ Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue());
}
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
- StringRef Value(A->getValue(Args));
+ StringRef Value(A->getValue());
size_t Comma = Value.find(',');
unsigned Bytes = 0;
unsigned EndOfLine = 0;
@@ -2162,9 +1346,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {
if ((*it)->getOption().matches(OPT_D))
- Opts.addMacroDef((*it)->getValue(Args));
+ Opts.addMacroDef((*it)->getValue());
else
- Opts.addMacroUndef((*it)->getValue(Args));
+ Opts.addMacroUndef((*it)->getValue());
}
Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros);
@@ -2174,22 +1358,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
OPT_include_pth),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- // PCH is handled specially, we need to extra the original include path.
- if (A->getOption().matches(OPT_include_pch)) {
- std::string OriginalFile =
- ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags);
- if (OriginalFile.empty())
- continue;
-
- Opts.Includes.push_back(OriginalFile);
- } else
- Opts.Includes.push_back(A->getValue(Args));
+ Opts.Includes.push_back(A->getValue());
}
for (arg_iterator it = Args.filtered_begin(OPT_chain_include),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- Opts.ChainedIncludes.push_back(A->getValue(Args));
+ Opts.ChainedIncludes.push_back(A->getValue());
}
// Include 'altivec.h' if -faltivec option present
@@ -2200,7 +1375,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
std::pair<StringRef,StringRef> Split =
- StringRef(A->getValue(Args)).split(';');
+ StringRef(A->getValue()).split(';');
if (Split.second.empty()) {
Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args);
@@ -2211,7 +1386,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
unsigned Library = llvm::StringSwitch<unsigned>(Name)
.Case("libc++", ARCXX_libcxx)
.Case("libstdc++", ARCXX_libstdcxx)
@@ -2240,7 +1415,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
Opts.ABI = Args.getLastArgValue(OPT_target_abi);
Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi);
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
- Opts.Features = Args.getAllArgValues(OPT_target_feature);
+ Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
@@ -2280,13 +1455,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// Issue errors on arguments that are not valid for CC1.
for (ArgList::iterator I = Args->begin(), E = Args->end();
I != E; ++I) {
- if (!(*I)->getOption().isCC1Option()) {
+ if (!(*I)->getOption().hasFlag(options::CC1Option)) {
Diags.Report(diag::err_drv_unknown_argument) << (*I)->getAsString(*Args);
Success = false;
}
}
- Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success;
+ Success = ParseAnalyzerArgs(*Res.getAnalyzerOpts(), *Args, Diags) && Success;
Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success;
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags)
@@ -2368,53 +1543,49 @@ llvm::APInt ModuleSignature::getAsInteger() const {
}
std::string CompilerInvocation::getModuleHash() const {
- ModuleSignature Signature;
-
+ using llvm::hash_code;
+ using llvm::hash_value;
+ using llvm::hash_combine;
+
// Start the signature with the compiler version.
- // FIXME: The full version string can be quite long. Omit it from the
- // module hash for now to avoid failures where the path name becomes too
- // long. An MD5 or similar checksum would work well here.
- // Signature.add(getClangFullRepositoryVersion());
-
+ // FIXME: We'd rather use something more cryptographically sound than
+ // CityHash, but this will do for now.
+ hash_code code = hash_value(getClangFullRepositoryVersion());
+
// Extend the signature with the language options
#define LANGOPT(Name, Bits, Default, Description) \
- Signature.add(LangOpts->Name, Bits);
+ code = hash_combine(code, LangOpts->Name);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- Signature.add(static_cast<unsigned>(LangOpts->get##Name()), Bits);
+ code = hash_combine(code, static_cast<unsigned>(LangOpts->get##Name()));
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- // Extend the signature with the target triple
- llvm::Triple T(TargetOpts.Triple);
- Signature.add((unsigned)T.getArch(), 5);
- Signature.add((unsigned)T.getVendor(), 4);
- Signature.add((unsigned)T.getOS(), 5);
- Signature.add((unsigned)T.getEnvironment(), 4);
+ // Extend the signature with the target options.
+ code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU,
+ TargetOpts->ABI, TargetOpts->CXXABI,
+ TargetOpts->LinkerVersion);
+ for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i)
+ code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]);
// Extend the signature with preprocessor options.
- Signature.add(getPreprocessorOpts().UsePredefines, 1);
- Signature.add(getPreprocessorOpts().DetailedRecord, 1);
-
- // Hash the preprocessor defines.
- // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines.
+ const PreprocessorOptions &ppOpts = getPreprocessorOpts();
+ code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
+
std::vector<StringRef> MacroDefs;
for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
I = getPreprocessorOpts().Macros.begin(),
IEnd = getPreprocessorOpts().Macros.end();
I != IEnd; ++I) {
- if (!I->second)
- MacroDefs.push_back(I->first);
+ code = hash_combine(code, I->first, I->second);
}
- llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end());
-
- unsigned PPHashResult = 0;
- for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I)
- PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult);
- Signature.add(PPHashResult, 32);
-
- // We've generated the signature. Treat it as one large APInt that we'll
- // encode in base-36 and return.
- Signature.flush();
- return Signature.getAsInteger().toString(36, /*Signed=*/false);
+
+ // Extend the signature with the sysroot.
+ const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
+ code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
+ hsOpts.UseStandardSystemIncludes,
+ hsOpts.UseStandardCXXIncludes,
+ hsOpts.UseLibcxx);
+
+ return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 0aca86e2c97f..d82cb6d05157 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/Utils.h"
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -34,8 +34,8 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgList.size(),
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ ArgList.size(),
ArgList.begin());
}
@@ -49,11 +49,6 @@ 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);
- // Force driver to use clang.
- // FIXME: This seems like a hack. Maybe the "Clang" tool subclass should be
- // available for using it to get the arguments, thus avoiding the overkill
- // of using the driver.
- TheDriver.setForcedClangUse();
// 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 21f5daa9ee39..53ea8befbc09 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -59,10 +59,11 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
virtual void EndOfMainFile() {
OutputDependencyFile();
@@ -132,10 +133,11 @@ void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
if (!File) {
if (AddMissingHeaderDeps)
AddFilename(FileName);
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index eebaf0c8fe48..28d9c5d320e2 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -51,10 +51,11 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
virtual void EndOfMainFile() {
OutputGraphFile();
@@ -72,10 +73,11 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
if (!File)
return;
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index f052f90fa953..359b82be6062 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Edit/EditedSource.h"
#include "clang/Edit/Commit.h"
@@ -18,6 +18,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include <algorithm>
using namespace clang;
@@ -60,8 +61,8 @@ static StringRef getImmediateMacroName(SourceLocation Loc,
}
DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
-: LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
+ DiagnosticOptions *DiagOpts)
+ : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
DiagnosticRenderer::~DiagnosticRenderer() {}
@@ -194,7 +195,7 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
return;
LastIncludeLoc = Loc;
- if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+ if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
return;
emitIncludeStackRecursively(Loc, SM);
@@ -218,6 +219,53 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
emitIncludeLocation(Loc, PLoc, SM);
}
+// 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.
+//
+// To find locations which correspond to the caret, we crawl the macro caller
+// chain for the beginning and end of each range. If the caret location
+// is in a macro expansion, we search each chain for a location
+// in the same expansion as the caret; otherwise, we crawl to the top of
+// each chain. Two locations are part of the same macro expansion
+// iff the FileID is the same.
+static void mapDiagnosticRanges(
+ SourceLocation CaretLoc,
+ const SmallVectorImpl<CharSourceRange>& Ranges,
+ SmallVectorImpl<CharSourceRange>& SpellingRanges,
+ const SourceManager *SM) {
+ FileID CaretLocFileID = SM->getFileID(CaretLoc);
+
+ for (SmallVectorImpl<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);
+
+ // 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)) {
+ End = SM->getImmediateSpellingLoc(End);
+ } else {
+ End = SM->getImmediateExpansionRange(End).second;
+ }
+ }
+
+ // Return the spelling location of the beginning and end of the range.
+ Begin = SM->getSpellingLoc(Begin);
+ End = SM->getSpellingLoc(End);
+ SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
+ IsTokenRange));
+ }
+}
+
/// \brief Recursively emit notes for each macro expansion and caret
/// diagnostics where appropriate.
///
@@ -245,9 +293,13 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
// 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, Ranges, Hints, SM);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
return;
}
// Otherwise recurse through each macro expansion layer.
@@ -257,8 +309,7 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
Loc = SM.skipToMacroArgExpansion(Loc);
SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc);
-
- // FIXME: Map ranges?
+
emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth,
OnMacroInst + 1);
@@ -269,28 +320,17 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
Loc = SM.getImmediateMacroCalleeLoc(Loc);
unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
- if (MacroDepth > DiagOpts.MacroBacktraceLimit &&
- DiagOpts.MacroBacktraceLimit != 0) {
- MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
- DiagOpts.MacroBacktraceLimit % 2;
- MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
+ if (MacroDepth > DiagOpts->MacroBacktraceLimit &&
+ DiagOpts->MacroBacktraceLimit != 0) {
+ MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
+ DiagOpts->MacroBacktraceLimit % 2;
+ MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2;
}
// Whether to suppress printing this macro expansion.
bool Suppressed = (OnMacroInst >= MacroSkipStart &&
OnMacroInst < MacroSkipEnd);
- // Map the ranges.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- SourceLocation Start = I->getBegin(), End = I->getEnd();
- if (Start.isMacroID())
- I->setBegin(SM.getImmediateMacroCalleeLoc(Start));
- if (End.isMacroID())
- I->setEnd(SM.getImmediateMacroCalleeLoc(End));
- }
-
if (Suppressed) {
// Tell the user that we've skipped contexts.
if (OnMacroInst == MacroSkipStart) {
@@ -303,14 +343,18 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
}
return;
}
-
+
+ // Map the ranges.
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(MacroLoc, 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,
Message.str(),
- Ranges, ArrayRef<FixItHint>(), &SM);
+ SpellingRanges, ArrayRef<FixItHint>(), &SM);
}
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index a4321e720ed0..2e9a791c3039 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -23,10 +23,12 @@
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Timer.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/system_error.h"
+#include "llvm/Support/Timer.h"
using namespace clang;
namespace {
@@ -155,20 +157,22 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return new MultiplexConsumer(Consumers);
}
+
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
- assert(!Input.File.empty() && "Unexpected empty filename!");
+ assert(!Input.isEmpty() && "Unexpected empty filename!");
setCurrentInput(Input);
setCompilerInstance(&CI);
+ StringRef InputFile = Input.getFile();
bool HasBegunSourceFile = false;
if (!BeginInvocation(CI))
goto failure;
// AST files follow a very different path, since they share objects via the
// AST unit.
- if (Input.Kind == IK_AST) {
+ if (Input.getKind() == IK_AST) {
assert(!usesPreprocessorOnly() &&
"Attempt to pass AST file to preprocessor only action!");
assert(hasASTFileSupport() &&
@@ -176,7 +180,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::string Error;
- ASTUnit *AST = ASTUnit::LoadFromASTFile(Input.File, Diags,
+ ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags,
CI.getFileSystemOpts());
if (!AST)
goto failure;
@@ -191,11 +195,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.setASTContext(&AST->getASTContext());
// Initialize the action.
- if (!BeginSourceFileAction(CI, Input.File))
+ if (!BeginSourceFileAction(CI, InputFile))
goto failure;
/// Create the AST consumer.
- CI.setASTConsumer(CreateWrappedASTConsumer(CI, Input.File));
+ CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
if (!CI.hasASTConsumer())
goto failure;
@@ -209,7 +213,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createSourceManager(CI.getFileManager());
// IR files bypass the rest of initialization.
- if (Input.Kind == IK_LLVM_IR) {
+ if (Input.getKind() == IK_LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -218,12 +222,51 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, Input.File))
+ if (!BeginSourceFileAction(CI, InputFile))
goto failure;
return true;
}
+ // If the implicit PCH include is actually a directory, rather than
+ // a single file, search for a suitable PCH file in that directory.
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ FileManager &FileMgr = CI.getFileManager();
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
+ if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
+ llvm::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(PCHDir->getName(), DirNative);
+ bool Found = false;
+ for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ // Check whether this is an acceptable AST file.
+ if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr,
+ 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?");
+ break;
+ }
+ }
+
+ if (!Found) {
+ CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude;
+ return true;
+ }
+ }
+ }
+
// Set up the preprocessor.
CI.createPreprocessor();
@@ -233,7 +276,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, Input.File))
+ if (!BeginSourceFileAction(CI, InputFile))
goto failure;
/// Create the AST context and consumer unless this is a preprocessor only
@@ -242,12 +285,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createASTContext();
OwningPtr<ASTConsumer> Consumer(
- CreateWrappedASTConsumer(CI, Input.File));
+ CreateWrappedASTConsumer(CI, InputFile));
if (!Consumer)
goto failure;
CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
-
+ CI.getPreprocessor().setPPMutationListener(
+ Consumer->GetPPMutationListener());
+
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
OwningPtr<ExternalASTSource> source;
@@ -270,7 +315,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createPCHExternalASTSource(
CI.getPreprocessorOpts().ImplicitPCHInclude,
CI.getPreprocessorOpts().DisablePCHValidation,
- CI.getPreprocessorOpts().DisableStatCache,
CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
DeserialListener);
if (!CI.getASTContext().getExternalSource())
@@ -314,6 +358,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
+ CI.clearOutputFiles(/*EraseFiles=*/true);
setCurrentInput(FrontendInputFile());
setCompilerInstance(0);
return false;
@@ -325,10 +370,7 @@ bool FrontendAction::Execute() {
// Initialize the main file entry. This needs to be delayed until after PCH
// has loaded.
if (!isCurrentFileAST()) {
- if (!CI.InitializeSourceManager(getCurrentFile(),
- getCurrentInput().IsSystem
- ? SrcMgr::C_System
- : SrcMgr::C_User))
+ if (!CI.InitializeSourceManager(getCurrentInput()))
return false;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 24960cf6a0c9..47063f78b5d9 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -131,8 +131,31 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
Sysroot, OS);
}
+static SmallVectorImpl<char> &
+operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+ Includes.append(RHS.begin(), RHS.end());
+ return Includes;
+}
+
+static void addHeaderInclude(StringRef HeaderName,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts) {
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+ Includes += HeaderName;
+ Includes += "\"\n";
+}
+
+static void addHeaderInclude(const FileEntry *Header,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts) {
+ addHeaderInclude(Header->getName(), Includes, LangOpts);
+}
+
/// \brief Collect the set of header includes needed to construct the given
-/// module.
+/// module and update the TopHeaders file set of the module.
///
/// \param Module The module we're collecting includes from.
///
@@ -142,30 +165,23 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
FileManager &FileMgr,
ModuleMap &ModMap,
clang::Module *Module,
- SmallString<256> &Includes) {
+ SmallVectorImpl<char> &Includes) {
// Don't collect any headers for unavailable modules.
if (!Module->isAvailable())
return;
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
- Includes += Module->Headers[I]->getName();
- Includes += "\"\n";
+ const FileEntry *Header = Module->Headers[I];
+ Module->TopHeaders.insert(Header);
+ addHeaderInclude(Header, Includes, LangOpts);
}
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
+ Module->TopHeaders.insert(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
- Includes += UmbrellaHeader->getName();
- Includes += "\"\n";
+ addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
}
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
// Add all of the headers we find in this subdirectory.
@@ -184,17 +200,14 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
// If this header is marked 'unavailable' in this module, don't include
// it.
- if (const FileEntry *Header = FileMgr.getFile(Dir->path()))
+ if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
if (ModMap.isHeaderInUnavailableModule(Header))
continue;
+ Module->TopHeaders.insert(Header);
+ }
// Include this header umbrella header for submodules.
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
- Includes += Dir->path();
- Includes += "\"\n";
+ addHeaderInclude(Dir->path(), Includes, LangOpts);
}
}
@@ -250,77 +263,29 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false;
}
- // Do we have an umbrella header for this module?
- const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
-
+ FileManager &FileMgr = CI.getFileManager();
+
// Collect the set of #includes we need to build the module.
SmallString<256> HeaderContents;
- collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(),
+ if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
+ addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts());
+ collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr,
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, HeaderContents);
- if (UmbrellaHeader && HeaderContents.empty()) {
- // Simple case: we have an umbrella header and there are no additional
- // includes, we can just parse the umbrella header directly.
- setCurrentInput(FrontendInputFile(UmbrellaHeader->getName(),
- getCurrentFileKind(),
- Module->IsSystem));
- return true;
- }
-
- FileManager &FileMgr = CI.getFileManager();
- SmallString<128> HeaderName;
- time_t ModTime;
- if (UmbrellaHeader) {
- // Read in the umbrella header.
- // FIXME: Go through the source manager; the umbrella header may have
- // been overridden.
- std::string ErrorStr;
- llvm::MemoryBuffer *UmbrellaContents
- = FileMgr.getBufferForFile(UmbrellaHeader, &ErrorStr);
- if (!UmbrellaContents) {
- CI.getDiagnostics().Report(diag::err_missing_umbrella_header)
- << UmbrellaHeader->getName() << ErrorStr;
- return false;
- }
-
- // Combine the contents of the umbrella header with the automatically-
- // generated includes.
- SmallString<256> OldContents = HeaderContents;
- HeaderContents = UmbrellaContents->getBuffer();
- HeaderContents += "\n\n";
- HeaderContents += "/* Module includes */\n";
- HeaderContents += OldContents;
-
- // Pretend that we're parsing the umbrella header.
- HeaderName = UmbrellaHeader->getName();
- ModTime = UmbrellaHeader->getModificationTime();
-
- delete UmbrellaContents;
- } else {
- // Pick an innocuous-sounding name for the umbrella header.
- HeaderName = Module->Name + ".h";
- if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
- /*CacheFailure=*/false)) {
- // Try again!
- HeaderName = Module->Name + "-module.h";
- if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
- /*CacheFailure=*/false)) {
- // Pick something ridiculous and go with it.
- HeaderName = Module->Name + "-module.hmod";
- }
- }
- ModTime = time(0);
- }
-
- // Remap the contents of the header name we're using to our synthesized
- // buffer.
- const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName,
+
+ 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(),
- ModTime);
+ time(0));
llvm::MemoryBuffer *HeaderContentsBuf
= llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
- setCurrentInput(FrontendInputFile(HeaderName, getCurrentFileKind(),
+ setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(),
Module->IsSystem));
return true;
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 8178f7a9362a..4fddd112df7e 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -14,7 +14,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Frontend/HeaderSearchOptions.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -320,7 +320,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
P.appendComponent("../../../include"); // <sysroot>/include
AddPath(P.str(), System, true, false, false);
AddPath("/mingw/include", System, true, false, false);
+#if defined(_WIN32)
AddPath("c:/mingw/include", System, true, false, false);
+#endif
}
break;
@@ -396,12 +398,14 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0");
// mingw.org C++ include paths
AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS
+#if defined(_WIN32)
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
+#endif
break;
case llvm::Triple::DragonFly:
AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 1440da6e3755..4bbd033f1c2e 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -17,11 +17,12 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
-#include "clang/Frontend/PreprocessorOptions.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"
#include "llvm/Support/MemoryBuffer.h"
@@ -83,6 +84,19 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
}
+/// \brief Add an implicit \#include using the original file used to generate
+/// a PCH file.
+static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP,
+ StringRef ImplicitIncludePCH) {
+ std::string OriginalFile =
+ ASTReader::getOriginalSourceFile(ImplicitIncludePCH, PP.getFileManager(),
+ PP.getDiagnostics());
+ if (OriginalFile.empty())
+ return;
+
+ AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
+}
+
/// PickFP - This is used to pick a value based on the FP semantics of the
/// specified FP model.
template <typename T>
@@ -102,51 +116,51 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
}
static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
- const llvm::fltSemantics *Sem) {
+ const llvm::fltSemantics *Sem, StringRef Ext) {
const char *DenormMin, *Epsilon, *Max, *Min;
- DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
- "3.64519953188247460253e-4951L",
- "4.94065645841246544176568792868221e-324L",
- "6.47517511943802511092443895822764655e-4966L");
+ DenormMin = PickFP(Sem, "1.40129846e-45", "4.9406564584124654e-324",
+ "3.64519953188247460253e-4951",
+ "4.94065645841246544176568792868221e-324",
+ "6.47517511943802511092443895822764655e-4966");
int Digits = PickFP(Sem, 6, 15, 18, 31, 33);
- Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16",
- "1.08420217248550443401e-19L",
- "4.94065645841246544176568792868221e-324L",
- "1.92592994438723585305597794258492732e-34L");
+ Epsilon = PickFP(Sem, "1.19209290e-7", "2.2204460492503131e-16",
+ "1.08420217248550443401e-19",
+ "4.94065645841246544176568792868221e-324",
+ "1.92592994438723585305597794258492732e-34");
int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381);
int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384);
- Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308",
- "3.36210314311209350626e-4932L",
- "2.00416836000897277799610805135016e-292L",
- "3.36210314311209350626267781732175260e-4932L");
- Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308",
- "1.18973149535723176502e+4932L",
- "1.79769313486231580793728971405301e+308L",
- "1.18973149535723176508575932662800702e+4932L");
+ Min = PickFP(Sem, "1.17549435e-38", "2.2250738585072014e-308",
+ "3.36210314311209350626e-4932",
+ "2.00416836000897277799610805135016e-292",
+ "3.36210314311209350626267781732175260e-4932");
+ Max = PickFP(Sem, "3.40282347e+38", "1.7976931348623157e+308",
+ "1.18973149535723176502e+4932",
+ "1.79769313486231580793728971405301e+308",
+ "1.18973149535723176508575932662800702e+4932");
SmallString<32> DefPrefix;
DefPrefix = "__";
DefPrefix += Prefix;
DefPrefix += "_";
- Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
+ Builder.defineMacro(DefPrefix + "DENORM_MIN__", Twine(DenormMin)+Ext);
Builder.defineMacro(DefPrefix + "HAS_DENORM__");
Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits));
- Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon));
+ Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)+Ext);
Builder.defineMacro(DefPrefix + "HAS_INFINITY__");
Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__");
Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits));
Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp));
Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp));
- Builder.defineMacro(DefPrefix + "MAX__", Twine(Max));
+ Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)+Ext);
Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")");
Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")");
- Builder.defineMacro(DefPrefix + "MIN__", Twine(Min));
+ Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)+Ext);
}
@@ -247,7 +261,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts,
<< "};\n"
<< "\n";
- if (LangOpts.ObjCRuntimeHasWeak) {
+ if (LangOpts.ObjCARCWeak) {
Out << "template<typename _Tp>\n"
<< "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n"
<< " enum { __value = 0 };\n"
@@ -288,6 +302,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} else {
+ // FIXME: LangOpts.CPlusPlus1y
+
// C++11 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201103L when compiling a
// C++ translation unit.
@@ -325,8 +341,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__clang_patchlevel__", "0");
#endif
Builder.defineMacro("__clang_version__",
- "\"" CLANG_VERSION_STRING " ("
- + getClangFullRepositoryVersion() + ")\"");
+ "\"" CLANG_VERSION_STRING " "
+ + getClangFullRepositoryVersion() + "\"");
#undef TOSTR
#undef TOSTR2
if (!LangOpts.MicrosoftMode) {
@@ -420,19 +436,17 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
// VC++ appears to only like __FUNCTION__.
Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
- // Work around some issues with Visual C++ headerws.
- if (LangOpts.CPlusPlus) {
- // Since we define wchar_t in C++ mode.
+ // Work around some issues with Visual C++ headers.
+ if (LangOpts.WChar) {
+ // wchar_t supported as a keyword.
Builder.defineMacro("_WCHAR_T_DEFINED");
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
+ }
+ if (LangOpts.CPlusPlus) {
// FIXME: Support Microsoft's __identifier extension in the lexer.
Builder.append("#define __identifier(x) x");
Builder.append("class type_info;");
}
-
- if (LangOpts.CPlusPlus0x) {
- Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", "1");
- }
}
if (LangOpts.Optimize)
@@ -511,9 +525,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder);
DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder);
- DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat());
- DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat());
- DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat());
+ DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
+ DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
+ DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L");
// Define a __POINTER_WIDTH__ macro for stdint.h.
Builder.defineMacro("__POINTER_WIDTH__",
@@ -763,6 +777,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
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());
}
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 3fee95749986..3a04f1859bda 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/LogDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
@@ -16,9 +17,9 @@
using namespace clang;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
- const DiagnosticOptions &diags,
+ DiagnosticOptions *diags,
bool _OwnsOutputStream)
- : OS(os), LangOpts(0), DiagOpts(&diags),
+ : OS(os), LangOpts(0), DiagOpts(diags),
OwnsOutputStream(_OwnsOutputStream) {
}
@@ -172,6 +173,6 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DiagnosticConsumer *
LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
- return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false);
+ return new LogDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false);
}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 5311ed52cd29..30707dc0c008 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -570,8 +570,12 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) {
do PP.Lex(Tok);
while (Tok.isNot(tok::eof));
- SmallVector<id_macro_pair, 128>
- MacrosByID(PP.macro_begin(), PP.macro_end());
+ SmallVector<id_macro_pair, 128> MacrosByID;
+ 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));
+ }
llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index a20f30d6be83..5f8fc1ecfc60 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -12,6 +12,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/DenseSet.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
@@ -50,13 +51,10 @@ class SDiagsWriter;
class SDiagsRenderer : public DiagnosticNoteRenderer {
SDiagsWriter &Writer;
- RecordData &Record;
public:
- SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
- const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
- : DiagnosticNoteRenderer(LangOpts, DiagOpts),
- Writer(Writer), Record(Record){}
+ SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
+ DiagnosticOptions *DiagOpts)
+ : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
virtual ~SDiagsRenderer() {}
@@ -73,15 +71,16 @@ protected:
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
const SourceManager &SM) {}
-
- void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM);
-
+
+ virtual void emitNote(SourceLocation Loc, StringRef Message,
+ const SourceManager *SM);
+
virtual void emitCodeContext(SourceLocation Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange>& Ranges,
ArrayRef<FixItHint> Hints,
const SourceManager &SM);
-
+
virtual void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level);
virtual void endDiagnostic(DiagOrStoredDiag D,
@@ -91,13 +90,12 @@ protected:
class SDiagsWriter : public DiagnosticConsumer {
friend class SDiagsRenderer;
public:
- explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
- : LangOpts(0), DiagOpts(diags),
- Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
- {
+ explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags)
+ : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os),
+ EmittedAnyDiagBlocks(false) {
EmitPreamble();
}
-
+
~SDiagsWriter() {}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
@@ -124,7 +122,26 @@ private:
/// \brief Emit the META data block.
void EmitMetaBlock();
-
+
+ /// \brief Start a DIAG block.
+ void EnterDiagBlock();
+
+ /// \brief End a DIAG block.
+ void ExitDiagBlock();
+
+ /// \brief Emit a DIAG record.
+ void EmitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ const SourceManager *SM,
+ DiagOrStoredDiag D);
+
+ /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
+ void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM);
+
/// \brief Emit a record for a CharSourceRange.
void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
@@ -159,7 +176,7 @@ private:
enum { Version = 1 };
const LangOptions *LangOpts;
- const DiagnosticOptions &DiagOpts;
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
/// \brief The byte buffer for the serialized content.
SmallString<1024> Buffer;
@@ -190,17 +207,18 @@ private:
/// \brief Map for uniquing strings.
DiagFlagsTy DiagFlags;
-
- /// \brief Flag indicating whether or not we are in the process of
- /// emitting a non-note diagnostic.
- bool inNonNoteDiagnostic;
+
+ /// \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;
};
} // end anonymous namespace
namespace clang {
namespace serialized_diags {
DiagnosticConsumer *create(llvm::raw_ostream *OS,
- const DiagnosticOptions &diags) {
+ DiagnosticOptions *diags) {
return new SDiagsWriter(OS, diags);
}
} // end namespace serialized_diags
@@ -474,31 +492,69 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
+ // Enter the block for a non-note diagnostic immediately, rather than waiting
+ // for beginDiagnostic, in case associated notes are emitted before we get
+ // there.
if (DiagLevel != DiagnosticsEngine::Note) {
- if (inNonNoteDiagnostic) {
- // We have encountered a non-note diagnostic. Finish up the previous
- // diagnostic block before starting a new one.
- Stream.ExitBlock();
- }
- inNonNoteDiagnostic = true;
+ if (EmittedAnyDiagBlocks)
+ ExitDiagBlock();
+
+ EnterDiagBlock();
+ EmittedAnyDiagBlocks = true;
}
// Compute the diagnostic text.
- diagBuf.clear();
+ diagBuf.clear();
Info.FormatDiagnostic(diagBuf);
- const SourceManager *
- SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0;
- SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts);
+ 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.
+ EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
+ diagBuf, 0, &Info);
+ return;
+ }
+
+ assert(Info.hasSourceManager() && LangOpts &&
+ "Unexpected diagnostic with valid location outside of a source file");
+ SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts);
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
diagBuf.str(),
Info.getRanges(),
llvm::makeArrayRef(Info.getFixItHints(),
Info.getNumFixItHints()),
- SM,
+ &Info.getSourceManager(),
&Info);
}
+void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ const SourceManager *SM,
+ DiagOrStoredDiag D) {
+ // Emit the RECORD_DIAG record.
+ Record.clear();
+ Record.push_back(RECORD_DIAG);
+ Record.push_back(Level);
+ AddLocToRecord(Loc, SM, PLoc, Record);
+
+ if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
+ // Emit the category string lazily and get the category ID.
+ unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
+ Record.push_back(getEmitCategory(DiagID));
+ // Emit the diagnostic flag string lazily and get the mapped ID.
+ Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
+ } else {
+ Record.push_back(getEmitCategory());
+ Record.push_back(getEmitDiagnosticFlag(Level));
+ }
+
+ Record.push_back(Message.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
+}
+
void
SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
PresumedLoc PLoc,
@@ -507,94 +563,80 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
ArrayRef<clang::CharSourceRange> Ranges,
const SourceManager *SM,
DiagOrStoredDiag D) {
- // Emit the RECORD_DIAG record.
- Writer.Record.clear();
- Writer.Record.push_back(RECORD_DIAG);
- Writer.Record.push_back(Level);
- Writer.AddLocToRecord(Loc, SM, PLoc, Record);
+ Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
+}
- if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
- // Emit the category string lazily and get the category ID.
- unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
- Writer.Record.push_back(Writer.getEmitCategory(DiagID));
- // Emit the diagnostic flag string lazily and get the mapped ID.
- Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
- }
- else {
- Writer.Record.push_back(Writer.getEmitCategory());
- Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
- }
+void SDiagsWriter::EnterDiagBlock() {
+ Stream.EnterSubblock(BLOCK_DIAG, 4);
+}
- Writer.Record.push_back(Message.size());
- Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
- Writer.Record, Message);
+void SDiagsWriter::ExitDiagBlock() {
+ Stream.ExitBlock();
}
void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {
- Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
+ if (Level == DiagnosticsEngine::Note)
+ Writer.EnterDiagBlock();
}
void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {
- if (D && Level != DiagnosticsEngine::Note)
- return;
- Writer.Stream.ExitBlock();
+ // Only end note diagnostics here, because we can't be sure when we've seen
+ // the last note associated with a non-note diagnostic.
+ if (Level == DiagnosticsEngine::Note)
+ Writer.ExitDiagBlock();
}
-void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange> &Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {
// Emit Source Ranges.
- for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
- it != ei; ++it) {
- if (it->isValid())
- Writer.EmitCharSourceRange(*it, SM);
- }
-
+ for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
+ I != E; ++I)
+ if (I->isValid())
+ EmitCharSourceRange(*I, SM);
+
// Emit FixIts.
- for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
- it != et; ++it) {
- const FixItHint &fix = *it;
- if (fix.isNull())
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ const FixItHint &Fix = *I;
+ if (Fix.isNull())
continue;
- Writer.Record.clear();
- Writer.Record.push_back(RECORD_FIXIT);
- Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
- Writer.Record.push_back(fix.CodeToInsert.size());
- Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
- fix.CodeToInsert);
+ Record.clear();
+ Record.push_back(RECORD_FIXIT);
+ AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM);
+ Record.push_back(Fix.CodeToInsert.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
+ Fix.CodeToInsert);
}
}
+void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {
+ Writer.EmitCodeContext(Ranges, Hints, SM);
+}
+
void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
const SourceManager *SM) {
- Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
- RecordData Record;
- Record.push_back(RECORD_DIAG);
- Record.push_back(DiagnosticsEngine::Note);
- Writer.AddLocToRecord(Loc, Record, SM);
- Record.push_back(Writer.getEmitCategory());
- Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
- Record.push_back(Message.size());
- Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
- Record, Message);
- Writer.Stream.ExitBlock();
+ Writer.EnterDiagBlock();
+ PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
+ Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
+ Message, SM, DiagOrStoredDiag());
+ Writer.ExitDiagBlock();
}
void SDiagsWriter::finish() {
- if (inNonNoteDiagnostic) {
- // Finish off any diagnostics we were in the process of emitting.
- Stream.ExitBlock();
- inNonNoteDiagnostic = false;
- }
+ // Finish off any diagnostic we were in the process of emitting.
+ if (EmittedAnyDiagBlocks)
+ ExitDiagBlock();
// Write the generated bitstream to "Out".
OS->write((char *)&Buffer.front(), Buffer.size());
OS->flush();
-
+
OS.reset(0);
}
-
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 9bb3e1dce8c7..35dabad60657 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -11,7 +11,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/ConvertUTF.h"
-#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -43,19 +43,22 @@ static const enum raw_ostream::Colors savedColor =
/// \brief Add highlights to differences in template strings.
static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,
bool &Normal, bool Bold) {
- for (unsigned i = 0, e = Str.size(); i < e; ++i)
- if (Str[i] != ToggleHighlight) {
- OS << Str[i];
- } else {
- if (Normal)
- OS.changeColor(templateColor, true);
- else {
- OS.resetColor();
- if (Bold)
- OS.changeColor(savedColor, true);
- }
- Normal = !Normal;
+ while (1) {
+ size_t Pos = Str.find(ToggleHighlight);
+ OS << Str.slice(0, Pos);
+ if (Pos == StringRef::npos)
+ break;
+
+ Str = Str.substr(Pos + 1);
+ if (Normal)
+ OS.changeColor(templateColor, true);
+ else {
+ OS.resetColor();
+ if (Bold)
+ OS.changeColor(savedColor, true);
}
+ Normal = !Normal;
+ }
}
/// \brief Number of spaces to indent when word-wrapping.
@@ -110,28 +113,15 @@ printableTextForNextCharacter(StringRef SourceLine, size_t *i,
return std::make_pair(expandedTab, true);
}
- // FIXME: this data is copied from the private implementation of ConvertUTF.h
- 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
- };
-
unsigned char const *begin, *end;
begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i));
- end = begin + SourceLine.size();
+ end = begin + (SourceLine.size() - *i);
if (isLegalUTF8Sequence(begin, end)) {
UTF32 c;
UTF32 *cptr = &c;
unsigned char const *original_begin = begin;
- char trailingBytes = trailingBytesForUTF8[(unsigned char)SourceLine[*i]];
- unsigned char const *cp_end = begin+trailingBytes+1;
+ unsigned char const *cp_end = begin+getNumBytesForUTF8(SourceLine[*i]);
ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1,
strictConversion);
@@ -274,14 +264,44 @@ struct SourceColumnMap {
}
int columns() const { return m_byteToColumn.back(); }
int bytes() const { return m_columnToByte.back(); }
+
+ /// \brief Map a byte to the column which it is at the start of, or return -1
+ /// if it is not at the start of a column (for a UTF-8 trailing byte).
int byteToColumn(int n) const {
assert(0<=n && n<static_cast<int>(m_byteToColumn.size()));
return m_byteToColumn[n];
}
+
+ /// \brief Map a byte to the first column which contains it.
+ int byteToContainingColumn(int N) const {
+ assert(0 <= N && N < static_cast<int>(m_byteToColumn.size()));
+ while (m_byteToColumn[N] == -1)
+ --N;
+ return m_byteToColumn[N];
+ }
+
+ /// \brief Map a column to the byte which starts the column, or return -1 if
+ /// the column the second or subsequent column of an expanded tab or similar
+ /// multi-column entity.
int columnToByte(int n) const {
assert(0<=n && n<static_cast<int>(m_columnToByte.size()));
return m_columnToByte[n];
}
+
+ /// \brief Map from a byte index to the next byte which starts a column.
+ int startOfNextColumn(int N) const {
+ assert(0 <= N && N < static_cast<int>(m_columnToByte.size() - 1));
+ while (byteToColumn(++N) == -1) {}
+ return N;
+ }
+
+ /// \brief Map from a byte index to the previous byte which starts a column.
+ int startOfPreviousColumn(int N) const {
+ assert(0 < N && N < static_cast<int>(m_columnToByte.size()));
+ while (byteToColumn(--N) == -1) {}
+ return N;
+ }
+
StringRef getSourceLine() const {
return m_SourceLine;
}
@@ -398,25 +418,24 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
bool ExpandedRegion = false;
if (SourceStart>0) {
- unsigned NewStart = SourceStart-1;
+ unsigned NewStart = map.startOfPreviousColumn(SourceStart);
// 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 &&
- (map.byteToColumn(NewStart)==-1 ||
- isspace(static_cast<unsigned char>(SourceLine[NewStart]))))
- --NewStart;
+ isspace(static_cast<unsigned char>(SourceLine[NewStart])))
+ NewStart = map.startOfPreviousColumn(NewStart);
// Skip over this bit of "interesting" text.
- while (NewStart &&
- (map.byteToColumn(NewStart)!=-1 &&
- !isspace(static_cast<unsigned char>(SourceLine[NewStart]))))
- --NewStart;
-
- // Move up to the non-whitespace character we just saw.
- if (NewStart)
- ++NewStart;
+ while (NewStart) {
+ unsigned Prev = map.startOfPreviousColumn(NewStart);
+ if (isspace(static_cast<unsigned char>(SourceLine[Prev])))
+ break;
+ NewStart = Prev;
+ }
+ assert(map.byteToColumn(NewStart) != -1);
unsigned NewColumns = map.byteToColumn(SourceEnd) -
map.byteToColumn(NewStart);
if (NewColumns <= TargetColumns) {
@@ -426,21 +445,21 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
}
if (SourceEnd<SourceLine.size()) {
- unsigned NewEnd = SourceEnd+1;
+ unsigned NewEnd = map.startOfNextColumn(SourceEnd);
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
- while (NewEnd<SourceLine.size() &&
- (map.byteToColumn(NewEnd)==-1 ||
- isspace(static_cast<unsigned char>(SourceLine[NewEnd]))))
- ++NewEnd;
+ // FIXME: Detect non-ASCII whitespace characters too.
+ while (NewEnd < SourceLine.size() &&
+ isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ NewEnd = map.startOfNextColumn(NewEnd);
// Skip over this bit of "interesting" text.
- while (NewEnd<SourceLine.size() &&
- (map.byteToColumn(NewEnd)!=-1 &&
- !isspace(static_cast<unsigned char>(SourceLine[NewEnd]))))
- ++NewEnd;
+ while (NewEnd < SourceLine.size() &&
+ !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ NewEnd = map.startOfNextColumn(NewEnd);
+ assert(map.byteToColumn(NewEnd) != -1);
unsigned NewColumns = map.byteToColumn(NewEnd) -
map.byteToColumn(SourceStart);
if (NewColumns <= TargetColumns) {
@@ -475,7 +494,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// The line needs some trunctiona, and we'd prefer to keep the front
// if possible, so remove the back
- if (BackColumnsRemoved)
+ if (BackColumnsRemoved > strlen(back_ellipse))
SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
// If that's enough then we're done
@@ -483,7 +502,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
return;
// Otherwise remove the front as well
- if (FrontColumnsRemoved) {
+ if (FrontColumnsRemoved > strlen(front_ellipse)) {
SourceLine.replace(0, SourceStart, front_ellipse);
CaretLine.replace(0, CaretStart, front_space);
if (!FixItInsertionLine.empty())
@@ -651,7 +670,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str,
TextDiagnostic::TextDiagnostic(raw_ostream &OS,
const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
+ DiagnosticOptions *DiagOpts)
: DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {}
TextDiagnostic::~TextDiagnostic() {}
@@ -670,13 +689,13 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
if (Loc.isValid())
emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM);
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
- printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
+ printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
printDiagnosticMessage(OS, Level, Message,
OS.tell() - StartOfLocationInfo,
- DiagOpts.MessageLength, DiagOpts.ShowColors);
+ DiagOpts->MessageLength, DiagOpts->ShowColors);
}
/*static*/ void
@@ -770,36 +789,36 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
}
unsigned LineNo = PLoc.getLine();
- if (!DiagOpts.ShowLocation)
+ if (!DiagOpts->ShowLocation)
return;
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
OS << PLoc.getFilename();
- switch (DiagOpts.Format) {
+ switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
}
- if (DiagOpts.ShowColumn)
+ if (DiagOpts->ShowColumn)
// Compute the column number.
if (unsigned ColNo = PLoc.getColumn()) {
- if (DiagOpts.Format == DiagnosticOptions::Msvc) {
+ if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) {
OS << ',';
ColNo--;
} else
OS << ':';
OS << ColNo;
}
- switch (DiagOpts.Format) {
+ switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang:
case DiagnosticOptions::Vi: OS << ':'; break;
case DiagnosticOptions::Msvc: OS << ") : "; break;
}
- if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
+ if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
FileID CaretFileID =
SM.getFileID(SM.getExpansionLoc(Loc));
bool PrintedRange = false;
@@ -858,7 +877,7 @@ void TextDiagnostic::emitBasicNote(StringRef Message) {
void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
PresumedLoc PLoc,
const SourceManager &SM) {
- if (DiagOpts.ShowLocation)
+ if (DiagOpts->ShowLocation)
OS << "In file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":\n";
else
@@ -886,7 +905,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// was part of a different warning or error diagnostic, or if the
// diagnostic has ranges. We don't want to emit the same caret
// multiple times if one loc has multiple diagnostics.
- if (!DiagOpts.ShowCarets)
+ if (!DiagOpts->ShowCarets)
return;
if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
(LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
@@ -924,7 +943,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// length as the line of source code.
std::string CaretLine(LineEnd-LineStart, ' ');
- const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop);
+ const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
// Highlight all of the characters covered by Ranges with ~ characters.
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
@@ -933,7 +952,7 @@ void TextDiagnostic::emitSnippetAndCaret(
highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM);
// Next, insert the caret itself.
- ColNo = sourceColMap.byteToColumn(ColNo-1);
+ ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
if (CaretLine.size()<ColNo+1)
CaretLine.resize(ColNo+1, ' ');
CaretLine[ColNo] = '^';
@@ -944,7 +963,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// If the source line is too long for our terminal, select only the
// "interesting" source region within that line.
- unsigned Columns = DiagOpts.MessageLength;
+ unsigned Columns = DiagOpts->MessageLength;
if (Columns)
selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
Columns, sourceColMap);
@@ -953,7 +972,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// to produce easily machine parsable output. Add a space before the
// source line and the caret to make it trivial to tell the main diagnostic
// line from what the user is intended to see.
- if (DiagOpts.ShowSourceRanges) {
+ if (DiagOpts->ShowSourceRanges) {
SourceLine = ' ' + SourceLine;
CaretLine = ' ' + CaretLine;
}
@@ -965,20 +984,20 @@ void TextDiagnostic::emitSnippetAndCaret(
// Emit what we have computed.
emitSnippet(SourceLine);
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.changeColor(caretColor, true);
OS << CaretLine << '\n';
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
if (!FixItInsertionLine.empty()) {
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
// Print fixit line in color
OS.changeColor(fixitColor, false);
- if (DiagOpts.ShowSourceRanges)
+ if (DiagOpts->ShowSourceRanges)
OS << ' ';
OS << FixItInsertionLine << '\n';
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
}
@@ -997,15 +1016,15 @@ void TextDiagnostic::emitSnippet(StringRef line) {
while (i<line.size()) {
std::pair<SmallString<16>,bool> res
- = printableTextForNextCharacter(line, &i, DiagOpts.TabStop);
+ = printableTextForNextCharacter(line, &i, DiagOpts->TabStop);
bool was_printable = res.second;
- if (DiagOpts.ShowColors && was_printable == print_reversed) {
+ if (DiagOpts->ShowColors && was_printable == print_reversed) {
if (print_reversed)
OS.reverseColor();
OS << to_print;
to_print.clear();
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
}
@@ -1013,10 +1032,10 @@ void TextDiagnostic::emitSnippet(StringRef line) {
to_print += res.first.str();
}
- if (print_reversed && DiagOpts.ShowColors)
+ if (print_reversed && DiagOpts->ShowColors)
OS.reverseColor();
OS << to_print;
- if (print_reversed && DiagOpts.ShowColors)
+ if (print_reversed && DiagOpts->ShowColors)
OS.resetColor();
OS << '\n';
@@ -1030,16 +1049,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
const SourceManager &SM) {
if (!R.isValid()) return;
- SourceLocation Begin = SM.getExpansionLoc(R.getBegin());
- SourceLocation End = SM.getExpansionLoc(R.getEnd());
-
- // If the End location and the start location are the same and are a macro
- // location, then the range was something that came from a macro expansion
- // or _Pragma. If this is an object-like macro, the best we can do is to
- // highlight the range. If this is a function-like macro, we'd also like to
- // highlight the arguments.
- if (Begin == End && R.getEnd().isMacroID())
- End = SM.getExpansionRange(R.getEnd()).second;
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
@@ -1080,7 +1091,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
while (StartColNo < map.getSourceLine().size() &&
(map.getSourceLine()[StartColNo] == ' ' ||
map.getSourceLine()[StartColNo] == '\t'))
- ++StartColNo;
+ StartColNo = map.startOfNextColumn(StartColNo);
// Pick the last non-whitespace column.
if (EndColNo > map.getSourceLine().size())
@@ -1088,7 +1099,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
while (EndColNo-1 &&
(map.getSourceLine()[EndColNo-1] == ' ' ||
map.getSourceLine()[EndColNo-1] == '\t'))
- --EndColNo;
+ 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
@@ -1100,8 +1111,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
// Fill the range with ~'s.
- StartColNo = map.byteToColumn(StartColNo);
- EndColNo = map.byteToColumn(EndColNo);
+ StartColNo = map.byteToContainingColumn(StartColNo);
+ EndColNo = map.byteToContainingColumn(EndColNo);
assert(StartColNo <= EndColNo && "Invalid range!");
if (CaretLine.size() < EndColNo)
@@ -1116,7 +1127,7 @@ std::string TextDiagnostic::buildFixItInsertionLine(
const SourceManager &SM) {
std::string FixItInsertionLine;
- if (Hints.empty() || !DiagOpts.ShowFixits)
+ if (Hints.empty() || !DiagOpts->ShowFixits)
return FixItInsertionLine;
unsigned PrevHintEndCol = 0;
@@ -1139,7 +1150,7 @@ std::string TextDiagnostic::buildFixItInsertionLine(
// The hint must start inside the source or right at the end
assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
- unsigned HintCol = map.byteToColumn(HintByteOffset);
+ 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
@@ -1176,14 +1187,14 @@ std::string TextDiagnostic::buildFixItInsertionLine(
}
}
- expandTabs(FixItInsertionLine, DiagOpts.TabStop);
+ expandTabs(FixItInsertionLine, DiagOpts->TabStop);
return FixItInsertionLine;
}
void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
const SourceManager &SM) {
- if (!DiagOpts.ShowParseableFixits)
+ if (!DiagOpts->ShowParseableFixits)
return;
// We follow FixItRewriter's example in not (yet) handling
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 382e1567c7f4..aa7a61a60f9e 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -25,9 +25,9 @@
using namespace clang;
TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
- const DiagnosticOptions &diags,
+ DiagnosticOptions *diags,
bool _OwnsOutputStream)
- : OS(os), DiagOpts(&diags),
+ : OS(os), DiagOpts(diags),
OwnsOutputStream(_OwnsOutputStream) {
}
@@ -39,7 +39,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
// Build the TextDiagnostic utility.
- TextDiag.reset(new TextDiagnostic(OS, LO, *DiagOpts));
+ TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts));
}
void TextDiagnosticPrinter::EndSourceFile() {
@@ -158,5 +158,5 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DiagnosticConsumer *
TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
- return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false);
+ return new TextDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false);
}
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index a9378a117d6b..1750946af497 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -31,14 +31,17 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
: Diags(_Diags),
PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()),
Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0),
- ActiveSourceFiles(0)
+ LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives)
{
Diags.takeClient();
+ if (Diags.hasSourceManager())
+ setSourceManager(Diags.getSourceManager());
}
VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
+ SrcManager = 0;
CheckDiagnostics();
Diags.takeClient();
if (OwnsPrimaryClient)
@@ -48,21 +51,20 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
#ifndef NDEBUG
namespace {
class VerifyFileTracker : public PPCallbacks {
- typedef VerifyDiagnosticConsumer::FilesParsedForDirectivesSet ListType;
- ListType &FilesList;
+ VerifyDiagnosticConsumer &Verify;
SourceManager &SM;
public:
- VerifyFileTracker(ListType &FilesList, SourceManager &SM)
- : FilesList(FilesList), SM(SM) { }
+ VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
+ : Verify(Verify), SM(SM) { }
/// \brief Hook into the preprocessor and update the list of parsed
/// files when the preprocessor indicates a new file is entered.
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) {
- if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(Loc)))
- FilesList.insert(E);
+ Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
+ VerifyDiagnosticConsumer::IsParsed);
}
};
} // End anonymous namespace.
@@ -76,10 +78,12 @@ void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
if (++ActiveSourceFiles == 1) {
if (PP) {
CurrentPreprocessor = PP;
+ this->LangOpts = &LangOpts;
+ setSourceManager(PP->getSourceManager());
const_cast<Preprocessor*>(PP)->addCommentHandler(this);
#ifndef NDEBUG
- VerifyFileTracker *V = new VerifyFileTracker(FilesParsedForDirectives,
- PP->getSourceManager());
+ // Debug build tracks parsed files.
+ VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager);
const_cast<Preprocessor*>(PP)->addPPCallbacks(V);
#endif
}
@@ -101,18 +105,40 @@ void VerifyDiagnosticConsumer::EndSourceFile() {
// Check diagnostics once last file completed.
CheckDiagnostics();
CurrentPreprocessor = 0;
+ LangOpts = 0;
}
}
void VerifyDiagnosticConsumer::HandleDiagnostic(
DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
+ if (Info.hasSourceManager())
+ setSourceManager(Info.getSourceManager());
+
#ifndef NDEBUG
- if (Info.hasSourceManager()) {
- FileID FID = Info.getSourceManager().getFileID(Info.getLocation());
- if (!FID.isInvalid())
- FilesWithDiagnostics.insert(FID);
+ // Debug build tracks unparsed files for possible
+ // unparsed expected-* directives.
+ if (SrcManager) {
+ SourceLocation Loc = Info.getLocation();
+ if (Loc.isValid()) {
+ ParsedStatus PS = IsUnparsed;
+
+ Loc = SrcManager->getExpansionLoc(Loc);
+ FileID FID = SrcManager->getFileID(Loc);
+
+ const FileEntry *FE = SrcManager->getFileEntryForID(FID);
+ if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
+ // If the file is a modules header file it shall not be parsed
+ // for expected-* directives.
+ HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
+ if (HS.findModuleForHeader(FE))
+ PS = IsUnparsedNoDirectives;
+ }
+
+ UpdateParsedFileStatus(*SrcManager, FID, PS);
+ }
}
#endif
+
// Send the diagnostic to the buffer, we will check it once we reach the end
// of the source file (or are destructed).
Buffer->HandleDiagnostic(DiagLevel, Info);
@@ -200,10 +226,22 @@ public:
// Return true if string literal is found.
// When true, P marks begin-position of S in content.
- bool Search(StringRef S) {
- P = std::search(C, End, S.begin(), S.end());
- PEnd = P + S.size();
- return P != End;
+ bool Search(StringRef S, bool EnsureStartOfWord = false) {
+ do {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.size();
+ if (P == End)
+ break;
+ if (!EnsureStartOfWord
+ // Check if string literal starts a new word.
+ || P == Begin || isspace(P[-1])
+ // Or it could be preceeded by the start of a comment.
+ || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
+ && P[-2] == '/'))
+ return true;
+ // Otherwise, skip and search again.
+ } while (Advance());
+ return false;
}
// Advance 1-past previous next/search.
@@ -240,12 +278,13 @@ private:
///
/// Returns true if any valid directives were found.
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
- SourceLocation Pos, DiagnosticsEngine &Diags) {
+ SourceLocation Pos, DiagnosticsEngine &Diags,
+ VerifyDiagnosticConsumer::DirectiveStatus &Status) {
// A single comment may contain multiple directives.
bool FoundDirective = false;
for (ParseHelper PH(S); !PH.Done();) {
// Search for token: expected
- if (!PH.Search("expected"))
+ if (!PH.Search("expected", true))
break;
PH.Advance();
@@ -262,10 +301,24 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
DL = ED ? &ED->Warnings : NULL;
else if (PH.Next("note"))
DL = ED ? &ED->Notes : NULL;
- else
+ else if (PH.Next("no-diagnostics")) {
+ if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
+ Diags.Report(Pos, diag::err_verify_invalid_no_diags)
+ << /*IsExpectedNoDiagnostics=*/true;
+ else
+ Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
+ continue;
+ } else
continue;
PH.Advance();
+ if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
+ Diags.Report(Pos, diag::err_verify_invalid_no_diags)
+ << /*IsExpectedNoDiagnostics=*/false;
+ continue;
+ }
+ Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
+
// If a directive has been found but we're not interested
// in storing the directive information, return now.
if (!DL)
@@ -412,7 +465,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
// Fold any "\<EOL>" sequences
size_t loc = C.find('\\');
if (loc == StringRef::npos) {
- ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics());
+ ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status);
return false;
}
@@ -442,7 +495,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
}
if (!C2.empty())
- ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics());
+ ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status);
return false;
}
@@ -452,34 +505,36 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
/// Preprocessor, directives inside skipped #if blocks will still be found.
///
/// \return true if any directives were found.
-static bool findDirectives(const Preprocessor &PP, FileID FID) {
+static bool findDirectives(SourceManager &SM, FileID FID,
+ const LangOptions &LangOpts) {
// Create a raw lexer to pull all the comments out of FID.
if (FID.isInvalid())
return false;
- SourceManager& SM = PP.getSourceManager();
// Create a lexer to lex all the tokens of the main file in raw mode.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
- Lexer RawLex(FID, FromFile, SM, PP.getLangOpts());
+ Lexer RawLex(FID, FromFile, SM, LangOpts);
// Return comments as tokens, this is how we find expected diagnostics.
RawLex.SetCommentRetentionState(true);
Token Tok;
Tok.setKind(tok::comment);
- bool Found = false;
+ VerifyDiagnosticConsumer::DirectiveStatus Status =
+ VerifyDiagnosticConsumer::HasNoDirectives;
while (Tok.isNot(tok::eof)) {
RawLex.Lex(Tok);
if (!Tok.is(tok::comment)) continue;
- std::string Comment = PP.getSpelling(Tok);
+ std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
if (Comment.empty()) continue;
- // Find all expected errors/warnings/notes.
- Found |= ParseDirective(Comment, 0, SM, Tok.getLocation(),
- PP.getDiagnostics());
+ // Find first directive.
+ if (ParseDirective(Comment, 0, SM, Tok.getLocation(),
+ SM.getDiagnostics(), Status))
+ return true;
}
- return Found;
+ return false;
}
#endif // !NDEBUG
@@ -601,41 +656,95 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
return NumProblems;
}
+void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
+ FileID FID,
+ ParsedStatus PS) {
+ // Check SourceManager hasn't changed.
+ setSourceManager(SM);
+
+#ifndef NDEBUG
+ if (FID.isInvalid())
+ return;
+
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+
+ if (PS == IsParsed) {
+ // Move the FileID from the unparsed set to the parsed set.
+ UnparsedFiles.erase(FID);
+ ParsedFiles.insert(std::make_pair(FID, FE));
+ } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
+ // Add the FileID to the unparsed set if we haven't seen it before.
+
+ // Check for directives.
+ bool FoundDirectives;
+ if (PS == IsUnparsedNoDirectives)
+ FoundDirectives = false;
+ else
+ FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
+
+ // Add the FileID to the unparsed set.
+ UnparsedFiles.insert(std::make_pair(FID,
+ UnparsedFileStatus(FE, FoundDirectives)));
+ }
+#endif
+}
+
void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Ensure any diagnostics go to the primary client.
bool OwnsCurClient = Diags.ownsClient();
DiagnosticConsumer *CurClient = Diags.takeClient();
Diags.setClient(PrimaryClient, false);
- // If we have a preprocessor, scan the source for expected diagnostic
- // markers. If not then any diagnostics are unexpected.
- if (CurrentPreprocessor) {
- SourceManager &SM = CurrentPreprocessor->getSourceManager();
-
#ifndef NDEBUG
- // In a debug build, scan through any files that may have been missed
- // during parsing and issue a fatal error if directives are contained
- // within these files. If a fatal error occurs, this suggests that
- // this file is being parsed separately from the main file.
- HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
- for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(),
- End = FilesWithDiagnostics.end();
- I != End; ++I) {
- const FileEntry *E = SM.getFileEntryForID(*I);
- // Don't check files already parsed or those handled as modules.
- if (E && (FilesParsedForDirectives.count(E)
- || HS.findModuleForHeader(E)))
+ // In a debug build, scan through any files that may have been missed
+ // during parsing and issue a fatal error if directives are contained
+ // within these files. If a fatal error occurs, this suggests that
+ // this file is being parsed separately from the main file, in which
+ // case consider moving the directives to the correct place, if this
+ // is applicable.
+ if (UnparsedFiles.size() > 0) {
+ // Generate a cache of parsed FileEntry pointers for alias lookups.
+ llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
+ for (ParsedFilesMap::iterator I = ParsedFiles.begin(),
+ End = ParsedFiles.end(); I != End; ++I) {
+ if (const FileEntry *FE = I->second)
+ ParsedFileCache.insert(FE);
+ }
+
+ // Iterate through list of unparsed files.
+ for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(),
+ End = UnparsedFiles.end(); I != End; ++I) {
+ const UnparsedFileStatus &Status = I->second;
+ const FileEntry *FE = Status.getFile();
+
+ // Skip files that have been parsed via an alias.
+ if (FE && ParsedFileCache.count(FE))
continue;
- if (findDirectives(*CurrentPreprocessor, *I))
+ // Report a fatal error if this file contained directives.
+ if (Status.foundDirectives()) {
llvm::report_fatal_error(Twine("-verify directives found after rather"
" than during normal parsing of ",
- StringRef(E ? E->getName() : "(unknown)")));
+ StringRef(FE ? FE->getName() : "(unknown)")));
+ }
+ }
+
+ // UnparsedFiles has been processed now, so clear it.
+ UnparsedFiles.clear();
+ }
+#endif // !NDEBUG
+
+ if (SrcManager) {
+ // Produce an error if no expected-* directives could be found in the
+ // source file(s) processed.
+ if (Status == HasNoDirectives) {
+ Diags.Report(diag::err_verify_no_directives).setForceEmit();
+ ++NumErrors;
+ Status = HasNoDirectivesReported;
}
-#endif
// Check that the expected diagnostics occurred.
- NumErrors += CheckResults(Diags, SM, *Buffer, ED);
+ NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
} else {
NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(),
Buffer->err_end(), "error") +
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index b7d4a3b92538..f789b7f3053f 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -24,7 +24,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include <cstring>
#include <utility>
@@ -51,8 +51,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
- Diags.setShowOverloads(
- static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads));
+ Diags.setShowOverloads(Opts.getShowOverloads());
Diags.setElideType(Opts.ElideType);
Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index fe9d5896e728..176511b0e4c8 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -11,7 +11,8 @@ add_dependencies(clangFrontendTool
target_link_libraries(clangFrontendTool
clangDriver
clangFrontend
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangCodeGen
clangStaticAnalyzerFrontend
clangStaticAnalyzerCheckers
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index bd50083bf1c9..c7c55b021145 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/OptTable.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -23,7 +24,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
-#include "clang/Rewrite/FrontendActions.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/DynamicLibrary.h"
using namespace clang;
@@ -137,7 +138,9 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
if (Clang->getFrontendOpts().ShowHelp) {
OwningPtr<driver::OptTable> Opts(driver::createDriverOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1",
- "LLVM 'Clang' Compiler: http://clang.llvm.org");
+ "LLVM 'Clang' Compiler: http://clang.llvm.org",
+ /*Include=*/driver::options::CC1Option,
+ /*Exclude=*/0);
return 0;
}
@@ -175,7 +178,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -analyzer-checker-help.
// This should happen AFTER plugins have been loaded!
- if (Clang->getAnalyzerOpts().ShowCheckerHelp) {
+ if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
return 0;
}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 6e9cc68540b6..25e4d903bb78 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -6,6 +6,7 @@ set(files
bmiintrin.h
bmi2intrin.h
emmintrin.h
+ f16cintrin.h
float.h
fma4intrin.h
fmaintrin.h
@@ -19,6 +20,7 @@ set(files
nmmintrin.h
pmmintrin.h
popcntintrin.h
+ rtmintrin.h
smmintrin.h
stdalign.h
stdarg.h
@@ -29,6 +31,8 @@ set(files
tmmintrin.h
varargs.h
wmmintrin.h
+ __wmmintrin_aes.h
+ __wmmintrin_pclmul.h
x86intrin.h
xmmintrin.h
xopintrin.h
diff --git a/lib/Headers/__wmmintrin_aes.h b/lib/Headers/__wmmintrin_aes.h
new file mode 100644
index 000000000000..2bfa027e07b1
--- /dev/null
+++ b/lib/Headers/__wmmintrin_aes.h
@@ -0,0 +1,67 @@
+/*===---- __wmmintrin_aes.h - AES 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 _WMMINTRIN_AES_H
+#define _WMMINTRIN_AES_H
+
+#include <emmintrin.h>
+
+#if !defined (__AES__)
+# error "AES instructions not enabled"
+#else
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesenc_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesenc128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesenclast_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesenclast128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesdec_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesdec128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesdeclast_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesdeclast128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesimc_si128(__m128i __V)
+{
+ return (__m128i)__builtin_ia32_aesimc128(__V);
+}
+
+#define _mm_aeskeygenassist_si128(C, R) \
+ __builtin_ia32_aeskeygenassist128((C), (R))
+
+#endif
+
+#endif /* _WMMINTRIN_AES_H */
diff --git a/lib/Headers/__wmmintrin_pclmul.h b/lib/Headers/__wmmintrin_pclmul.h
new file mode 100644
index 000000000000..8d1f1b7c0868
--- /dev/null
+++ b/lib/Headers/__wmmintrin_pclmul.h
@@ -0,0 +1,34 @@
+/*===---- __wmmintrin_pclmul.h - AES 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 _WMMINTRIN_PCLMUL_H
+#define _WMMINTRIN_PCLMUL_H
+
+#if !defined (__PCLMUL__)
+# error "PCLMUL instruction is not enabled"
+#else
+#define _mm_clmulepi64_si128(__X, __Y, __I) \
+ ((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(__X), \
+ (__v2di)(__m128i)(__Y), (char)(__I)))
+#endif
+
+#endif /* _WMMINTRIN_PCLMUL_H */
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index a225378c3062..2bf53fb43b9b 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -4363,14 +4363,14 @@ vec_perm(vector float a, vector float b, vector unsigned char c)
/* vec_vperm */
-vector signed char __ATTRS_o_ai
+static vector signed char __ATTRS_o_ai
vec_vperm(vector signed char a, vector signed char b, vector unsigned char c)
{
return (vector signed char)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector unsigned char __ATTRS_o_ai
+static vector unsigned char __ATTRS_o_ai
vec_vperm(vector unsigned char a,
vector unsigned char b,
vector unsigned char c)
@@ -4379,21 +4379,21 @@ vec_vperm(vector unsigned char a,
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector bool char __ATTRS_o_ai
+static vector bool char __ATTRS_o_ai
vec_vperm(vector bool char a, vector bool char b, vector unsigned char c)
{
return (vector bool char)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector short __ATTRS_o_ai
+static vector short __ATTRS_o_ai
vec_vperm(vector short a, vector short b, vector unsigned char c)
{
return (vector short)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector unsigned short __ATTRS_o_ai
+static vector unsigned short __ATTRS_o_ai
vec_vperm(vector unsigned short a,
vector unsigned short b,
vector unsigned char c)
@@ -4402,41 +4402,41 @@ vec_vperm(vector unsigned short a,
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector bool short __ATTRS_o_ai
+static vector bool short __ATTRS_o_ai
vec_vperm(vector bool short a, vector bool short b, vector unsigned char c)
{
return (vector bool short)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector pixel __ATTRS_o_ai
+static vector pixel __ATTRS_o_ai
vec_vperm(vector pixel a, vector pixel b, vector unsigned char c)
{
return (vector pixel)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector int __ATTRS_o_ai
+static vector int __ATTRS_o_ai
vec_vperm(vector int a, vector int b, vector unsigned char c)
{
return (vector int)__builtin_altivec_vperm_4si(a, b, c);
}
-vector unsigned int __ATTRS_o_ai
+static vector unsigned int __ATTRS_o_ai
vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c)
{
return (vector unsigned int)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector bool int __ATTRS_o_ai
+static vector bool int __ATTRS_o_ai
vec_vperm(vector bool int a, vector bool int b, vector unsigned char c)
{
return (vector bool int)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector float __ATTRS_o_ai
+static vector float __ATTRS_o_ai
vec_vperm(vector float a, vector float b, vector unsigned char c)
{
return (vector float)
@@ -4445,7 +4445,7 @@ vec_vperm(vector float a, vector float b, vector unsigned char c)
/* vec_re */
-vector float __attribute__((__always_inline__))
+static vector float __attribute__((__always_inline__))
vec_re(vector float a)
{
return __builtin_altivec_vrefp(a);
@@ -4453,7 +4453,7 @@ vec_re(vector float a)
/* vec_vrefp */
-vector float __attribute__((__always_inline__))
+static vector float __attribute__((__always_inline__))
vec_vrefp(vector float a)
{
return __builtin_altivec_vrefp(a);
diff --git a/lib/Headers/bmi2intrin.h b/lib/Headers/bmi2intrin.h
index c60b0c439315..a05cfad3d027 100644
--- a/lib/Headers/bmi2intrin.h
+++ b/lib/Headers/bmi2intrin.h
@@ -70,6 +70,25 @@ _pext_u64(unsigned long long __X, unsigned long long __Y)
return __builtin_ia32_pext_di(__X, __Y);
}
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_mulx_u64 (unsigned long long __X, unsigned long long __Y,
+ unsigned long long *__P)
+{
+ unsigned __int128 __res = (unsigned __int128) __X * __Y;
+ *__P = (unsigned long long) (__res >> 64);
+ return (unsigned long long) __res;
+}
+
+#else /* !__x86_64__ */
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_mulx_u32 (unsigned int __X, unsigned int __Y, unsigned int *__P)
+{
+ unsigned long long __res = (unsigned long long) __X * __Y;
+ *__P = (unsigned int) (__res >> 32);
+ return (unsigned int) __res;
+}
+
#endif /* !__x86_64__ */
#endif /* __BMI2INTRIN_H */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 05c293f6bd96..33df7c2d19f0 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -28,6 +28,6 @@
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));
+ __asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level));
return 1;
}
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
new file mode 100644
index 000000000000..2c96952446d6
--- /dev/null
+++ b/lib/Headers/f16cintrin.h
@@ -0,0 +1,58 @@
+/*===---- f16cintrin.h - F16C 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.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined __X86INTRIN_H && !defined __IMMINTRIN_H
+#error "Never use <f16cintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __F16C__
+# error "F16C instruction is not enabled"
+#endif /* __F16C__ */
+
+#ifndef __F16CINTRIN_H
+#define __F16CINTRIN_H
+
+typedef float __v8sf __attribute__ ((__vector_size__ (32)));
+typedef float __m256 __attribute__ ((__vector_size__ (32)));
+
+#define _mm_cvtps_ph(a, imm) __extension__ ({ \
+ __m128 __a = (a); \
+ (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)__a, (imm)); })
+
+#define _mm256_cvtps_ph(a, imm) __extension__ ({ \
+ __m256 __a = (a); \
+ (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (imm)); })
+
+static __inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtph_ps(__m128i a)
+{
+ return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)a);
+}
+
+static __inline __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtph_ps(__m128i a)
+{
+ return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)a);
+}
+
+#endif /* __F16CINTRIN_H */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index 15b65f3fd8c6..cd733bfc71d3 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -98,4 +98,8 @@ _rdrand64_step(unsigned long long *__p)
#endif
#endif /* __RDRND__ */
+#ifdef __RTM__
+#include <rtmintrin.h>
+#endif
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/module.map b/lib/Headers/module.map
index 418ba5009094..b24bccc12056 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.map
@@ -25,6 +25,11 @@ module _Builtin_intrinsics [system] {
header "mmintrin.h"
}
+ explicit module f16c {
+ requires f16c
+ header "f16cintrin.h"
+ }
+
explicit module sse {
requires sse
export mmx
@@ -62,6 +67,12 @@ module _Builtin_intrinsics [system] {
header "nmmintrin.h"
}
+ explicit module sse4a {
+ requires sse4a
+ export sse3
+ header "ammintrin.h"
+ }
+
explicit module avx {
requires avx
export sse4_2
@@ -84,6 +95,11 @@ module _Builtin_intrinsics [system] {
header "bmi2intrin.h"
}
+ explicit module fma {
+ requires fma
+ header "fmaintrin.h"
+ }
+
explicit module fma4 {
requires fma4
export sse3
@@ -104,5 +120,26 @@ module _Builtin_intrinsics [system] {
requires mm3dnow
header "mm3dnow.h"
}
+
+ explicit module xop {
+ requires xop
+ export fma4
+ header "xopintrin.h"
+ }
+
+ explicit module aes_pclmul {
+ requires aes, pclmul
+ header "wmmintrin.h"
+ }
+
+ explicit module aes {
+ requires aes
+ header "__wmmintrin_aes.h"
+ }
+
+ explicit module pclmul {
+ requires pclmul
+ header "__wmmintrin_pclmul.h"
+ }
}
}
diff --git a/lib/Headers/rtmintrin.h b/lib/Headers/rtmintrin.h
new file mode 100644
index 000000000000..bdc2b994264f
--- /dev/null
+++ b/lib/Headers/rtmintrin.h
@@ -0,0 +1,49 @@
+/*===---- rtmintrin.h - RTM 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 __IMMINTRIN_H
+#error "Never use <rtmintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#define _XBEGIN_STARTED (~0u)
+#define _XABORT_EXPLICIT (1 << 0)
+#define _XABORT_RETRY (1 << 1)
+#define _XABORT_CONFLICT (1 << 2)
+#define _XABORT_CAPACITY (1 << 3)
+#define _XABORT_DEBUG (1 << 4)
+#define _XABORT_NESTED (1 << 5)
+#define _XABORT_CODE(x) (((x) >> 24) & 0xFF)
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_xbegin(void)
+{
+ return __builtin_ia32_xbegin();
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_xend(void)
+{
+ __builtin_ia32_xend();
+}
+
+#define _xabort(imm) __builtin_ia32_xabort((imm))
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index a0659203b15c..6520b8316f3d 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -100,7 +100,7 @@ typedef enum {
_UVRSR_FAILED = 2
} _Unwind_VRS_Result;
-_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
+_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *context,
_Unwind_VRS_RegClass regclass,
uint32_t regno,
_Unwind_VRS_DataRepresentation representation,
diff --git a/lib/Headers/wmmintrin.h b/lib/Headers/wmmintrin.h
index dca896fd65d8..369e3c208e53 100644
--- a/lib/Headers/wmmintrin.h
+++ b/lib/Headers/wmmintrin.h
@@ -31,48 +31,11 @@
#else
#ifdef __AES__
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesenc_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesenc128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesenclast_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesenclast128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesdec_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesdec128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesdeclast_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesdeclast128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesimc_si128(__m128i __V)
-{
- return (__m128i)__builtin_ia32_aesimc128(__V);
-}
-
-#define _mm_aeskeygenassist_si128(C, R) \
- __builtin_ia32_aeskeygenassist128((C), (R))
-
+#include <__wmmintrin_aes.h>
#endif /* __AES__ */
#ifdef __PCLMUL__
-
-#define _mm_clmulepi64_si128(__X, __Y, __I) \
- ((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(__X), \
- (__v2di)(__m128i)(__Y), (char)(__I)))
-
+#include <__wmmintrin_pclmul.h>
#endif /* __PCLMUL__ */
#endif /* __AES__ || __PCLMUL__ */
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 556cd011f05d..68ce106be308 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -58,6 +58,10 @@
#include <xopintrin.h>
#endif
+#ifdef __F16C__
+#include <f16cintrin.h>
+#endif
+
// FIXME: LWP
#endif /* __X86INTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index e616157b047c..e2480ec7a0e3 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -95,7 +95,8 @@ _mm_div_ps(__m128 a, __m128 b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_sqrt_ss(__m128 a)
{
- return __builtin_ia32_sqrtss(a);
+ __m128 c = __builtin_ia32_sqrtss(a);
+ return (__m128) { c[0], a[1], a[2], a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -107,7 +108,8 @@ _mm_sqrt_ps(__m128 a)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rcp_ss(__m128 a)
{
- return __builtin_ia32_rcpss(a);
+ __m128 c = __builtin_ia32_rcpss(a);
+ return (__m128) { c[0], a[1], a[2], a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -119,7 +121,8 @@ _mm_rcp_ps(__m128 a)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rsqrt_ss(__m128 a)
{
- return __builtin_ia32_rsqrtss(a);
+ __m128 c = __builtin_ia32_rsqrtss(a);
+ return (__m128) { c[0], a[1], a[2], a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index bbfc1df76fdd..7dc0491392cc 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -144,7 +144,7 @@ HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
sizeof(HMapHeader));
const HMapBucket *BucketPtr = BucketArray+BucketNo;
- if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) {
+ if ((const char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) {
Result.Prefix = 0;
Result.Suffix = 0;
return Result; // Invalid buffer, corrupt hmap.
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index bb3a67378ad5..67000b682982 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#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"
@@ -38,10 +39,11 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
-HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+HeaderSearch::HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+ FileManager &FM, DiagnosticsEngine &Diags,
const LangOptions &LangOpts,
const TargetInfo *Target)
- : FileMgr(FM), Diags(Diags), FrameworkMap(64),
+ : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
ModMap(FileMgr, *Diags.getClient(), LangOpts, Target)
{
AngledDirIdx = 0;
@@ -905,7 +907,20 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
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);
@@ -924,7 +939,33 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
TopFrameworkDir = Dir;
}
} while (true);
-
+
+ // 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,
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 5212dd86e7a1..a5ba7dbe0a93 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -513,10 +513,13 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
const unsigned StartOffset = 1;
- SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset);
- Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(),
+ SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset);
+ Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(),
Buffer->getBufferStart(), Buffer->getBufferEnd());
-
+
+ // StartLoc will differ from FileLoc if there is a BOM that was skipped.
+ SourceLocation StartLoc = TheLexer.getSourceLocation();
+
bool InPreprocessorDirective = false;
Token TheTok;
Token IfStartTok;
@@ -1534,7 +1537,7 @@ FinishIdentifier:
/// isHexaLiteral - Return true if Start points to a hex constant.
/// in microsoft mode (where this is supposed to be several different tokens).
-static bool isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
+bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
unsigned Size;
char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts);
if (C1 != '0')
@@ -1813,17 +1816,18 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
while (C != '\'') {
// Skip escaped characters.
- if (C == '\\') {
- // Skip the escaped character.
- // FIXME: UCN's
- getAndAdvanceChar(CurPtr, Result);
- } else if (C == '\n' || C == '\r' || // Newline.
- (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (C == '\\')
+ C = getAndAdvanceChar(CurPtr, Result);
+
+ if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
- } else if (C == 0) {
+ }
+
+ if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
@@ -1895,21 +1899,21 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
return false;
}
-// SkipBCPLComment - We have just read the // characters from input. Skip until
-// we find the newline character thats terminate the comment. Then update
-/// BufferPtr and return.
+/// We have just read the // characters from input. Skip until we find the
+/// newline character thats terminate the comment. Then update BufferPtr and
+/// return.
///
/// If we're in KeepCommentMode or any CommentHandler has inserted
/// some tokens, this will store the first token and return true.
-bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
- // If BCPL comments aren't explicitly enabled for this language, emit an
+bool Lexer::SkipLineComment(Token &Result, const char *CurPtr) {
+ // If Line comments aren't explicitly enabled for this language, emit an
// extension warning.
- if (!LangOpts.BCPLComment && !isLexingRawMode()) {
- Diag(BufferPtr, diag::ext_bcpl_comment);
+ if (!LangOpts.LineComment && !isLexingRawMode()) {
+ Diag(BufferPtr, diag::ext_line_comment);
// Mark them enabled so we only emit one warning for this translation
// unit.
- LangOpts.BCPLComment = true;
+ LangOpts.LineComment = true;
}
// Scan over the body of the comment. The common case, when scanning, is that
@@ -1973,7 +1977,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
}
if (!isLexingRawMode())
- Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment);
+ Diag(OldPtr-1, diag::ext_multi_line_line_comment);
break;
}
}
@@ -2002,7 +2006,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
// If we are returning comments as tokens, return this comment as a token.
if (inKeepCommentMode())
- return SaveBCPLComment(Result, CurPtr);
+ return SaveLineComment(Result, CurPtr);
// If we are inside a preprocessor directive and we see the end of line,
// return immediately, so that the lexer can return this as an EOD token.
@@ -2026,9 +2030,9 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
return false;
}
-/// SaveBCPLComment - If in save-comment mode, package up this BCPL comment in
-/// an appropriate way and return it.
-bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
+/// If in save-comment mode, package up this Line comment in an appropriate
+/// way and return it.
+bool Lexer::SaveLineComment(Token &Result, const char *CurPtr) {
// If we're not in a preprocessor directive, just return the // comment
// directly.
FormTokenWithChars(Result, CurPtr, tok::comment);
@@ -2036,19 +2040,19 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
if (!ParsingPreprocessorDirective || LexingRawMode)
return true;
- // If this BCPL-style comment is in a macro definition, transmogrify it into
+ // If this Line-style comment is in a macro definition, transmogrify it into
// a C-style block comment.
bool Invalid = false;
std::string Spelling = PP->getSpelling(Result, &Invalid);
if (Invalid)
return true;
- assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
+ assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not line comment?");
Spelling[1] = '*'; // Change prefix to "/*".
Spelling += "*/"; // add suffix.
Result.setKind(tok::comment);
- PP->CreateString(&Spelling[0], Spelling.size(), Result,
+ PP->CreateString(Spelling, Result,
Result.getLocation(), Result.getLocation());
return true;
}
@@ -2179,7 +2183,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
#ifdef __SSE2__
__m128i Slashes = _mm_set1_epi8('/');
while (CurPtr+16 <= BufferEnd) {
- int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes));
+ int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr,
+ Slashes));
if (cmp != 0) {
// Adjust the pointer to point directly after the first slash. It's
// not necessary to set C here, it will be overwritten at the end of
@@ -2669,8 +2674,8 @@ LexNextToken:
// If the next token is obviously a // or /* */ comment, skip it efficiently
// too (without going through the big switch stmt).
if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
- LangOpts.BCPLComment && !LangOpts.TraditionalCPP) {
- if (SkipBCPLComment(Result, CurPtr+2))
+ LangOpts.LineComment && !LangOpts.TraditionalCPP) {
+ if (SkipLineComment(Result, CurPtr+2))
return; // There is a token to return.
goto SkipIgnoredUnits;
} else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
@@ -2955,19 +2960,19 @@ LexNextToken:
case '/':
// 6.4.9: Comments
Char = getCharAndSize(CurPtr, SizeTmp);
- if (Char == '/') { // BCPL comment.
- // Even if BCPL comments are disabled (e.g. in C89 mode), we generally
+ if (Char == '/') { // Line comment.
+ // Even if Line comments are disabled (e.g. in C89 mode), we generally
// want to lex this as a comment. There is one problem with this though,
// that in one particular corner case, this can change the behavior of the
// resultant program. For example, In "foo //**/ bar", C89 would lex
- // this as "foo / bar" and langauges with BCPL comments would lex it as
+ // 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.BCPLComment ||
+ if ((LangOpts.LineComment ||
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
!LangOpts.TraditionalCPP) {
- if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
+ if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
// It is common for the tokens immediately after a // comment to be
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 9e3c7786a732..e30612e57c5b 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -49,12 +49,46 @@ static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
}
}
+static CharSourceRange MakeCharSourceRange(const LangOptions &Features,
+ FullSourceLoc TokLoc,
+ const char *TokBegin,
+ const char *TokRangeBegin,
+ const char *TokRangeEnd) {
+ SourceLocation Begin =
+ Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin,
+ TokLoc.getManager(), Features);
+ SourceLocation End =
+ Lexer::AdvanceToTokenCharacter(Begin, TokRangeEnd - TokRangeBegin,
+ TokLoc.getManager(), Features);
+ return CharSourceRange::getCharRange(Begin, End);
+}
+
+/// \brief Produce a diagnostic highlighting some portion of a literal.
+///
+/// Emits the diagnostic \p DiagID, highlighting the range of characters from
+/// \p TokRangeBegin (inclusive) to \p TokRangeEnd (exclusive), which must be
+/// a substring of a spelling buffer for the token beginning at \p TokBegin.
+static DiagnosticBuilder Diag(DiagnosticsEngine *Diags,
+ const LangOptions &Features, FullSourceLoc TokLoc,
+ const char *TokBegin, const char *TokRangeBegin,
+ const char *TokRangeEnd, unsigned DiagID) {
+ SourceLocation Begin =
+ Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin,
+ TokLoc.getManager(), Features);
+ return Diags->Report(Begin, DiagID) <<
+ MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, TokRangeEnd);
+}
+
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
/// either a character or a string literal.
-static unsigned ProcessCharEscape(const char *&ThisTokBuf,
+static unsigned ProcessCharEscape(const char *ThisTokBegin,
+ const char *&ThisTokBuf,
const char *ThisTokEnd, bool &HadError,
FullSourceLoc Loc, unsigned CharWidth,
- DiagnosticsEngine *Diags) {
+ DiagnosticsEngine *Diags,
+ const LangOptions &Features) {
+ const char *EscapeBegin = ThisTokBuf;
+
// Skip the '\' char.
++ThisTokBuf;
@@ -75,12 +109,14 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
break;
case 'e':
if (Diags)
- Diags->Report(Loc, diag::ext_nonstandard_escape) << "e";
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_nonstandard_escape) << "e";
ResultChar = 27;
break;
case 'E':
if (Diags)
- Diags->Report(Loc, diag::ext_nonstandard_escape) << "E";
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_nonstandard_escape) << "E";
ResultChar = 27;
break;
case 'f':
@@ -102,7 +138,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
ResultChar = 0;
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
if (Diags)
- Diags->Report(Loc, diag::err_hex_escape_no_digits);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::err_hex_escape_no_digits);
HadError = 1;
break;
}
@@ -126,7 +163,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
// Check for overflow.
if (Overflow && Diags) // Too many digits to fit in
- Diags->Report(Loc, diag::warn_hex_escape_too_large);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::warn_hex_escape_too_large);
break;
}
case '0': case '1': case '2': case '3':
@@ -148,7 +186,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
// Check for overflow. Reject '\777', but not L'\777'.
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
if (Diags)
- Diags->Report(Loc, diag::warn_octal_escape_too_large);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::warn_octal_escape_too_large);
ResultChar &= ~0U >> (32-CharWidth);
}
break;
@@ -158,19 +197,22 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
case '(': case '{': case '[': case '%':
// GCC accepts these as extensions. We warn about them as such though.
if (Diags)
- Diags->Report(Loc, diag::ext_nonstandard_escape)
- << std::string()+(char)ResultChar;
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_nonstandard_escape)
+ << std::string(1, ResultChar);
break;
default:
if (Diags == 0)
break;
-
+
if (isgraph(ResultChar))
- Diags->Report(Loc, diag::ext_unknown_escape)
- << std::string()+(char)ResultChar;
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_unknown_escape)
+ << std::string(1, ResultChar);
else
- Diags->Report(Loc, diag::ext_unknown_escape)
- << "x"+llvm::utohexstr(ResultChar);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_unknown_escape)
+ << "x" + llvm::utohexstr(ResultChar);
break;
}
@@ -185,9 +227,6 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
FullSourceLoc Loc, DiagnosticsEngine *Diags,
const LangOptions &Features,
bool in_char_string_literal = false) {
- if (!Features.CPlusPlus && !Features.C99 && Diags)
- Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89);
-
const char *UcnBegin = ThisTokBuf;
// Skip the '\u' char's.
@@ -195,7 +234,8 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
if (Diags)
- Diags->Report(Loc, diag::err_ucn_escape_no_digits);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::err_ucn_escape_no_digits);
return false;
}
UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8);
@@ -208,12 +248,9 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
}
// If we didn't consume the proper number of digits, there is a problem.
if (UcnLenSave) {
- if (Diags) {
- SourceLocation L =
- Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin,
- Loc.getManager(), Features);
- Diags->Report(L, diag::err_ucn_escape_incomplete);
- }
+ if (Diags)
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::err_ucn_escape_incomplete);
return false;
}
@@ -221,7 +258,8 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if ((0xD800 <= UcnVal && UcnVal <= 0xDFFF) || // surrogate codepoints
UcnVal > 0x10FFFF) { // maximum legal UTF32 value
if (Diags)
- Diags->Report(Loc, diag::err_ucn_escape_invalid);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::err_ucn_escape_invalid);
return false;
}
@@ -231,22 +269,25 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, `
bool IsError = (!Features.CPlusPlus0x || !in_char_string_literal);
if (Diags) {
- SourceLocation UcnBeginLoc =
- Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin,
- Loc.getManager(), Features);
char BasicSCSChar = UcnVal;
if (UcnVal >= 0x20 && UcnVal < 0x7f)
- Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_escape_basic_scs :
- diag::warn_cxx98_compat_literal_ucn_escape_basic_scs)
- << StringRef(&BasicSCSChar, 1);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ IsError ? diag::err_ucn_escape_basic_scs :
+ diag::warn_cxx98_compat_literal_ucn_escape_basic_scs)
+ << StringRef(&BasicSCSChar, 1);
else
- Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_control_character :
- diag::warn_cxx98_compat_literal_ucn_control_character);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ IsError ? diag::err_ucn_control_character :
+ diag::warn_cxx98_compat_literal_ucn_control_character);
}
if (IsError)
return false;
}
+ if (!Features.CPlusPlus && !Features.C99 && Diags)
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::warn_ucn_not_valid_in_c89);
+
return true;
}
@@ -365,10 +406,10 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// Finally, we write the bytes into ResultBuf.
ResultBuf += bytesToWrite;
switch (bytesToWrite) { // note: everything falls through.
- case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
+ case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
}
// Update the buffer.
ResultBuf += bytesToWrite;
@@ -417,19 +458,19 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
/// floating-constant: [C99 6.4.4.2]
/// TODO: add rules...
///
-NumericLiteralParser::
-NumericLiteralParser(const char *begin, const char *end,
- SourceLocation TokLoc, Preprocessor &pp)
- : PP(pp), ThisTokBegin(begin), ThisTokEnd(end) {
+NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
+ SourceLocation TokLoc,
+ Preprocessor &PP)
+ : PP(PP), ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) {
// This routine assumes that the range begin/end matches the regex for integer
// 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(*end) && *end != '.' && *end != '_' &&
+ assert(!isalnum(*ThisTokEnd) && *ThisTokEnd != '.' && *ThisTokEnd != '_' &&
"Lexer didn't maximally munch?");
- s = DigitsBegin = begin;
+ s = DigitsBegin = ThisTokBegin;
saw_exponent = false;
saw_period = false;
saw_ud_suffix = false;
@@ -451,7 +492,7 @@ NumericLiteralParser(const char *begin, const char *end,
if (s == ThisTokEnd) {
// Done.
} else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_invalid_decimal_digit) << StringRef(s, 1);
hadError = true;
return;
@@ -469,7 +510,7 @@ NumericLiteralParser(const char *begin, const char *end,
if (first_non_digit != s) {
s = first_non_digit;
} else {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent - ThisTokBegin),
diag::err_exponent_has_no_digits);
hadError = true;
return;
@@ -565,7 +606,7 @@ NumericLiteralParser(const char *begin, const char *end,
case 'j':
case 'J':
if (isImaginary) break; // Cannot be repeated.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::ext_imaginary_constant);
isImaginary = true;
continue; // Success.
@@ -583,7 +624,7 @@ NumericLiteralParser(const char *begin, const char *end,
}
// Report an error if there are any.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
isFPConstant ? diag::err_invalid_suffix_float_constant :
diag::err_invalid_suffix_integer_constant)
<< StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);
@@ -619,7 +660,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
if (noSignificand) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), \
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_hexconstant_requires_digits);
hadError = true;
return;
@@ -722,6 +763,20 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
}
+static bool alwaysFitsInto64Bits(unsigned Radix, unsigned NumDigits) {
+ switch (Radix) {
+ case 2:
+ return NumDigits <= 64;
+ case 8:
+ return NumDigits <= 64 / 3; // Digits are groups of 3 bits.
+ case 10:
+ return NumDigits <= 19; // floor(log10(2^64))
+ case 16:
+ return NumDigits <= 64 / 4; // Digits are groups of 4 bits.
+ default:
+ llvm_unreachable("impossible Radix");
+ }
+}
/// GetIntegerValue - Convert this numeric literal value to an APInt that
/// matches Val's input width. If there is an overflow, set Val to the low bits
@@ -733,13 +788,11 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
// integer. This avoids the expensive overflow checking below, and
// handles the common cases that matter (small decimal integers and
// hex/octal values which don't overflow).
- unsigned MaxBitsPerDigit = 1;
- while ((1U << MaxBitsPerDigit) < radix)
- MaxBitsPerDigit += 1;
- if ((SuffixBegin - DigitsBegin) * MaxBitsPerDigit <= 64) {
+ const unsigned NumDigits = SuffixBegin - DigitsBegin;
+ if (alwaysFitsInto64Bits(radix, NumDigits)) {
uint64_t N = 0;
- for (s = DigitsBegin; s != SuffixBegin; ++s)
- N = N*radix + HexDigitValue(*s);
+ for (const char *Ptr = DigitsBegin; Ptr != SuffixBegin; ++Ptr)
+ N = N * radix + HexDigitValue(*Ptr);
// This will truncate the value to Val's input width. Simply check
// for overflow by comparing.
@@ -748,15 +801,15 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
}
Val = 0;
- s = DigitsBegin;
+ const char *Ptr = DigitsBegin;
llvm::APInt RadixVal(Val.getBitWidth(), radix);
llvm::APInt CharVal(Val.getBitWidth(), 0);
llvm::APInt OldVal = Val;
bool OverflowOccurred = false;
- while (s < SuffixBegin) {
- unsigned C = HexDigitValue(*s++);
+ while (Ptr < SuffixBegin) {
+ unsigned C = HexDigitValue(*Ptr++);
// If this letter is out of bound for this radix, reject it.
assert(C < radix && "NumericLiteralParser ctor should have rejected this");
@@ -943,7 +996,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
HadError = true;
} else if (*buffer_begin > largest_character_for_kind) {
HadError = true;
- PP.Diag(Loc,diag::err_character_too_large);
+ PP.Diag(Loc, diag::err_character_too_large);
}
++buffer_begin;
@@ -951,9 +1004,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
}
unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
uint64_t result =
- ProcessCharEscape(begin, end, HadError,
- FullSourceLoc(Loc,PP.getSourceManager()),
- CharWidth, &PP.getDiagnostics());
+ ProcessCharEscape(TokBegin, begin, end, HadError,
+ FullSourceLoc(Loc,PP.getSourceManager()),
+ CharWidth, &PP.getDiagnostics(), PP.getLangOpts());
*buffer_begin++ = result;
}
@@ -1110,7 +1163,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
Kind = StringToks[i].getKind();
} else {
if (Diags)
- Diags->Report(FullSourceLoc(StringToks[i].getLocation(), SM),
+ Diags->Report(StringToks[i].getLocation(),
diag::err_unsupported_string_concat);
hadError = true;
}
@@ -1218,9 +1271,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
assert(ThisTokEnd >= ThisTokBuf && "malformed raw string literal");
// Copy the string over
- if (CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf)))
- if (DiagnoseBadString(StringToks[i]))
- hadError = true;
+ if (CopyStringFragment(StringToks[i], ThisTokBegin,
+ StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf)))
+ hadError = true;
} else {
if (ThisTokBuf[0] != '"') {
// The file may have come from PCH and then changed after loading the
@@ -1251,9 +1304,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
} while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
// Copy the character span over.
- if (CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart)))
- if (DiagnoseBadString(StringToks[i]))
- hadError = true;
+ if (CopyStringFragment(StringToks[i], ThisTokBegin,
+ StringRef(InStart, ThisTokBuf - InStart)))
+ hadError = true;
continue;
}
// Is this a Universal Character Name escape?
@@ -1266,9 +1319,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
}
// Otherwise, this is a non-UCN escape character. Process it.
unsigned ResultChar =
- ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
+ ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
FullSourceLoc(StringToks[i].getLocation(), SM),
- CharByteWidth*8, Diags);
+ CharByteWidth*8, Diags, Features);
if (CharByteWidth == 4) {
// FIXME: Make the type of the result buffer correct instead of
@@ -1308,8 +1361,8 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// Verify that pascal strings aren't too large.
if (GetStringLength() > 256) {
- if (Diags)
- Diags->Report(FullSourceLoc(StringToks[0].getLocation(), SM),
+ if (Diags)
+ Diags->Report(StringToks[0].getLocation(),
diag::err_pascal_string_too_long)
<< SourceRange(StringToks[0].getLocation(),
StringToks[NumStringToks-1].getLocation());
@@ -1319,9 +1372,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
} else if (Diags) {
// Complain if this string literal has too many characters.
unsigned MaxChars = Features.CPlusPlus? 65536 : Features.C99 ? 4095 : 509;
-
+
if (GetNumStringChars() > MaxChars)
- Diags->Report(FullSourceLoc(StringToks[0].getLocation(), SM),
+ Diags->Report(StringToks[0].getLocation(),
diag::ext_string_too_long)
<< GetNumStringChars() << MaxChars
<< (Features.CPlusPlus ? 2 : Features.C99 ? 1 : 0)
@@ -1330,21 +1383,61 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
}
}
-/// copyStringFragment - This function copies from Start to End into ResultPtr.
-/// Performs widening for multi-byte characters.
-bool StringLiteralParser::CopyStringFragment(StringRef Fragment) {
- return !ConvertUTF8toWide(CharByteWidth, Fragment, ResultPtr);
+static const char *resyncUTF8(const char *Err, const char *End) {
+ if (Err == End)
+ return End;
+ End = Err + std::min<unsigned>(getNumBytesForUTF8(*Err), End-Err);
+ while (++Err != End && (*Err & 0xC0) == 0x80)
+ ;
+ return Err;
}
-bool StringLiteralParser::DiagnoseBadString(const Token &Tok) {
+/// \brief This function copies from Fragment, which is a sequence of bytes
+/// within Tok's contents (which begin at TokBegin) into ResultPtr.
+/// Performs widening for multi-byte characters.
+bool StringLiteralParser::CopyStringFragment(const Token &Tok,
+ const char *TokBegin,
+ StringRef Fragment) {
+ const UTF8 *ErrorPtrTmp;
+ if (ConvertUTF8toWide(CharByteWidth, Fragment, ResultPtr, ErrorPtrTmp))
+ return false;
+
// If we see bad encoding for unprefixed string literals, warn and
// simply copy the byte values, for compatibility with gcc and older
// versions of clang.
bool NoErrorOnBadEncoding = isAscii();
- unsigned Msg = NoErrorOnBadEncoding ? diag::warn_bad_string_encoding :
- diag::err_bad_string_encoding;
- if (Diags)
- Diags->Report(FullSourceLoc(Tok.getLocation(), SM), Msg);
+ if (NoErrorOnBadEncoding) {
+ memcpy(ResultPtr, Fragment.data(), Fragment.size());
+ ResultPtr += Fragment.size();
+ }
+
+ if (Diags) {
+ const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp);
+
+ FullSourceLoc SourceLoc(Tok.getLocation(), SM);
+ const DiagnosticBuilder &Builder =
+ Diag(Diags, Features, SourceLoc, TokBegin,
+ ErrorPtr, resyncUTF8(ErrorPtr, Fragment.end()),
+ NoErrorOnBadEncoding ? diag::warn_bad_string_encoding
+ : diag::err_bad_string_encoding);
+
+ const char *NextStart = resyncUTF8(ErrorPtr, Fragment.end());
+ StringRef NextFragment(NextStart, Fragment.end()-NextStart);
+
+ // Decode into a dummy buffer.
+ SmallString<512> Dummy;
+ Dummy.reserve(Fragment.size() * CharByteWidth);
+ char *Ptr = Dummy.data();
+
+ while (!Builder.hasMaxRanges() &&
+ !ConvertUTF8toWide(CharByteWidth, NextFragment, Ptr, ErrorPtrTmp)) {
+ const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp);
+ NextStart = resyncUTF8(ErrorPtr, Fragment.end());
+ Builder << MakeCharSourceRange(Features, SourceLoc, TokBegin,
+ ErrorPtr, NextStart);
+ NextFragment = StringRef(NextStart, Fragment.end()-NextStart);
+ }
+ }
return !NoErrorOnBadEncoding;
}
@@ -1422,9 +1515,9 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
}
ByteNo -= Len;
} else {
- ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
+ ProcessCharEscape(SpellingStart, SpellingPtr, SpellingEnd, HadError,
FullSourceLoc(Tok.getLocation(), SM),
- CharByteWidth*8, Diags);
+ CharByteWidth*8, Diags, Features);
--ByteNo;
}
assert(!HadError && "This method isn't valid on erroneous strings");
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index e2b251a4499d..ed8873d08612 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -291,7 +291,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
}
}
- PP.CreateString(&Result[0], Result.size(), Tok,
+ PP.CreateString(Result, Tok,
ExpansionLocStart, ExpansionLocEnd);
return Tok;
}
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 3d0c9a1c2b51..904f04e4f836 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -15,47 +15,65 @@
#include "clang/Lex/Preprocessor.h"
using namespace clang;
-MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
- IsFunctionLike = false;
- IsC99Varargs = false;
- IsGNUVarargs = false;
- IsBuiltinMacro = false;
- IsFromAST = false;
- ChangedAfterLoad = false;
- IsDisabled = false;
- IsUsed = false;
- IsAllowRedefinitionsWithoutWarning = false;
- IsWarnIfUnused = false;
- IsDefinitionLengthCached = false;
- IsPublic = true;
-
- ArgumentList = 0;
- NumArguments = 0;
+MacroInfo::MacroInfo(SourceLocation DefLoc)
+ : Location(DefLoc),
+ PreviousDefinition(0),
+ ArgumentList(0),
+ NumArguments(0),
+ IsDefinitionLengthCached(false),
+ IsFunctionLike(false),
+ IsC99Varargs(false),
+ IsGNUVarargs(false),
+ IsBuiltinMacro(false),
+ IsFromAST(false),
+ ChangedAfterLoad(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;
- ReplacementTokens = MI.ReplacementTokens;
- 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;
- IsDefinitionLengthCached = MI.IsDefinitionLengthCached;
- DefinitionLength = MI.DefinitionLength;
- IsPublic = MI.IsPublic;
-
- ArgumentList = 0;
- NumArguments = 0;
+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;
+}
+
unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
assert(!IsDefinitionLengthCached);
IsDefinitionLengthCached = true;
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 5304311ef619..8a936fa8e145 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/LexDiagnostic.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"
@@ -26,6 +27,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include <stdlib.h>
using namespace clang;
Module::ExportDecl
@@ -75,7 +77,7 @@ ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
{
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
- new DiagnosticsEngine(DiagIDs));
+ new DiagnosticsEngine(DiagIDs, new DiagnosticOptions));
Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true);
SourceMgr = new SourceManager(*Diags, FileMgr);
}
@@ -96,16 +98,62 @@ void ModuleMap::setTarget(const TargetInfo &Target) {
this->Target = &Target;
}
+/// \brief "Sanitize" a filename so that it can be used as an identifier.
+static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
+ SmallVectorImpl<char> &Buffer) {
+ 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 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]))
+ 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]))
+ Buffer.push_back(Name[I]);
+ else
+ Buffer.push_back('_');
+ }
+
+ Name = StringRef(Buffer.data(), Buffer.size());
+ }
+
+ while (llvm::StringSwitch<bool>(Name)
+#define KEYWORD(Keyword,Conditions) .Case(#Keyword, true)
+#define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true)
+#include "clang/Basic/TokenKinds.def"
+ .Default(false)) {
+ if (Name.data() != Buffer.data())
+ Buffer.append(Name.begin(), Name.end());
+ Buffer.push_back('_');
+ Name = StringRef(Buffer.data(), Buffer.size());
+ }
+
+ return Name;
+}
+
Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
- llvm::DenseMap<const FileEntry *, Module *>::iterator Known
- = Headers.find(File);
+ HeadersMap::iterator Known = Headers.find(File);
if (Known != Headers.end()) {
- // If a header corresponds to an unavailable module, don't report
- // that it maps to anything.
- if (!Known->second->isAvailable())
+ // If a header is not available, don't report that it maps to anything.
+ if (!Known->second.isAvailable())
return 0;
- return Known->second;
+ return Known->second.getModule();
}
const DirectoryEntry *Dir = File->getDir();
@@ -134,7 +182,10 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
- StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
+ NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
@@ -148,9 +199,12 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
// Infer a submodule with the same name as this header file.
- StringRef Name = llvm::sys::path::stem(File->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(File->getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
+ Result->TopHeaders.insert(File);
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
@@ -163,7 +217,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
UmbrellaDirs[SkippedDirs[I]] = Result;
}
- Headers[File] = Result;
+ Headers[File] = KnownHeader(Result, /*Excluded=*/false);
// If a header corresponds to an unavailable module, don't report
// that it maps to anything.
@@ -188,10 +242,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
- llvm::DenseMap<const FileEntry *, Module *>::iterator Known
- = Headers.find(Header);
+ HeadersMap::iterator Known = Headers.find(Header);
if (Known != Headers.end())
- return !Known->second->isAvailable();
+ return !Known->second.isAvailable();
const DirectoryEntry *Dir = Header->getDir();
llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -216,7 +269,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
if (UmbrellaModule->InferSubmodules) {
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
- StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
+ NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -225,7 +281,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
}
// Infer a submodule with the same name as this header file.
- StringRef Name = llvm::sys::path::stem(Header->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(Header->getName()),
+ NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -287,8 +346,32 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
return std::make_pair(Result, true);
}
+bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
+ StringRef Name, bool &IsSystem) {
+ // Check whether we have already looked into the parent directory
+ // for a module map.
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ inferred = InferredDirectories.find(ParentDir);
+ if (inferred == InferredDirectories.end())
+ return false;
+
+ if (!inferred->second.InferModules)
+ return false;
+
+ // We're allowed to infer for this directory, but make sure it's okay
+ // to infer this particular module.
+ bool canInfer = std::find(inferred->second.ExcludedModules.begin(),
+ inferred->second.ExcludedModules.end(),
+ Name) == inferred->second.ExcludedModules.end();
+
+ if (canInfer && inferred->second.InferSystemModules)
+ IsSystem = true;
+
+ return canInfer;
+}
+
Module *
-ModuleMap::inferFrameworkModule(StringRef ModuleName,
+ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir,
bool IsSystem,
Module *Parent) {
@@ -297,7 +380,54 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
return Mod;
FileManager &FileMgr = SourceMgr->getFileManager();
-
+
+ // If the framework has a parent path from which we're allowed to infer
+ // a framework module, do so.
+ if (!Parent) {
+ bool canInfer = false;
+ if (llvm::sys::path::has_parent_path(FrameworkDir->getName())) {
+ // Figure out the parent path.
+ StringRef Parent = llvm::sys::path::parent_path(FrameworkDir->getName());
+ 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
+ inferred = InferredDirectories.find(ParentDir);
+ if (inferred == InferredDirectories.end()) {
+ // We haven't looked here before. Load a module map, if there is
+ // one.
+ SmallString<128> ModMapPath = Parent;
+ llvm::sys::path::append(ModMapPath, "module.map");
+ if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
+ parseModuleMapFile(ModMapFile);
+ inferred = InferredDirectories.find(ParentDir);
+ }
+
+ if (inferred == InferredDirectories.end())
+ inferred = InferredDirectories.insert(
+ std::make_pair(ParentDir, InferredDirectory())).first;
+ }
+
+ 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());
+ canInfer = std::find(inferred->second.ExcludedModules.begin(),
+ inferred->second.ExcludedModules.end(),
+ Name) == inferred->second.ExcludedModules.end();
+
+ if (inferred->second.InferSystemModules)
+ IsSystem = true;
+ }
+ }
+ }
+
+ // If we're not allowed to infer a framework module, don't.
+ if (!canInfer)
+ return 0;
+ }
+
+
// Look for an umbrella header.
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
llvm::sys::path::append(UmbrellaName, "Headers");
@@ -320,7 +450,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader;
- Headers[UmbrellaHeader] = Result;
+ Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false);
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
@@ -343,12 +473,42 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (!StringRef(Dir->path()).endswith(".framework"))
continue;
-
+
if (const DirectoryEntry *SubframeworkDir
= FileMgr.getDirectory(Dir->path())) {
+ // Note: as an egregious but useful hack, we use the real path here and
+ // 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);
+
+ if (!FoundParent)
+ continue;
+ }
+#endif
+
// FIXME: Do we want to warn about subframeworks without umbrella headers?
- inferFrameworkModule(llvm::sys::path::stem(Dir->path()), SubframeworkDir,
- IsSystem, Result);
+ SmallString<32> NameBuf;
+ inferFrameworkModule(sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(Dir->path()), NameBuf),
+ SubframeworkDir, IsSystem, Result);
}
}
@@ -356,7 +516,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
- Headers[UmbrellaHeader] = Mod;
+ Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false);
Mod->Umbrella = UmbrellaHeader;
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
}
@@ -366,9 +526,13 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
UmbrellaDirs[UmbrellaDir] = Mod;
}
-void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
- Mod->Headers.push_back(Header);
- Headers[Header] = Mod;
+void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
+ bool Excluded) {
+ if (Excluded)
+ Mod->ExcludedHeaders.push_back(Header);
+ else
+ Mod->Headers.push_back(Header);
+ Headers[Header] = KnownHeader(Mod, Excluded);
}
const FileEntry *
@@ -388,12 +552,10 @@ void ModuleMap::dump() {
M->getValue()->print(llvm::errs(), 2);
llvm::errs() << "Headers:";
- for (llvm::DenseMap<const FileEntry *, Module *>::iterator
- H = Headers.begin(),
- HEnd = Headers.end();
+ for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
H != HEnd; ++H) {
llvm::errs() << " \"" << H->first->getName() << "\" -> "
- << H->second->getFullModuleName() << "\n";
+ << H->second.getModule()->getFullModuleName() << "\n";
}
}
@@ -454,6 +616,7 @@ namespace clang {
EndOfFile,
HeaderKeyword,
Identifier,
+ ExcludeKeyword,
ExplicitKeyword,
ExportKeyword,
FrameworkKeyword,
@@ -490,10 +653,24 @@ namespace clang {
return StringRef(StringData, StringLength);
}
};
+
+ /// \brief The set of attributes that can be attached to a module.
+ struct Attributes {
+ Attributes() : IsSystem() { }
+
+ /// \brief Whether this is a system module.
+ unsigned IsSystem : 1;
+ };
+
class ModuleMapParser {
Lexer &L;
SourceManager &SourceMgr;
+
+ /// \brief Default target information, used only for string literal
+ /// parsing.
+ const TargetInfo *Target;
+
DiagnosticsEngine &Diags;
ModuleMap &Map;
@@ -505,11 +682,7 @@ namespace clang {
/// \brief Whether an error occurred.
bool HadError;
-
- /// \brief Default target information, used only for string literal
- /// parsing.
- OwningPtr<TargetInfo> Target;
-
+
/// \brief Stores string data for the various string literals referenced
/// during parsing.
llvm::BumpPtrAllocator StringData;
@@ -532,27 +705,25 @@ namespace clang {
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseRequiresDecl();
- void parseHeaderDecl(SourceLocation UmbrellaLoc);
+ void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
- void parseInferredSubmoduleDecl(bool Explicit);
-
+ void parseInferredModuleDecl(bool Framework, bool Explicit);
+ bool parseOptionalAttributes(Attributes &Attrs);
+
const DirectoryEntry *getOverriddenHeaderSearchDir();
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
+ const TargetInfo *Target,
DiagnosticsEngine &Diags,
ModuleMap &Map,
const DirectoryEntry *Directory,
const DirectoryEntry *BuiltinIncludeDir)
- : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
+ : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
HadError(false), ActiveModule(0)
{
- TargetOptions TargetOpts;
- TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
- Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
-
Tok.clear();
consumeToken();
}
@@ -575,6 +746,7 @@ retry:
Tok.StringLength = LToken.getLength();
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
.Case("header", MMToken::HeaderKeyword)
+ .Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
@@ -743,13 +915,6 @@ namespace {
/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
/// { module-member* }
///
-/// attributes:
-/// attribute attributes
-/// attribute
-///
-/// attribute:
-/// [ identifier ]
-///
/// module-member:
/// requires-declaration
/// header-declaration
@@ -791,7 +956,7 @@ void ModuleMapParser::parseModuleDecl() {
// If we have a wildcard for the module name, this is an inferred submodule.
// Parse it.
if (Tok.is(MMToken::Star))
- return parseInferredSubmoduleDecl(Explicit);
+ return parseInferredModuleDecl(Framework, Explicit);
// Parse the module name.
ModuleId Id;
@@ -799,7 +964,7 @@ void ModuleMapParser::parseModuleDecl() {
HadError = true;
return;
}
-
+
if (ActiveModule) {
if (Id.size() > 1) {
Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
@@ -842,47 +1007,8 @@ void ModuleMapParser::parseModuleDecl() {
SourceLocation ModuleNameLoc = Id.back().second;
// Parse the optional attribute list.
- bool IsSystem = false;
- while (Tok.is(MMToken::LSquare)) {
- // Consume the '['.
- SourceLocation LSquareLoc = consumeToken();
-
- // Check whether we have an attribute name here.
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
- skipUntil(MMToken::RSquare);
- if (Tok.is(MMToken::RSquare))
- consumeToken();
- continue;
- }
-
- // Decode the attribute name.
- AttributeKind Attribute
- = llvm::StringSwitch<AttributeKind>(Tok.getString())
- .Case("system", AT_system)
- .Default(AT_unknown);
- switch (Attribute) {
- case AT_unknown:
- Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
- << Tok.getString();
- break;
-
- case AT_system:
- IsSystem = true;
- break;
- }
- consumeToken();
-
- // Consume the ']'.
- if (!Tok.is(MMToken::RSquare)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
- Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
- skipUntil(MMToken::RSquare);
- }
-
- if (Tok.is(MMToken::RSquare))
- consumeToken();
- }
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
// Parse the opening brace.
if (!Tok.is(MMToken::LBrace)) {
@@ -925,7 +1051,7 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
- if (IsSystem)
+ if (Attrs.IsSystem)
ActiveModule->IsSystem = true;
bool Done = false;
@@ -953,14 +1079,25 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword))
- parseHeaderDecl(UmbrellaLoc);
+ parseHeaderDecl(UmbrellaLoc, SourceLocation());
else
parseUmbrellaDirDecl(UmbrellaLoc);
break;
}
+ case MMToken::ExcludeKeyword: {
+ SourceLocation ExcludeLoc = consumeToken();
+ if (Tok.is(MMToken::HeaderKeyword)) {
+ parseHeaderDecl(SourceLocation(), ExcludeLoc);
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << "exclude";
+ }
+ break;
+ }
+
case MMToken::HeaderKeyword:
- parseHeaderDecl(SourceLocation());
+ parseHeaderDecl(SourceLocation(), SourceLocation());
break;
default:
@@ -1062,12 +1199,15 @@ static bool isBuiltinHeader(StringRef FileName) {
///
/// header-declaration:
/// 'umbrella'[opt] 'header' string-literal
-void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
+/// 'exclude'[opt] 'header' string-literal
+void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
+ SourceLocation ExcludeLoc) {
assert(Tok.is(MMToken::HeaderKeyword));
consumeToken();
bool Umbrella = UmbrellaLoc.isValid();
-
+ bool Exclude = ExcludeLoc.isValid();
+ assert(!(Umbrella && Exclude) && "Cannot have both 'umbrella' and 'exclude'");
// Parse the header name.
if (!Tok.is(MMToken::StringLiteral)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
@@ -1145,15 +1285,15 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
// Come up with a lazy way to do this.
if (File) {
- if (const Module *OwningModule = Map.Headers[File]) {
+ if (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) {
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
- << FileName << OwningModule->getFullModuleName();
+ << FileName << OwningModule.getModule()->getFullModuleName();
HadError = true;
} else if (Umbrella) {
const DirectoryEntry *UmbrellaDir = File->getDir();
- if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
+ if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
- << OwningModule->getFullModuleName();
+ << UmbrellaModule->getFullModuleName();
HadError = true;
} else {
// Record this umbrella header.
@@ -1161,11 +1301,11 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
}
} else {
// Record this header.
- Map.addHeader(ActiveModule, File);
+ Map.addHeader(ActiveModule, File, Exclude);
// If there is a builtin counterpart to this file, add it now.
if (BuiltinFile)
- Map.addHeader(ActiveModule, BuiltinFile);
+ Map.addHeader(ActiveModule, BuiltinFile, Exclude);
}
} else {
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
@@ -1274,32 +1414,52 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
-void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
+/// \brief Parse an inferried module declaration (wildcard modules).
+///
+/// module-declaration:
+/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]
+/// { inferred-module-member* }
+///
+/// inferred-module-member:
+/// 'export' '*'
+/// 'exclude' identifier
+void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
assert(Tok.is(MMToken::Star));
SourceLocation StarLoc = consumeToken();
bool Failed = false;
-
+
// Inferred modules must be submodules.
- if (!ActiveModule) {
+ if (!ActiveModule && !Framework) {
Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
Failed = true;
}
-
- // Inferred modules must have umbrella directories.
- if (!Failed && !ActiveModule->getUmbrellaDir()) {
- Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
- Failed = true;
- }
-
- // Check for redefinition of an inferred module.
- if (!Failed && ActiveModule->InferSubmodules) {
- Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
- if (ActiveModule->InferredSubmoduleLoc.isValid())
- Diags.Report(ActiveModule->InferredSubmoduleLoc,
- diag::note_mmap_prev_definition);
- Failed = true;
+
+ if (ActiveModule) {
+ // Inferred modules must have umbrella directories.
+ if (!Failed && !ActiveModule->getUmbrellaDir()) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
+ Failed = true;
+ }
+
+ // Check for redefinition of an inferred module.
+ if (!Failed && ActiveModule->InferSubmodules) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
+ if (ActiveModule->InferredSubmoduleLoc.isValid())
+ Diags.Report(ActiveModule->InferredSubmoduleLoc,
+ diag::note_mmap_prev_definition);
+ Failed = true;
+ }
+
+ // Check for the 'framework' keyword, which is not permitted here.
+ if (Framework) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule);
+ Framework = false;
+ }
+ } else if (Explicit) {
+ Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework);
+ Explicit = false;
}
-
+
// If there were any problems with this inferred submodule, skip its body.
if (Failed) {
if (Tok.is(MMToken::LBrace)) {
@@ -1311,12 +1471,22 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
HadError = true;
return;
}
-
- // Note that we have an inferred submodule.
- ActiveModule->InferSubmodules = true;
- ActiveModule->InferredSubmoduleLoc = StarLoc;
- ActiveModule->InferExplicitSubmodules = Explicit;
-
+
+ // Parse optional attributes.
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
+
+ if (ActiveModule) {
+ // Note that we have an inferred submodule.
+ ActiveModule->InferSubmodules = true;
+ ActiveModule->InferredSubmoduleLoc = StarLoc;
+ ActiveModule->InferExplicitSubmodules = Explicit;
+ } else {
+ // We'll be inferring framework modules for this directory.
+ Map.InferredDirectories[Directory].InferModules = true;
+ Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem;
+ }
+
// Parse the opening brace.
if (!Tok.is(MMToken::LBrace)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);
@@ -1333,8 +1503,35 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
case MMToken::RBrace:
Done = true;
break;
-
- case MMToken::ExportKeyword: {
+
+ case MMToken::ExcludeKeyword: {
+ if (ActiveModule) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != 0);
+ consumeToken();
+ break;
+ }
+
+ consumeToken();
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
+ break;
+ }
+
+ Map.InferredDirectories[Directory].ExcludedModules
+ .push_back(Tok.getString());
+ consumeToken();
+ break;
+ }
+
+ case MMToken::ExportKeyword:
+ if (!ActiveModule) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != 0);
+ consumeToken();
+ break;
+ }
+
consumeToken();
if (Tok.is(MMToken::Star))
ActiveModule->InferExportWildcard = true;
@@ -1343,14 +1540,14 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
diag::err_mmap_expected_export_wildcard);
consumeToken();
break;
- }
-
+
case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword:
case MMToken::HeaderKeyword:
case MMToken::UmbrellaKeyword:
default:
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_wildcard_member);
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != 0);
consumeToken();
break;
}
@@ -1365,6 +1562,66 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
}
}
+/// \brief Parse optional attributes.
+///
+/// attributes:
+/// attribute attributes
+/// attribute
+///
+/// attribute:
+/// [ identifier ]
+///
+/// \param Attrs Will be filled in with the parsed attributes.
+///
+/// \returns true if an error occurred, false otherwise.
+bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
+ bool HadError = false;
+
+ while (Tok.is(MMToken::LSquare)) {
+ // Consume the '['.
+ SourceLocation LSquareLoc = consumeToken();
+
+ // Check whether we have an attribute name here.
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
+ skipUntil(MMToken::RSquare);
+ if (Tok.is(MMToken::RSquare))
+ consumeToken();
+ HadError = true;
+ }
+
+ // Decode the attribute name.
+ AttributeKind Attribute
+ = llvm::StringSwitch<AttributeKind>(Tok.getString())
+ .Case("system", AT_system)
+ .Default(AT_unknown);
+ switch (Attribute) {
+ case AT_unknown:
+ Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
+ << Tok.getString();
+ break;
+
+ case AT_system:
+ Attrs.IsSystem = true;
+ break;
+ }
+ consumeToken();
+
+ // Consume the ']'.
+ if (!Tok.is(MMToken::RSquare)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
+ Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
+ skipUntil(MMToken::RSquare);
+ HadError = true;
+ }
+
+ if (Tok.is(MMToken::RSquare))
+ consumeToken();
+ }
+
+ return HadError;
+}
+
/// \brief If there is a specific header search directory due the presence
/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
@@ -1398,6 +1655,7 @@ bool ModuleMapParser::parseModuleMapFile() {
break;
case MMToken::Comma:
+ case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
@@ -1428,7 +1686,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
// Parse this module map file.
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
Diags->getClient()->BeginSourceFile(MMapLangOpts);
- ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir(),
+ ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(),
BuiltinIncludeDir);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 74b9cbc881ac..b7c1846e82be 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1296,7 +1296,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
case tok::string_literal:
Filename = getSpelling(FilenameTok, FilenameBuffer);
End = FilenameTok.getLocation();
- CharEnd = End.getLocWithOffset(Filename.size());
+ CharEnd = End.getLocWithOffset(FilenameTok.getLength());
break;
case tok::less:
@@ -1306,7 +1306,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (ConcatenateIncludeName(FilenameBuffer, End))
return; // Found <eod> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
- CharEnd = getLocForEndOfToken(End);
+ CharEnd = End.getLocWithOffset(1);
break;
default:
Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
@@ -1314,6 +1314,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
return;
}
+ CharSourceRange FilenameRange
+ = CharSourceRange::getCharRange(FilenameTok.getLocation(), CharEnd);
StringRef OriginalFilename = Filename;
bool isAngled =
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
@@ -1384,9 +1386,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
- // Notify the callback object that we've seen an inclusion directive.
- Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
- End, SearchPath, RelativePath);
+ if (!SuggestedModule) {
+ // Notify the callback object that we've seen an inclusion directive.
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
+ FilenameRange, File,
+ SearchPath, RelativePath,
+ /*ImportedModule=*/0);
+ }
}
if (File == 0) {
@@ -1480,10 +1486,28 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Module *Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
+ assert((Imported == 0 || Imported == SuggestedModule) &&
+ "the imported module is different than the suggested one");
// If this header isn't part of the module we're building, we're done.
- if (!BuildingImportedModule && Imported)
+ if (!BuildingImportedModule && Imported) {
+ if (Callbacks) {
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
+ FilenameRange, File,
+ SearchPath, RelativePath, Imported);
+ }
return;
+ }
+ }
+
+ if (Callbacks && SuggestedModule) {
+ // We didn't notify the callback object that we've seen an inclusion
+ // directive before. Now that we are parsing the include normally and not
+ // turning it to a module import, notify the callback object.
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
+ FilenameRange, File,
+ SearchPath, RelativePath,
+ /*ImportedModule=*/0);
}
// The #included file will be considered to be a system header if either it is
@@ -1849,7 +1873,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
MI->setDefinitionEndLoc(LastTok.getLocation());
// Finally, if this identifier already had a macro defined for it, verify that
- // the macro bodies are identical and free the old definition.
+ // the macro bodies are identical, and issue diagnostics if they are not.
if (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,
@@ -1870,7 +1894,6 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
}
if (OtherMI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(OtherMI->getDefinitionLoc());
- ReleaseMacroInfo(OtherMI);
}
setMacroInfo(MacroNameTok.getIdentifierInfo(), MI);
@@ -1921,9 +1944,20 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
if (MI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
- // Free macro definition.
- ReleaseMacroInfo(MI);
- setMacroInfo(MacroNameTok.getIdentifierInfo(), 0);
+ 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);
}
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 7cac63eb0f53..d5a88db470d8 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -178,7 +178,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// preprocessor keywords and it wasn't macro expanded, it turns
// into a simple 0, unless it is the C++ keyword "true", in which case it
// turns into "1".
- if (ValueLive)
+ if (ValueLive &&
+ II->getTokenID() != tok::kw_true &&
+ II->getTokenID() != tok::kw_false)
PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
Result.Val = II->getTokenID() == tok::kw_true;
Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
@@ -204,8 +206,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (NumberInvalid)
return true; // a diagnostic was already reported
- NumericLiteralParser Literal(Spelling.begin(), Spelling.end(),
- PeekTok.getLocation(), PP);
+ NumericLiteralParser Literal(Spelling, PeekTok.getLocation(), PP);
if (Literal.hadError)
return true; // a diagnostic was already reported.
@@ -219,10 +220,15 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (Literal.hasUDSuffix())
PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1;
- // long long is a C99 feature.
- if (!PP.getLangOpts().C99 && Literal.isLongLong)
- PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!PP.getLangOpts().C99 && Literal.isLongLong) {
+ if (PP.getLangOpts().CPlusPlus)
+ PP.Diag(PeekTok,
+ PP.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ PP.Diag(PeekTok, diag::ext_c99_longlong);
+ }
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index e824320cf732..d827f58a485f 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -157,15 +157,15 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
/// EnterMacro - Add a Macro to the top of the include stack and start lexing
/// tokens from it instead of the current buffer.
void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
- MacroArgs *Args) {
+ MacroInfo *Macro, MacroArgs *Args) {
PushIncludeMacroStack();
CurDirLookup = 0;
if (NumCachedTokenLexers == 0) {
- CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Args, *this));
+ CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Macro, Args, *this));
} else {
CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
- CurTokenLexer->Init(Tok, ILEnd, Args);
+ CurTokenLexer->Init(Tok, ILEnd, Macro, Args);
}
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index ebdb6446d167..eee4342e27ca 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -27,39 +27,138 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include <cstdio>
#include <ctime>
using namespace clang;
-MacroInfo *Preprocessor::getInfoForMacro(IdentifierInfo *II) const {
- assert(II->hasMacroDefinition() && "Identifier is not a macro!");
-
- llvm::DenseMap<IdentifierInfo*, MacroInfo*>::const_iterator Pos
- = Macros.find(II);
- if (Pos == Macros.end()) {
- // Load this macro from the external source.
- getExternalSource()->LoadMacroDefinition(II);
- Pos = Macros.find(II);
- }
+MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const {
+ assert(II->hadMacroDefinition() && "Identifier has not been not a macro!");
+
+ macro_iterator Pos = Macros.find(II);
assert(Pos != Macros.end() && "Identifier macro info is missing!");
return Pos->second;
}
/// setMacroInfo - Specify a macro for this identifier.
///
-void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI,
- bool LoadedFromAST) {
- if (MI) {
- Macros[II] = MI;
- II->setHasMacroDefinition(true);
- if (II->isFromAST() && !LoadedFromAST)
- II->setChangedSinceDeserialization();
- } else if (II->hasMacroDefinition()) {
- Macros.erase(II);
- II->setHasMacroDefinition(false);
- if (II->isFromAST() && !LoadedFromAST)
- II->setChangedSinceDeserialization();
+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())
+ 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();
}
/// RegisterBuiltinMacro - Register the specified identifier in the identifier
@@ -100,6 +199,20 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
+ // Modules.
+ if (LangOpts.Modules) {
+ Ident__building_module = RegisterBuiltinMacro(*this, "__building_module");
+
+ // __MODULE__
+ if (!LangOpts.CurrentModule.empty())
+ Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__");
+ else
+ Ident__MODULE__ = 0;
+ } else {
+ Ident__building_module = 0;
+ Ident__MODULE__ = 0;
+ }
+
// Microsoft Extensions.
if (LangOpts.MicrosoftExt)
Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
@@ -263,7 +376,23 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
}
}
-
+
+ // If the macro definition is ambiguous, complain.
+ if (MI->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)
+ << Identifier.getIdentifierInfo();
+ }
+ }
+ }
+
// If we started lexing a macro, enter the macro expansion body.
// If this macro expands to no tokens, don't bother to push it onto the
@@ -337,7 +466,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
// Start expanding the macro.
- EnterMacro(Identifier, ExpansionEnd, Args);
+ EnterMacro(Identifier, ExpansionEnd, MI, Args);
// Now that the macro is at the top of the include stack, ask the
// preprocessor to read the next token from it.
@@ -581,27 +710,27 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};
- char TmpBuffer[32];
-#ifdef LLVM_ON_WIN32
- sprintf(TmpBuffer, "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday,
- TM->tm_year+1900);
-#else
- snprintf(TmpBuffer, sizeof(TmpBuffer), "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday,
- TM->tm_year+1900);
-#endif
-
- Token TmpTok;
- TmpTok.startToken();
- PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok);
- DATELoc = TmpTok.getLocation();
-
-#ifdef LLVM_ON_WIN32
- sprintf(TmpBuffer, "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec);
-#else
- snprintf(TmpBuffer, sizeof(TmpBuffer), "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec);
-#endif
- PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok);
- TIMELoc = TmpTok.getLocation();
+ {
+ SmallString<32> TmpBuffer;
+ llvm::raw_svector_ostream TmpStream(TmpBuffer);
+ TmpStream << llvm::format("\"%s %2d %4d\"", Months[TM->tm_mon],
+ TM->tm_mday, TM->tm_year + 1900);
+ Token TmpTok;
+ TmpTok.startToken();
+ PP.CreateString(TmpStream.str(), TmpTok);
+ DATELoc = TmpTok.getLocation();
+ }
+
+ {
+ SmallString<32> TmpBuffer;
+ llvm::raw_svector_ostream TmpStream(TmpBuffer);
+ TmpStream << llvm::format("\"%02d:%02d:%02d\"",
+ TM->tm_hour, TM->tm_min, TM->tm_sec);
+ Token TmpTok;
+ TmpTok.startToken();
+ PP.CreateString(TmpStream.str(), TmpTok);
+ TIMELoc = TmpTok.getLocation();
+ }
}
@@ -616,7 +745,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.AddressSanitizer)
+ .Case("address_sanitizer", LangOpts.SanitizeAddress)
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
.Case("attribute_availability_with_message", true)
@@ -641,8 +770,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
- .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
- LangOpts.ObjCRuntimeHasWeak)
+ .Case("objc_arc_weak", LangOpts.ObjCARCWeak)
.Case("objc_default_synthesize_properties", LangOpts.ObjC2)
.Case("objc_fixed_enum", LangOpts.ObjC2)
.Case("objc_instancetype", LangOpts.ObjC2)
@@ -716,22 +844,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
// "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 &&
- PP.getIdentifierInfo("__is_empty")->getTokenID()
- != tok::identifier)
+ .Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_final", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
.Case("is_standard_layout", LangOpts.CPlusPlus)
- // __is_pod is available only if the horrible
- // "struct __is_pod" parsing hack hasn't been needed in this
- // translation unit. If it has, __is_pod reverts to a normal
- // identifier and __has_feature(is_pod) evaluates false.
- .Case("is_pod",
- LangOpts.CPlusPlus &&
- PP.getIdentifierInfo("__is_pod")->getTokenID()
- != tok::identifier)
+ .Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
@@ -807,22 +925,30 @@ static bool HasAttribute(const IdentifierInfo *II) {
static bool EvaluateHasIncludeCommon(Token &Tok,
IdentifierInfo *II, Preprocessor &PP,
const DirectoryLookup *LookupFrom) {
- SourceLocation LParenLoc;
+ // Save the location of the current token. If a '(' is later found, use
+ // that location. If no, use the end of this location instead.
+ SourceLocation LParenLoc = Tok.getLocation();
// Get '('.
PP.LexNonComment(Tok);
// Ensure we have a '('.
if (Tok.isNot(tok::l_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName();
- return false;
- }
-
- // Save '(' location for possible missing ')' message.
- LParenLoc = Tok.getLocation();
+ // No '(', use end of last token.
+ LParenLoc = PP.getLocForEndOfToken(LParenLoc);
+ PP.Diag(LParenLoc, diag::err_pp_missing_lparen) << II->getName();
+ // If the next token looks like a filename or the start of one,
+ // assume it is and process it as such.
+ if (!Tok.is(tok::angle_string_literal) && !Tok.is(tok::string_literal) &&
+ !Tok.is(tok::less))
+ return false;
+ } else {
+ // Save '(' location for possible missing ')' message.
+ LParenLoc = Tok.getLocation();
- // Get the file name.
- PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ // Get the file name.
+ PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ }
// Reserve a buffer to get the spelling.
SmallString<128> FilenameBuffer;
@@ -847,8 +973,11 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// This could be a <foo/bar.h> file coming from a macro expansion. In this
// case, glue the tokens together into FilenameBuffer and interpret those.
FilenameBuffer.push_back('<');
- if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc))
+ if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) {
+ // Let the caller know a <eod> was found by changing the Token kind.
+ Tok.setKind(tok::eod);
return false; // Found <eod> but no ">"? Diagnostic already emitted.
+ }
Filename = FilenameBuffer.str();
break;
default:
@@ -856,12 +985,15 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
return false;
}
+ SourceLocation FilenameLoc = Tok.getLocation();
+
// Get ')'.
PP.LexNonComment(Tok);
// Ensure we have a trailing ).
if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
+ PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_missing_rparen)
+ << II->getName();
PP.Diag(LParenLoc, diag::note_matching) << "(";
return false;
}
@@ -909,6 +1041,47 @@ static bool EvaluateHasIncludeNext(Token &Tok,
return EvaluateHasIncludeCommon(Tok, II, PP, Lookup);
}
+/// \brief Process __building_module(identifier) expression.
+/// \returns true if we are building the named module, false otherwise.
+static bool EvaluateBuildingModule(Token &Tok,
+ IdentifierInfo *II, Preprocessor &PP) {
+ // Get '('.
+ PP.LexNonComment(Tok);
+
+ // Ensure we have a '('.
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName();
+ return false;
+ }
+
+ // Save '(' location for possible missing ')' message.
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ // Get the module name.
+ PP.LexNonComment(Tok);
+
+ // Ensure that we have an identifier.
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected_id_building_module);
+ return false;
+ }
+
+ bool Result
+ = Tok.getIdentifierInfo()->getName() == PP.getLangOpts().CurrentModule;
+
+ // Get ')'.
+ PP.LexNonComment(Tok);
+
+ // Ensure we have a trailing ).
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
+ PP.Diag(LParenLoc, diag::note_matching) << "(";
+ return false;
+ }
+
+ return Result;
+}
+
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
/// as a builtin macro, handle it and return the next token as 'Tok'.
void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
@@ -1093,7 +1266,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
else
Value = EvaluateHasIncludeNext(Tok, II, *this);
OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ if (Tok.is(tok::r_paren))
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_warning) {
// The argument should be a parenthesized string literal.
// The argument to these builtins should be a parenthesized identifier.
@@ -1164,11 +1338,22 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
OS << (int)Value;
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
+ // currently building.
+ OS << (int)EvaluateBuildingModule(Tok, II, *this);
+ Tok.setKind(tok::numeric_constant);
+ } else if (II == Ident__MODULE__) {
+ // The current module as an identifier.
+ OS << getLangOpts().CurrentModule;
+ IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule);
+ Tok.setIdentifierInfo(ModuleII);
+ Tok.setKind(ModuleII->getTokenID());
} else {
llvm_unreachable("Unknown identifier!");
}
- CreateString(OS.str().data(), OS.str().size(), Tok,
- Tok.getLocation(), Tok.getLocation());
+ CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation());
}
void Preprocessor::markMacroAsUsed(MacroInfo *MI) {
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index 67738e907516..b1671721b630 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -198,12 +198,11 @@ bool PTHLexer::SkipBlock() {
assert(LastHashTokPtr && "No known '#' token.");
const unsigned char* HashEntryI = 0;
- uint32_t Offset;
uint32_t TableIdx;
do {
// Read the token offset from the side-table.
- Offset = ReadLE32(CurPPCondPtr);
+ uint32_t Offset = ReadLE32(CurPPCondPtr);
// Read the target table index from the side-table.
TableIdx = ReadLE32(CurPPCondPtr);
@@ -223,13 +222,11 @@ bool PTHLexer::SkipBlock() {
PPCond + TableIdx*(sizeof(uint32_t)*2);
assert(NextPPCondPtr >= CurPPCondPtr);
// Read where we should jump to.
- uint32_t TmpOffset = ReadLE32(NextPPCondPtr);
- const unsigned char* HashEntryJ = TokBuf + TmpOffset;
+ const unsigned char* HashEntryJ = TokBuf + ReadLE32(NextPPCondPtr);
if (HashEntryJ <= LastHashTokPtr) {
// Jump directly to the next entry in the side table.
HashEntryI = HashEntryJ;
- Offset = TmpOffset;
TableIdx = ReadLE32(NextPPCondPtr);
CurPPCondPtr = NextPPCondPtr;
}
@@ -448,8 +445,8 @@ PTHManager *PTHManager::Create(const std::string &file,
// Get the buffer ranges and check if there are at least three 32-bit
// words at the end of the file.
- const unsigned char *BufBeg = (unsigned char*)File->getBufferStart();
- const unsigned char *BufEnd = (unsigned char*)File->getBufferEnd();
+ const unsigned char *BufBeg = (const unsigned char*)File->getBufferStart();
+ const unsigned char *BufEnd = (const unsigned char*)File->getBufferEnd();
// Check the prologue of the file.
if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 4 + 4) ||
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index c9cc4adf4019..e7e6c3705376 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -43,7 +43,6 @@ void EmptyPragmaHandler::HandlePragma(Preprocessor &PP,
// PragmaNamespace Implementation.
//===----------------------------------------------------------------------===//
-
PragmaNamespace::~PragmaNamespace() {
for (llvm::StringMap<PragmaHandler*>::iterator
I = Handlers.begin(), E = Handlers.end(); I != E; ++I)
@@ -251,7 +250,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// where we can lex it.
Token TmpTok;
TmpTok.startToken();
- CreateString(&StrVal[0], StrVal.size(), TmpTok);
+ CreateString(StrVal, TmpTok);
SourceLocation TokLoc = TmpTok.getLocation();
// Make and enter a lexer object so that we lex and expand the tokens just
@@ -683,7 +682,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
Token MacroTok;
MacroTok.startToken();
MacroTok.setKind(tok::raw_identifier);
- CreateString(&StrVal[1], StrVal.size() - 2, MacroTok);
+ CreateString(StringRef(&StrVal[1], StrVal.size() - 2), MacroTok);
// Get the IdentifierInfo of MacroToPushTok.
return LookUpIdentifierInfo(MacroTok);
@@ -733,19 +732,22 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> >::iterator iter =
PragmaPushMacroInfo.find(IdentInfo);
if (iter != PragmaPushMacroInfo.end()) {
- // Release the MacroInfo currently associated with IdentInfo.
- MacroInfo *CurrentMI = getMacroInfo(IdentInfo);
- if (CurrentMI) {
+ // Forget the MacroInfo currently associated with IdentInfo.
+ if (MacroInfo *CurrentMI = getMacroInfo(IdentInfo)) {
if (CurrentMI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc());
- ReleaseMacroInfo(CurrentMI);
+ UndefineMacro(IdentInfo, CurrentMI, MessageLoc);
}
// Get the MacroInfo we want to reinstall.
MacroInfo *MacroToReInstall = iter->second.back();
- // Reinstall the previously pushed macro.
- setMacroInfo(IdentInfo, MacroToReInstall);
+ if (MacroToReInstall) {
+ // Reinstall the previously pushed macro.
+ setMacroInfo(IdentInfo, MacroToReInstall);
+ } else if (IdentInfo->hasMacroDefinition()) {
+ clearMacroInfo(IdentInfo);
+ }
// Pop PragmaPushMacroInfo stack.
iter->second.pop_back();
@@ -1009,7 +1011,7 @@ struct PragmaDebugHandler : public PragmaHandler {
if (II->isStr("assert")) {
llvm_unreachable("This is an assertion!");
} else if (II->isStr("crash")) {
- *(volatile int*) 0x11 = 0;
+ LLVM_BUILTIN_TRAP;
} else if (II->isStr("parser_crash")) {
Token Crasher;
Crasher.setKind(tok::annot_pragma_parser_crash);
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index dfdeba3f9cd9..01f3665e76bd 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -25,10 +25,11 @@ ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
InclusionKind Kind,
StringRef FileName,
- bool InQuotes, const FileEntry *File,
+ bool InQuotes, bool ImportedModule,
+ const FileEntry *File,
SourceRange Range)
: PreprocessingDirective(InclusionDirectiveKind, Range),
- InQuotes(InQuotes), Kind(Kind), File(File)
+ InQuotes(InQuotes), Kind(Kind), ImportedModule(ImportedModule), File(File)
{
char *Memory
= (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>());
@@ -59,8 +60,7 @@ PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
iterator(this, CachedRangeQuery.Result.second));
}
- std::pair<PPEntityID, PPEntityID>
- Res = getPreprocessedEntitiesInRangeSlow(Range);
+ std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range);
CachedRangeQuery.Range = Range;
CachedRangeQuery.Result = Res;
@@ -95,12 +95,12 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
if (FID.isInvalid())
return false;
- PPEntityID PPID = PPEI.Position;
- if (PPID < 0) {
- assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
+ int Pos = PPEI.Position;
+ if (Pos < 0) {
+ assert(unsigned(-Pos-1) < LoadedPreprocessedEntities.size() &&
"Out-of bounds loaded preprocessed entity");
assert(ExternalSource && "No external source to load from");
- unsigned LoadedIndex = LoadedPreprocessedEntities.size()+PPID;
+ unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;
if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr);
@@ -118,15 +118,15 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
FID, SourceMgr);
}
- assert(unsigned(PPID) < PreprocessedEntities.size() &&
+ assert(unsigned(Pos) < PreprocessedEntities.size() &&
"Out-of bounds local preprocessed entity");
- return isPreprocessedEntityIfInFileID(PreprocessedEntities[PPID],
+ return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos],
FID, SourceMgr);
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
/// that source range \arg R encompasses.
-std::pair<PreprocessingRecord::PPEntityID, PreprocessingRecord::PPEntityID>
+std::pair<int, int>
PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) {
assert(Range.isValid());
assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
@@ -319,14 +319,19 @@ void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
/// \brief Retrieve the preprocessed entity at the given ID.
PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
- if (PPID < 0) {
- assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
+ if (PPID.ID < 0) {
+ unsigned Index = -PPID.ID - 1;
+ assert(Index < LoadedPreprocessedEntities.size() &&
"Out-of bounds loaded preprocessed entity");
- return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID);
+ return getLoadedPreprocessedEntity(Index);
}
- assert(unsigned(PPID) < PreprocessedEntities.size() &&
+
+ if (PPID.ID == 0)
+ return 0;
+ unsigned Index = PPID.ID - 1;
+ assert(Index < PreprocessedEntities.size() &&
"Out-of bounds local preprocessed entity");
- return PreprocessedEntities[PPID];
+ return PreprocessedEntities[Index];
}
/// \brief Retrieve the loaded preprocessed entity at the given index.
@@ -389,10 +394,11 @@ void PreprocessingRecord::InclusionDirective(
const clang::Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- clang::SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
@@ -415,9 +421,19 @@ void PreprocessingRecord::InclusionDirective(
default:
llvm_unreachable("Unknown include directive kind");
}
-
+
+ SourceLocation EndLoc;
+ if (!IsAngled) {
+ EndLoc = FilenameRange.getBegin();
+ } else {
+ EndLoc = FilenameRange.getEnd();
+ if (FilenameRange.isCharRange())
+ EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects
+ // a token range.
+ }
clang::InclusionDirective *ID
- = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
+ = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
+ (bool)Imported,
File, SourceRange(HashLoc, EndLoc));
addPreprocessedEntity(ID);
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 614530cf387f..3b070ce049db 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -26,6 +26,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "MacroArgs.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
@@ -49,21 +50,25 @@ using namespace clang;
//===----------------------------------------------------------------------===//
ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
-Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
+PPMutationListener::~PPMutationListener() { }
+
+Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
+ DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target, SourceManager &SM,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup* IILookup,
bool OwnsHeaders,
bool DelayInitialization,
bool IncrProcessing)
- : Diags(&diags), LangOpts(opts), Target(target),FileMgr(Headers.getFileMgr()),
+ : 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)
+ CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0),
+ MacroArgCache(0), Record(0), MIChainHead(0), MICache(0)
{
OwnsHeaderSearch = OwnsHeaders;
@@ -285,6 +290,39 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const {
return Macros.end();
}
+/// \brief Compares macro tokens with a specified token value sequence.
+static bool MacroDefinitionEquals(const MacroInfo *MI,
+ llvm::ArrayRef<TokenValue> Tokens) {
+ return Tokens.size() == MI->getNumTokens() &&
+ std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin());
+}
+
+StringRef Preprocessor::getLastMacroWithSpelling(
+ SourceLocation Loc,
+ ArrayRef<TokenValue> Tokens) const {
+ SourceLocation BestLocation;
+ StringRef BestSpelling;
+ for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end();
+ I != E; ++I) {
+ if (!I->second->isObjectLike())
+ continue;
+ const MacroInfo *MI = I->second->findDefinitionAtLoc(Loc, SourceMgr);
+ if (!MI)
+ continue;
+ if (!MacroDefinitionEquals(MI, Tokens))
+ continue;
+ SourceLocation Location = I->second->getDefinitionLoc();
+ // Choose the macro defined latest.
+ if (BestLocation.isInvalid() ||
+ (Location.isValid() &&
+ SourceMgr.isBeforeInTranslationUnit(BestLocation, Location))) {
+ BestLocation = Location;
+ BestSpelling = I->first->getName();
+ }
+ }
+ return BestSpelling;
+}
+
void Preprocessor::recomputeCurLexerKind() {
if (CurLexer)
CurLexerKind = CLK_Lexer;
@@ -378,17 +416,17 @@ StringRef Preprocessor::getSpelling(const Token &Tok,
/// CreateString - Plop the specified string into a scratch buffer and return a
/// location for it. If specified, the source location provides a source
/// location for the token.
-void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
+void Preprocessor::CreateString(StringRef Str, Token &Tok,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd) {
- Tok.setLength(Len);
+ Tok.setLength(Str.size());
const char *DestPtr;
- SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr);
+ SourceLocation Loc = ScratchBuf->getToken(Str.data(), Str.size(), DestPtr);
if (ExpansionLocStart.isValid())
Loc = SourceMgr.createExpansionLoc(Loc, ExpansionLocStart,
- ExpansionLocEnd, Len);
+ ExpansionLocEnd, Str.size());
Tok.setLocation(Loc);
// If this is a raw identifier or a literal token, set the pointer data.
@@ -641,10 +679,14 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
}
// If we have a non-empty module path, load the named module.
- if (!ModuleImportPath.empty())
- (void)TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath,
- Module::MacrosVisible,
- /*IsIncludeDirective=*/false);
+ if (!ModuleImportPath.empty()) {
+ Module *Imported = TheModuleLoader.loadModule(ModuleImportLoc,
+ ModuleImportPath,
+ Module::MacrosVisible,
+ /*IsIncludeDirective=*/false);
+ if (Callbacks)
+ Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported);
+ }
}
void Preprocessor::addCommentHandler(CommentHandler *Handler) {
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index ade40dad77d9..59b747814a51 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -23,12 +23,13 @@ using namespace clang;
/// Create a TokenLexer for the specified macro with the specified actual
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
-void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) {
+void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI,
+ MacroArgs *Actuals) {
// If the client is reusing a TokenLexer, make sure to free any memory
// associated with it.
destroy();
- Macro = PP.getMacroInfo(Tok.getIdentifierInfo());
+ Macro = MI;
ActualArgs = Actuals;
CurToken = 0;
@@ -118,6 +119,55 @@ void TokenLexer::destroy() {
if (ActualArgs) ActualArgs->destroy(PP);
}
+/// Remove comma ahead of __VA_ARGS__, if present, according to compiler dialect
+/// settings. Returns true if the comma is removed.
+static bool MaybeRemoveCommaBeforeVaArgs(SmallVector<Token, 128> &ResultToks,
+ bool &NextTokGetsSpace,
+ bool HasPasteOperator,
+ MacroInfo *Macro, unsigned MacroArgNo,
+ Preprocessor &PP) {
+ // Is the macro argument __VA_ARGS__?
+ if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1)
+ return false;
+
+ // In Microsoft-compatibility mode, a comma is removed in the expansion
+ // of " ... , __VA_ARGS__ " if __VA_ARGS__ is empty. This extension is
+ // not supported by gcc.
+ if (!HasPasteOperator && !PP.getLangOpts().MicrosoftMode)
+ return false;
+
+ // GCC removes the comma in the expansion of " ... , ## __VA_ARGS__ " if
+ // __VA_ARGS__ is empty, but not in strict C99 mode where there are no
+ // named arguments, where it remains. In all other modes, including C99
+ // with GNU extensions, it is removed regardless of named arguments.
+ // Microsoft also appears to support this extension, unofficially.
+ if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode
+ && Macro->getNumArgs() < 2)
+ return false;
+
+ // Is a comma available to be removed?
+ if (ResultToks.empty() || !ResultToks.back().is(tok::comma))
+ return false;
+
+ // Issue an extension diagnostic for the paste operator.
+ if (HasPasteOperator)
+ PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
+
+ // Remove the comma.
+ ResultToks.pop_back();
+
+ // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
+ // then removal of the comma should produce a placemarker token (in C99
+ // terms) which we model by popping off the previous ##, giving us a plain
+ // "X" when __VA_ARGS__ is empty.
+ if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash))
+ ResultToks.pop_back();
+
+ // Never add a space, even if the comma, ##, or arg had a space.
+ NextTokGetsSpace = false;
+ return true;
+}
+
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
void TokenLexer::ExpandFunctionArguments() {
@@ -198,6 +248,14 @@ void TokenLexer::ExpandFunctionArguments() {
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
+ // In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
+ // are no trailing commas if __VA_ARGS__ is empty.
+ if (!PasteBefore && ActualArgs->isVarargsElidedUse() &&
+ MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+ /*HasPasteOperator=*/false,
+ Macro, ArgNo, PP))
+ continue;
+
// If it is not the LHS/RHS of a ## operator, we must pre-expand the
// argument and substitute the expanded tokens into the result. This is
// C99 6.10.3.1p1.
@@ -320,23 +378,13 @@ void TokenLexer::ExpandFunctionArguments() {
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
// and if the macro had at least one real argument, and if the token before
- // the ## was a comma, remove the comma.
- if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__
- ActualArgs->isVarargsElidedUse() && // Argument elided.
- !ResultToks.empty() && ResultToks.back().is(tok::comma)) {
- // Never add a space, even if the comma, ##, or arg had a space.
- NextTokGetsSpace = false;
- // Remove the paste operator, report use of the extension.
- PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
- ResultToks.pop_back();
-
- // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
- // then removal of the comma should produce a placemarker token (in C99
- // terms) which we model by popping off the previous ##, giving us a plain
- // "X" when __VA_ARGS__ is empty.
- if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash))
- ResultToks.pop_back();
- }
+ // the ## was a comma, remove the comma. This is a GCC extension which is
+ // disabled when using -std=c99.
+ if (ActualArgs->isVarargsElidedUse())
+ MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+ /*HasPasteOperator=*/true,
+ Macro, ArgNo, PP);
+
continue;
}
@@ -494,7 +542,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Claim that the tmp token is a string_literal so that we can get the
// character pointer back from CreateString in getLiteralData().
ResultTokTmp.setKind(tok::string_literal);
- PP.CreateString(&Buffer[0], Buffer.size(), ResultTokTmp);
+ PP.CreateString(Buffer, ResultTokTmp);
SourceLocation ResultTokLoc = ResultTokTmp.getLocation();
ResultTokStrPtr = ResultTokTmp.getLiteralData();
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index bd4f85952120..7d68e1f37e40 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -78,7 +78,6 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
S.getPreprocessor().EnterMainSourceFile();
P.Initialize();
- S.Initialize();
// C11 6.9p1 says translation units must have at least one top-level
// declaration. C++ doesn't have this restriction. We also don't want to
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index abce27c3f820..9c5c0597eee1 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -34,7 +34,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
Tok.is(tok::equal)) &&
"Current token not a '{', ':', '=', or 'try'!");
- MultiTemplateParamsArg TemplateParams(Actions,
+ MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
@@ -42,10 +42,10 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
D.setFunctionDefinitionKind(DefinitionKind);
if (D.getDeclSpec().isFriendSpecified())
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
- move(TemplateParams));
+ TemplateParams);
else {
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
- move(TemplateParams), 0,
+ TemplateParams, 0,
VS, ICIS_NoInit);
if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index cb865cc9c2ba..f73907a7c409 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -143,7 +143,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// Attributes in a class are parsed at the end of the class, along
// with other late-parsed declarations.
- if (!ClassStack.empty())
+ if (!ClassStack.empty() && !LateAttrs->parseSoon())
getCurrentClass().LateParsedDeclarations.push_back(LA);
// consume everything up to and including the matching right parens
@@ -154,7 +154,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
Eof.setLocation(Tok.getLocation());
LA->Toks.push_back(Eof);
} else {
- ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc);
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc,
+ 0, SourceLocation(), AttributeList::AS_GNU);
}
} else {
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
@@ -173,11 +174,15 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
-/// Parse the arguments to a parameterized GNU attribute
+/// Parse the arguments to a parameterized GNU attribute or
+/// a C++11 attribute in "gnu" namespace.
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
@@ -236,7 +241,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
break;
}
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
if (!BuiltinType &&
(ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
@@ -277,10 +282,11 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation RParen = Tok.getLocation();
if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
AttributeList *attr =
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
- ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(),
- AttributeList::AS_GNU);
+ 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);
}
@@ -851,10 +857,6 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) {
Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
Class.TagOrTemplate);
if (!Class.LateParsedDeclarations.empty()) {
- // Allow 'this' within late-parsed attributes.
- Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate,
- /*TypeQuals=*/0);
-
for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){
Class.LateParsedDeclarations[i]->ParseLexedAttributes();
}
@@ -869,6 +871,8 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) {
/// \brief Parse all attributes in LAs, and attach them to Decl D.
void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
bool EnterScope, bool OnDefinition) {
+ assert(LAs.parseSoon() &&
+ "Attribute list should be marked for immediate parsing.");
for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) {
if (D)
LAs[i]->addDecl(D);
@@ -904,34 +908,45 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
ParsedAttributes Attrs(AttrFactory);
SourceLocation endLoc;
- if (LA.Decls.size() == 1) {
+ if (LA.Decls.size() > 0) {
Decl *D = LA.Decls[0];
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
- // If the Decl is templatized, add template parameters to scope.
- bool HasTemplateScope = EnterScope && D->isTemplateDecl();
- ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
- if (HasTemplateScope)
- Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
-
- // If the Decl is on a function, add function parameters to the scope.
- bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate();
- ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope);
- if (HasFunctionScope)
- Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
-
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
-
- if (HasFunctionScope) {
- Actions.ActOnExitFunctionContext();
- FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
- }
- if (HasTemplateScope) {
- TempScope.Exit();
+ // Allow 'this' within late-parsed attributes.
+ Sema::CXXThisScopeRAII ThisScope(Actions, RD,
+ /*TypeQuals=*/0,
+ ND && RD && ND->isCXXInstanceMember());
+
+ if (LA.Decls.size() == 1) {
+ // If the Decl is templatized, add template parameters to scope.
+ bool HasTemplateScope = EnterScope && D->isTemplateDecl();
+ ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
+
+ // If the Decl is on a function, add function parameters to the scope.
+ bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate();
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunScope);
+ if (HasFunScope)
+ Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
+
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
+ 0, SourceLocation(), AttributeList::AS_GNU);
+
+ if (HasFunScope) {
+ Actions.ActOnExitFunctionContext();
+ FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
+ }
+ if (HasTemplateScope) {
+ TempScope.Exit();
+ }
+ } else {
+ // If there are multiple decls, then the decl cannot be within the
+ // function scope.
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
+ 0, SourceLocation(), AttributeList::AS_GNU);
}
- } else if (LA.Decls.size() > 0) {
- // If there are multiple decls, then the decl cannot be within the
- // function scope.
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
} else {
Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
}
@@ -998,7 +1013,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
bool ArgExprsOk = true;
// now parse the list of expressions
@@ -1018,7 +1033,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
// Match the ')'.
if (ArgExprsOk && !T.consumeClose()) {
Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
- ArgExprs.take(), ArgExprs.size(), AttributeList::AS_GNU);
+ ArgExprs.data(), ArgExprs.size(), AttributeList::AS_GNU);
}
if (EndLoc)
*EndLoc = T.getCloseLocation();
@@ -1127,6 +1142,18 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
<< attrs.Range;
}
+void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) {
+ AttributeList *AttrList = attrs.getList();
+ while (AttrList) {
+ if (AttrList->isCXX0XAttribute()) {
+ Diag(AttrList->getLoc(), diag::warn_attribute_no_decl)
+ << AttrList->getName();
+ AttrList->setInvalid();
+ }
+ AttrList = AttrList->getNext();
+ }
+}
+
/// ParseDeclaration - Parse a full 'declaration', which consists of
/// declaration-specifiers, some number of declarators, and a semicolon.
/// 'Context' should be a Declarator::TheContext value. This returns the
@@ -1400,7 +1427,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Save late-parsed attributes for now; they need to be parsed in the
// appropriate function scope after the function Decl has been constructed.
- LateParsedAttrList LateParsedAttrs;
+ // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
+ LateParsedAttrList LateParsedAttrs(true);
if (D.isFunctionDeclarator())
MaybeParseGNUAttributes(D, &LateParsedAttrs);
@@ -1587,9 +1615,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
case ParsedTemplateInfo::Template:
case ParsedTemplateInfo::ExplicitSpecialization:
ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(),
- MultiTemplateParamsArg(Actions,
- TemplateInfo.TemplateParams->data(),
- TemplateInfo.TemplateParams->size()),
+ *TemplateInfo.TemplateParams,
D);
break;
@@ -1660,7 +1686,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector Exprs(Actions);
+ ExprVector Exprs;
CommaLocsTy CommaLocs;
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
@@ -1669,6 +1695,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
if (ParseExpressionList(Exprs, CommaLocs)) {
+ Actions.ActOnInitializerError(ThisDecl);
SkipUntil(tok::r_paren);
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
@@ -1689,7 +1716,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
T.getCloseLocation(),
- move_arg(Exprs));
+ Exprs);
Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
/*DirectInit=*/true, TypeContainsAuto);
}
@@ -1872,6 +1899,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break;
case DeclSpec::TST_struct:
TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break;
+ case DeclSpec::TST_interface:
+ TagName="__interface"; FixitTagName = "__interface ";
+ TagKind=tok::kw___interface;break;
case DeclSpec::TST_class:
TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break;
}
@@ -2069,13 +2099,13 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
return;
}
- ExprVector ArgExprs(Actions);
+ 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.take(), 1,
+ 0, T.getOpenLocation(), ArgExprs.data(), 1,
AttributeList::AS_GNU);
}
@@ -2130,8 +2160,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DoneWithDeclSpec:
if (!AttrsLastTime)
ProhibitAttributes(attrs);
- else
+ else {
+ // Reject C++11 attributes that appertain to decl specifiers as
+ // we don't support any C++11 attributes that appertain to decl
+ // specifiers. This also conforms to what g++ 4.8 is doing.
+ ProhibitCXX11Attributes(attrs);
+
DS.takeAttributesFrom(attrs);
+ }
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
@@ -2271,6 +2307,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, T);
+ if (isInvalid)
+ break;
}
else
DS.SetTypeSpecError();
@@ -2476,12 +2514,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___forceinline: {
isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
- SourceLocation AttrNameLoc = ConsumeToken();
+ SourceLocation AttrNameLoc = Tok.getLocation();
// FIXME: This does not work correctly if it is set to be a declspec
// attribute, and a GNU attribute is simply incorrect.
DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
SourceLocation(), 0, 0, AttributeList::AS_GNU);
- continue;
+ break;
}
case tok::kw___ptr64:
@@ -2706,6 +2744,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// class-specifier:
case tok::kw_class:
case tok::kw_struct:
+ case tok::kw___interface:
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
@@ -2723,15 +2762,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/true);
+ getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/true);
+ getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/true);
+ getLangOpts());
break;
// C++ typename-specifier:
@@ -3165,6 +3204,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// anything that's a simple-type-specifier followed by '(' as an
// expression. This suffices because function types are not valid
// underlying types anyway.
+ EnterExpressionEvaluationContext Unevaluated(Actions,
+ Sema::ConstantEvaluated);
TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
// If the next token starts an expression, we know we're parsing a
// bit-field. This is the common case.
@@ -3213,11 +3254,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SourceRange Range;
BaseType = ParseTypeName(&Range);
- if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2)
- Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type)
- << Range;
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus0x) {
Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
+ } else if (!getLangOpts().ObjC2) {
+ if (getLangOpts().CPlusPlus)
+ Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type) << Range;
+ else
+ Diag(StartLoc, diag::ext_c_enum_fixed_underlying_type) << Range;
+ }
}
}
@@ -3526,6 +3570,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
+ case tok::kw___interface:
case tok::kw_union:
// enum-specifier
case tok::kw_enum:
@@ -3597,6 +3642,7 @@ bool Parser::isTypeSpecifierQualifier() {
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
+ case tok::kw___interface:
case tok::kw_union:
// enum-specifier
case tok::kw_enum:
@@ -3735,6 +3781,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_class:
case tok::kw_struct:
case tok::kw_union:
+ case tok::kw___interface:
// enum-specifier
case tok::kw_enum:
@@ -3748,6 +3795,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_virtual:
case tok::kw_explicit:
+ // friend keyword.
+ case tok::kw_friend:
+
// static_assert-declaration
case tok::kw__Static_assert:
@@ -3756,11 +3806,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// GNU attributes.
case tok::kw___attribute:
- return true;
- // C++0x decltype.
+ // C++11 decltype and constexpr.
case tok::annot_decltype:
- return true;
+ case tok::kw_constexpr:
// C11 _Atomic()
case tok::kw__Atomic:
@@ -3925,15 +3974,15 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/false);
+ getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/false);
+ getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/false);
+ getLangOpts());
break;
// OpenCL qualifiers:
@@ -4344,7 +4393,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetIdentifier(0, Tok.getLocation());
} else {
if (Tok.getKind() == tok::annot_pragma_parser_crash)
- *(volatile int*) 0x11 = 0;
+ LLVM_BUILTIN_TRAP;
if (D.getContext() == Declarator::MemberContext)
Diag(Tok, diag::err_expected_member_name_or_semi)
<< D.getDeclSpec().getSourceRange();
@@ -4374,9 +4423,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// In such a case, check if we actually have a function declarator; if it
// is not, the declarator has been fully parsed.
bool IsAmbiguous = false;
- if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit() &&
- !isCXXFunctionDeclarator(&IsAmbiguous))
- break;
+ if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ // The name of the declarator, if any, is tentatively declared within
+ // a possible direct initializer.
+ TentativelyDeclaredIdentifiers.push_back(D.getIdentifier());
+ bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous);
+ TentativelyDeclaredIdentifiers.pop_back();
+ if (!IsFunctionDecl)
+ break;
+ }
ParsedAttributes attrs(AttrFactory);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -4553,7 +4608,14 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
Actions.ActOnStartFunctionDeclarator();
- SourceLocation EndLoc;
+ /* LocalEndLoc is the end location for the local FunctionTypeLoc.
+ EndLoc is the end location for the function declarator.
+ They differ for trailing return types. */
+ SourceLocation StartLoc, LocalEndLoc, EndLoc;
+ SourceLocation LParenLoc, RParenLoc;
+ LParenLoc = Tracker.getOpenLocation();
+ StartLoc = LParenLoc;
+
if (isFunctionDeclaratorIdentifierList()) {
if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -4561,7 +4623,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ParseFunctionDeclaratorIdentifierList(D, ParamInfo);
Tracker.consumeClose();
- EndLoc = Tracker.getCloseLocation();
+ RParenLoc = Tracker.getCloseLocation();
+ LocalEndLoc = RParenLoc;
+ EndLoc = RParenLoc;
} else {
if (Tok.isNot(tok::r_paren))
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
@@ -4572,7 +4636,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// If we have the closing ')', eat it.
Tracker.consumeClose();
- EndLoc = Tracker.getCloseLocation();
+ RParenLoc = Tracker.getCloseLocation();
+ LocalEndLoc = RParenLoc;
+ EndLoc = RParenLoc;
if (getLangOpts().CPlusPlus) {
// FIXME: Accept these components in any order, and produce fixits to
@@ -4628,21 +4694,25 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
MaybeParseCXX0XAttributes(FnAttrs);
// Parse trailing-return-type[opt].
+ LocalEndLoc = EndLoc;
if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
+ if (D.getDeclSpec().getTypeSpecType() == TST_auto)
+ StartLoc = D.getDeclSpec().getTypeSpecTypeLoc();
+ LocalEndLoc = Tok.getLocation();
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(Range);
- if (Range.getEnd().isValid())
- EndLoc = Range.getEnd();
+ EndLoc = Range.getEnd();
}
}
}
// Remember that we parsed a function type, and remember the attributes.
D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
- /*isVariadic=*/EllipsisLoc.isValid(),
- IsAmbiguous, EllipsisLoc,
+ IsAmbiguous,
+ LParenLoc,
ParamInfo.data(), ParamInfo.size(),
+ EllipsisLoc, RParenLoc,
DS.getTypeQualifiers(),
RefQualifierIsLValueRef,
RefQualifierLoc, ConstQualifierLoc,
@@ -4654,8 +4724,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
- Tracker.getOpenLocation(),
- EndLoc, D,
+ StartLoc, LocalEndLoc, D,
TrailingReturnType),
FnAttrs, EndLoc);
@@ -5058,7 +5127,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const bool hasParens = Tok.is(tok::l_paren);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
bool isCastExpr;
ParsedType CastTy;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 3dc96cf0d294..4cb14e24f48f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
@@ -87,6 +88,12 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
if (Tok.is(tok::equal)) {
+ if (Ident == 0) {
+ Diag(Tok, diag::err_expected_ident);
+ // Skip to end of the definition and eat the ';'.
+ SkipUntil(tok::semi);
+ return 0;
+ }
if (!attrs.empty())
Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
if (InlineLoc.isValid())
@@ -581,7 +588,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
if (IsAliasDecl) {
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
- MultiTemplateParamsArg TemplateParamsArg(Actions,
+ MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
// FIXME: Propagate attributes.
@@ -616,12 +623,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen);
+ SkipMalformedDecl();
return 0;
}
ExprResult AssertExpr(ParseConstantExpression());
if (AssertExpr.isInvalid()) {
- SkipUntil(tok::semi);
+ SkipMalformedDecl();
return 0;
}
@@ -630,13 +638,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (!isTokenStringLiteral()) {
Diag(Tok, diag::err_expected_string_literal);
- SkipUntil(tok::semi);
+ SkipMalformedDecl();
return 0;
}
ExprResult AssertMessage(ParseStringLiteralExpression());
if (AssertMessage.isInvalid()) {
- SkipUntil(tok::semi);
+ SkipMalformedDecl();
return 0;
}
@@ -694,9 +702,22 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
0, /*IsDecltype=*/true);
Result = ParseExpression();
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
DS.SetTypeSpecError();
- return StartLoc;
+ if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) {
+ EndLoc = ConsumeParen();
+ } else {
+ assert(Tok.is(tok::semi));
+ if (PP.isBacktrackEnabled()) {
+ // Backtrack to get the location of the last token before the semi.
+ PP.RevertCachedTokens(2);
+ ConsumeToken(); // the semi.
+ EndLoc = ConsumeAnyToken();
+ assert(Tok.is(tok::semi));
+ } else {
+ EndLoc = Tok.getLocation();
+ }
+ }
+ return EndLoc;
}
// Match the ')'
@@ -1034,6 +1055,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
+ else if (TagTokKind == tok::kw___interface)
+ TagType = DeclSpec::TST_interface;
else if (TagTokKind == tok::kw_class)
TagType = DeclSpec::TST_class;
else {
@@ -1151,7 +1174,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
<< (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
<< (TagType == DeclSpec::TST_class? 0
: TagType == DeclSpec::TST_struct? 1
- : 2)
+ : TagType == DeclSpec::TST_interface? 2
+ : 3)
<< Name
<< SourceRange(LAngleLoc, RAngleLoc);
@@ -1243,8 +1267,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.isNot(tok::semi)) {
// A semicolon was missing after this declaration. Diagnose and recover.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- TagType == DeclSpec::TST_class ? "class" :
- TagType == DeclSpec::TST_struct ? "struct" : "union");
+ DeclSpec::getSpecifierName(TagType));
PP.EnterToken(Tok);
Tok.setKind(tok::semi);
}
@@ -1279,8 +1302,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
@@ -1362,7 +1384,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateArgsPtr,
TemplateId->RAngleLoc,
attrs.getList(),
- MultiTemplateParamsArg(Actions,
+ MultiTemplateParamsArg(
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
}
@@ -1389,7 +1411,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(),
TagType, StartLoc, SS,
Name, NameLoc, attrs.getList(),
- MultiTemplateParamsArg(Actions,
+ MultiTemplateParamsArg(
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
} else {
@@ -1470,8 +1492,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- TagType == DeclSpec::TST_class ? "class" :
- TagType == DeclSpec::TST_struct ? "struct" : "union");
+ 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.
@@ -1667,7 +1688,8 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
/// virt-specifier-seq:
/// virt-specifier
/// virt-specifier-seq virt-specifier
-void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
+void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
+ bool IsInterface) {
while (true) {
VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
@@ -1681,10 +1703,15 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
<< PrevSpec
<< FixItHint::CreateRemoval(Tok.getLocation());
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_override_control_keyword :
- diag::ext_override_control_keyword)
- << VirtSpecifiers::getSpecifierName(Specifier);
+ if (IsInterface && Specifier == VirtSpecifiers::VS_Final) {
+ Diag(Tok.getLocation(), diag::err_override_control_interface)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ } else {
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_override_control_keyword :
+ diag::ext_override_control_keyword)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ }
ConsumeToken();
}
}
@@ -1869,7 +1896,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
&CommonLateParsedAttrs);
- MultiTemplateParamsArg TemplateParams(Actions,
+ MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
@@ -1905,7 +1932,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS);
+ ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
@@ -2026,7 +2053,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);
+ ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
InClassInitStyle HasInClassInit = ICIS_NoInit;
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
@@ -2052,11 +2079,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (DS.isFriendSpecified()) {
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
- move(TemplateParams));
+ TemplateParams);
} else {
ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS,
DeclaratorInfo,
- move(TemplateParams),
+ TemplateParams,
BitfieldSize.release(),
VS, HasInClassInit);
if (AccessAttrs)
@@ -2240,6 +2267,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
unsigned TagType, Decl *TagDecl) {
assert((TagType == DeclSpec::TST_struct ||
+ TagType == DeclSpec::TST_interface ||
TagType == DeclSpec::TST_union ||
TagType == DeclSpec::TST_class) && "Invalid TagType!");
@@ -2254,6 +2282,15 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (S->isClassScope()) {
// We're inside a class scope, so this is a nested class.
NonNestedClass = false;
+
+ // The Microsoft extension __interface does not permit nested classes.
+ if (getCurrentClass().IsInterface) {
+ Diag(RecordLoc, diag::err_invalid_member_in_interface)
+ << /*ErrorType=*/6
+ << (isa<NamedDecl>(TagDecl)
+ ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
+ : "<anonymous>");
+ }
break;
}
@@ -2274,7 +2311,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
// Note that we are parsing a new (potentially-nested) class definition.
- ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass);
+ ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass,
+ TagType == DeclSpec::TST_interface);
if (TagDecl)
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
@@ -2286,9 +2324,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
assert(isCXX0XFinalKeyword() && "not a class definition");
FinalLoc = ConsumeToken();
- Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_override_control_keyword :
- diag::ext_override_control_keyword) << "final";
+ if (TagType == DeclSpec::TST_interface) {
+ Diag(FinalLoc, diag::err_override_control_interface)
+ << "final";
+ } else {
+ Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_override_control_keyword :
+ diag::ext_override_control_keyword) << "final";
+ }
}
if (Tok.is(tok::colon)) {
@@ -2348,6 +2391,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_align)) {
+ HandlePragmaAlign();
+ continue;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2373,6 +2421,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
<< FixItHint::CreateInsertion(EndLoc, ":");
}
+ // The Microsoft extension __interface does not permit non-public
+ // access specifiers.
+ if (TagType == DeclSpec::TST_interface && CurAS != AS_public) {
+ Diag(ASLoc, diag::err_access_specifier_interface)
+ << (CurAS == AS_protected);
+ }
+
if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
AccessAttrs.getList())) {
// found another attribute than only annotations
@@ -2571,7 +2626,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
T.consumeOpen();
// Parse the optional expression-list.
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
SkipUntil(tok::r_paren);
@@ -2586,7 +2641,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
- T.getOpenLocation(), ArgExprs.take(),
+ T.getOpenLocation(), ArgExprs.data(),
ArgExprs.size(), T.getCloseLocation(),
EllipsisLoc);
}
@@ -2752,10 +2807,11 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
/// so push that class onto our stack of classes that is currently
/// being parsed.
Sema::ParsingClassState
-Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) {
+Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass,
+ bool IsInterface) {
assert((NonNestedClass || !ClassStack.empty()) &&
"Nested class without outer class");
- ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass));
+ ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass, IsInterface));
return Actions.PushParsingClass();
}
@@ -2773,9 +2829,6 @@ void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
/// This routine should be called when we have finished parsing the
/// definition of a class, but have not yet popped the Scope
/// associated with the class's definition.
-///
-/// \returns true if the class we've popped is a top-level class,
-/// false otherwise.
void Parser::PopParsingClass(Sema::ParsingClassState state) {
assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
@@ -2850,6 +2903,21 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
}
}
+static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
+ IdentifierInfo *ScopeName) {
+ switch (AttributeList::getKind(AttrName, ScopeName,
+ AttributeList::AS_CXX11)) {
+ case AttributeList::AT_CarriesDependency:
+ case AttributeList::AT_FallThrough:
+ case AttributeList::AT_NoReturn: {
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently
/// only parses standard attributes.
///
@@ -2934,46 +3002,38 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
}
}
+ bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName);
bool AttrParsed = false;
- switch (AttributeList::getKind(AttrName, ScopeName,
- AttributeList::AS_CXX11)) {
- // No arguments
- case AttributeList::AT_CarriesDependency:
- // FIXME: implement generic support of attributes with C++11 syntax
- // see Parse/ParseDecl.cpp: ParseGNUAttributes
- case AttributeList::AT_FallThrough:
- case AttributeList::AT_NoReturn: {
- if (Tok.is(tok::l_paren)) {
- Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
- << AttrName->getName();
- break;
+
+ // Parse attribute arguments
+ if (Tok.is(tok::l_paren)) {
+ if (ScopeName && ScopeName->getName() == "gnu") {
+ ParseGNUAttributeArgs(AttrName, AttrLoc, attrs, endLoc,
+ ScopeName, ScopeLoc, AttributeList::AS_CXX11);
+ AttrParsed = true;
+ } else {
+ if (StandardAttr)
+ Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
+ << AttrName->getName();
+
+ // FIXME: handle other formats of c++11 attribute arguments
+ ConsumeParen();
+ SkipUntil(tok::r_paren, false);
}
+ }
+ if (!AttrParsed)
attrs.addNew(AttrName,
SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
AttrLoc),
ScopeName, ScopeLoc, 0,
SourceLocation(), 0, 0, AttributeList::AS_CXX11);
- AttrParsed = true;
- break;
- }
-
- // Silence warnings
- default: break;
- }
-
- // Skip the entire parameter clause, if any
- if (!AttrParsed && Tok.is(tok::l_paren)) {
- ConsumeParen();
- // SkipUntil maintains the balancedness of tokens.
- SkipUntil(tok::r_paren, false);
- }
if (Tok.is(tok::ellipsis)) {
- if (AttrParsed)
- Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
- << AttrName->getName();
ConsumeToken();
+
+ Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
+ << AttrName->getName();
}
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 8d4668b95481..c7be0d3ff2b9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -179,7 +179,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// \endverbatim
ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
ExprResult LHS(ParseAssignmentExpression(isTypeCast));
- return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
/// This routine is called when the '@' is seen and consumed.
@@ -190,7 +190,7 @@ ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
ExprResult
Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) {
ExprResult LHS(ParseObjCAtExpression(AtLoc));
- return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
/// This routine is called when a leading '__extension__' is seen and
@@ -210,7 +210,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__,
LHS.take());
- return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
/// \brief Parse an expr that doesn't include (top-level) commas.
@@ -227,7 +227,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
/*isAddressOfOperand=*/false,
isTypeCast);
- return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
+ return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
}
/// \brief Parse an assignment expression where part of an Objective-C message
@@ -265,6 +265,17 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
return Actions.ActOnConstantExpression(Res);
}
+bool Parser::isNotExpressionStart() {
+ tok::TokenKind K = Tok.getKind();
+ if (K == tok::l_brace || K == tok::r_brace ||
+ K == tok::kw_for || K == tok::kw_while ||
+ K == tok::kw_if || K == tok::kw_else ||
+ K == tok::kw_goto || K == tok::kw_try)
+ return true;
+ // If this is a decl-specifier, we can't be at the start of an expression.
+ return isKnownToBeDeclarationSpecifier();
+}
+
/// \brief Parse a binary expression that starts with \p LHS and has a
/// precedence of at least \p MinPrec.
ExprResult
@@ -279,12 +290,23 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// because we are called recursively, or because the token is not a binop),
// then we are done!
if (NextTokPrec < MinPrec)
- return move(LHS);
+ return LHS;
// Consume the operator, saving the operator token for error reporting.
Token OpToken = Tok;
ConsumeToken();
+ // Bail out when encountering a comma followed by a token which can't
+ // possibly be the start of an expression. For instance:
+ // int f() { return 1, }
+ // We can't do this before consuming the comma, because
+ // isNotExpressionStart() looks at the token stream.
+ if (OpToken.is(tok::comma) && isNotExpressionStart()) {
+ PP.EnterToken(Tok);
+ Tok = OpToken;
+ return LHS;
+ }
+
// Special case handling for the ternary operator.
ExprResult TernaryMiddle(true);
if (NextTokPrec == prec::Conditional) {
@@ -458,7 +480,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
isTypeCast);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
- return move(Res);
+ return Res;
}
namespace {
@@ -698,7 +720,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case CastExpr:
// We have parsed the cast-expression and no postfix-expr pieces are
// following.
- return move(Res);
+ return Res;
}
break;
@@ -741,6 +763,53 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// Avoid the unnecessary parse-time lookup in the common case
// where the syntax forbids a type.
const Token &Next = NextToken();
+
+ // If this identifier was reverted from a token ID, and the next token
+ // is a parenthesis, this is likely to be a use of a type trait. Check
+ // those tokens.
+ if (Next.is(tok::l_paren) &&
+ Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ // Build up the mapping of revertable type traits, for future use.
+ if (RevertableTypeTraits.empty()) {
+#define RTT_JOIN(X,Y) X##Y
+#define REVERTABLE_TYPE_TRAIT(Name) \
+ RevertableTypeTraits[PP.getIdentifierInfo(#Name)] \
+ = RTT_JOIN(tok::kw_,Name)
+
+ REVERTABLE_TYPE_TRAIT(__is_arithmetic);
+ REVERTABLE_TYPE_TRAIT(__is_convertible);
+ REVERTABLE_TYPE_TRAIT(__is_empty);
+ REVERTABLE_TYPE_TRAIT(__is_floating_point);
+ REVERTABLE_TYPE_TRAIT(__is_function);
+ REVERTABLE_TYPE_TRAIT(__is_fundamental);
+ REVERTABLE_TYPE_TRAIT(__is_integral);
+ REVERTABLE_TYPE_TRAIT(__is_member_function_pointer);
+ REVERTABLE_TYPE_TRAIT(__is_member_pointer);
+ REVERTABLE_TYPE_TRAIT(__is_pod);
+ REVERTABLE_TYPE_TRAIT(__is_pointer);
+ REVERTABLE_TYPE_TRAIT(__is_same);
+ REVERTABLE_TYPE_TRAIT(__is_scalar);
+ REVERTABLE_TYPE_TRAIT(__is_signed);
+ REVERTABLE_TYPE_TRAIT(__is_unsigned);
+ REVERTABLE_TYPE_TRAIT(__is_void);
+#undef REVERTABLE_TYPE_TRAIT
+#undef RTT_JOIN
+ }
+
+ // If we find that this is in fact the name of a type trait,
+ // update the token kind in place and parse again to treat it as
+ // the appropriate kind of type trait.
+ llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
+ = RevertableTypeTraits.find(II);
+ if (Known != RevertableTypeTraits.end()) {
+ Tok.setKind(Known->second);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
+ }
+ }
+
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
Next.is(tok::less) ||
@@ -758,7 +827,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// '.'.
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation ILoc = ConsumeToken();
-
+
// Support 'Class.property' and 'super.property' notation.
if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
(Actions.getTypeName(II, ILoc, getCurScope()) ||
@@ -888,7 +957,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(!getLangOpts().CPlusPlus);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::amp: { // unary-expression: '&' cast-expression
// Special treatment because of member pointers
@@ -896,7 +965,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(false, true);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::star: // unary-expression: '*' cast-expression
@@ -910,7 +979,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
@@ -920,7 +989,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
if (!getLangOpts().C11)
@@ -946,7 +1015,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Tok.getLocation());
Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD);
ConsumeToken();
- return move(Res);
+ return Res;
}
case tok::kw_const_cast:
case tok::kw_dynamic_cast:
@@ -1132,13 +1201,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (!Result.isInvalid())
Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(),
Result.take(), T.getCloseLocation());
- return move(Result);
+ return Result;
}
case tok::kw___is_abstract: // [GNU] unary-type-trait
case tok::kw___is_class:
case tok::kw___is_empty:
case tok::kw___is_enum:
+ case tok::kw___is_interface_class:
case tok::kw___is_literal:
case tok::kw___is_arithmetic:
case tok::kw___is_integral:
@@ -1270,7 +1340,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
switch (Tok.getKind()) {
case tok::code_completion:
if (InMessageExpression)
- return move(LHS);
+ return LHS;
Actions.CodeCompletePostfixExpression(getCurScope(), LHS);
cutOffParsing();
@@ -1290,7 +1360,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// Fall through; this isn't a message send.
default: // Not a postfix-expression suffix.
- return move(LHS);
+ return LHS;
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
// If we have a array postfix expression that starts on a new line and
// Objective-C is enabled, it is highly likely that the user forgot a
@@ -1300,7 +1370,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// expression and recover by pretending there is no suffix.
if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() &&
isSimpleObjCMessageExpression())
- return move(LHS);
+ return LHS;
// Reject array indices starting with a lambda-expression. '[[' is
// reserved for attributes.
@@ -1341,7 +1411,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
BalancedDelimiterTracker PT(*this, tok::l_paren);
if (OpKind == tok::lesslessless) {
- ExprVector ExecConfigExprs(Actions);
+ ExprVector ExecConfigExprs;
CommaLocsTy ExecConfigCommaLocs;
SourceLocation OpenLoc = ConsumeToken();
@@ -1372,7 +1442,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid()) {
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
OpenLoc,
- move_arg(ExecConfigExprs),
+ ExecConfigExprs,
CloseLoc);
if (ECResult.isInvalid())
LHS = ExprError();
@@ -1384,7 +1454,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
Loc = PT.getOpenLocation();
}
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (Tok.is(tok::code_completion)) {
@@ -1414,7 +1484,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
ArgExprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc,
- move_arg(ArgExprs), Tok.getLocation(),
+ ArgExprs, Tok.getLocation(),
ExecConfig);
PT.consumeClose();
}
@@ -1583,7 +1653,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
// If we get here, the operand to the typeof/sizeof/alignof was an expresion.
isCastExpr = false;
- return move(Operand);
+ return Operand;
}
@@ -1653,7 +1723,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof))
Diag(OpTok, diag::warn_cxx98_compat_alignof);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
bool isCastExpr;
ParsedType CastTy;
@@ -1684,7 +1755,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
/*isType=*/false,
Operand.release(),
CastRange);
- return move(Operand);
+ return Operand;
}
/// ParseBuiltinPrimaryExpression
@@ -1796,7 +1867,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Res = ParseExpression();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Res);
+ return Res;
}
Comps.back().U.E = Res.release();
@@ -1823,7 +1894,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Cond(ParseAssignmentExpression());
if (Cond.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Cond);
+ return Cond;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
@@ -1831,7 +1902,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Expr1(ParseAssignmentExpression());
if (Expr1.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Expr1);
+ return Expr1;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
@@ -1839,7 +1910,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Expr2(ParseAssignmentExpression());
if (Expr2.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Expr2);
+ return Expr2;
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
@@ -2083,7 +2154,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
DeclaratorInfo, CastTy,
RParenLoc, Result.take());
}
- return move(Result);
+ return Result;
}
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
@@ -2093,13 +2164,13 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the expression-list.
InMessageExpressionRAIIObject InMessage(*this, false);
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (!ParseExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
- move_arg(ArgExprs));
+ ArgExprs);
}
} else {
InMessageExpressionRAIIObject InMessage(*this, false);
@@ -2120,7 +2191,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
T.consumeClose();
RParenLoc = T.getCloseLocation();
- return move(Result);
+ return Result;
}
/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name
@@ -2141,7 +2212,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty,
ExprResult Result = ParseInitializer();
if (!Result.isInvalid() && Ty)
return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take());
- return move(Result);
+ return Result;
}
/// ParseStringLiteralExpression - This handles the various token types that
@@ -2211,8 +2282,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
}
SourceLocation DefaultLoc;
- TypeVector Types(Actions);
- ExprVector Exprs(Actions);
+ TypeVector Types;
+ ExprVector Exprs;
while (1) {
ParsedType Ty;
if (Tok.is(tok::kw_default)) {
@@ -2263,7 +2334,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc,
T.getCloseLocation(),
ControllingExpr.release(),
- move_arg(Types), move_arg(Exprs));
+ Types, Exprs);
}
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
@@ -2415,18 +2486,28 @@ ExprResult Parser::ParseBlockLiteralExpression() {
} else {
// Otherwise, pretend we saw (void).
ParsedAttributes attrs(AttrFactory);
- ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, false,
- SourceLocation(),
- 0, 0, 0,
- true, SourceLocation(),
- SourceLocation(),
- SourceLocation(),
- SourceLocation(),
- EST_None,
- SourceLocation(),
- 0, 0, 0, 0,
- CaretLoc, CaretLoc,
- ParamInfo),
+ SourceLocation NoLoc;
+ ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/true,
+ /*IsAmbiguous=*/false,
+ /*RParenLoc=*/NoLoc,
+ /*ArgInfo=*/0,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ CaretLoc, CaretLoc,
+ ParamInfo),
attrs, CaretLoc);
MaybeParseGNUAttributes(ParamInfo);
@@ -2450,7 +2531,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope());
else
Actions.ActOnBlockError(CaretLoc, getCurScope());
- return move(Result);
+ return Result;
}
/// ParseObjCBoolLiteral - This handles the objective-c Boolean literals.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index afac25793a73..2f615e150aad 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -96,6 +96,45 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
/*AtDigraph*/false);
}
+/// \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.
+void Parser::CheckForLParenAfterColonColon() {
+ if (!Tok.is(tok::l_paren))
+ return;
+
+ SourceLocation l_parenLoc = ConsumeParen(), r_parenLoc;
+ Token Tok1 = getCurToken();
+ if (!Tok1.is(tok::identifier) && !Tok1.is(tok::star))
+ return;
+
+ if (Tok1.is(tok::identifier)) {
+ Token Tok2 = GetLookAheadToken(1);
+ if (Tok2.is(tok::r_paren)) {
+ ConsumeToken();
+ PP.EnterToken(Tok1);
+ r_parenLoc = ConsumeParen();
+ }
+ } else if (Tok1.is(tok::star)) {
+ Token Tok2 = GetLookAheadToken(1);
+ if (Tok2.is(tok::identifier)) {
+ Token Tok3 = GetLookAheadToken(2);
+ if (Tok3.is(tok::r_paren)) {
+ ConsumeToken();
+ ConsumeToken();
+ PP.EnterToken(Tok2);
+ PP.EnterToken(Tok1);
+ r_parenLoc = ConsumeParen();
+ }
+ }
+ }
+
+ Diag(l_parenLoc, diag::err_paren_after_colon_colon)
+ << FixItHint::CreateRemoval(l_parenLoc)
+ << FixItHint::CreateRemoval(r_parenLoc);
+}
+
/// \brief Parse global scope or nested-name-specifier if present.
///
/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
@@ -160,7 +199,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// '::' - Global scope qualifier.
if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS))
return true;
-
+
+ CheckForLParenAfterColonColon();
+
HasScopeSpecifier = true;
}
@@ -301,8 +342,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
HasScopeSpecifier = true;
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
@@ -372,6 +412,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
"NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
+ CheckForLParenAfterColonColon();
+
HasScopeSpecifier = true;
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
ObjectType, EnteringContext, SS))
@@ -757,10 +799,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Scope::FunctionPrototypeScope |
Scope::DeclScope);
- SourceLocation DeclLoc, DeclEndLoc;
+ SourceLocation DeclEndLoc;
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- DeclLoc = T.getOpenLocation();
+ SourceLocation LParenLoc = T.getOpenLocation();
// Parse parameter-declaration-clause.
ParsedAttributes Attr(AttrFactory);
@@ -771,7 +813,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
T.consumeClose();
- DeclEndLoc = T.getCloseLocation();
+ SourceLocation RParenLoc = T.getCloseLocation();
+ DeclEndLoc = RParenLoc;
// Parse 'mutable'[opt].
SourceLocation MutableLoc;
@@ -797,9 +840,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse attribute-specifier[opt].
MaybeParseCXX0XAttributes(Attr, &DeclEndLoc);
+ SourceLocation FunLocalRangeEnd = DeclEndLoc;
+
// Parse trailing-return-type[opt].
TypeResult TrailingReturnType;
if (Tok.is(tok::arrow)) {
+ FunLocalRangeEnd = Tok.getLocation();
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(Range);
if (Range.getEnd().isValid())
@@ -808,15 +854,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
PrototypeScope.Exit();
+ SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
- /*isVariadic=*/EllipsisLoc.isValid(),
- /*isAmbiguous=*/false, EllipsisLoc,
+ /*isAmbiguous=*/false,
+ LParenLoc,
ParamInfo.data(), ParamInfo.size(),
+ EllipsisLoc, RParenLoc,
DS.getTypeQualifiers(),
/*RefQualifierIsLValueRef=*/true,
- /*RefQualifierLoc=*/SourceLocation(),
- /*ConstQualifierLoc=*/SourceLocation(),
- /*VolatileQualifierLoc=*/SourceLocation(),
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
MutableLoc,
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -824,7 +872,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
- DeclLoc, DeclEndLoc, D,
+ LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType),
Attr, DeclEndLoc);
} else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) {
@@ -853,25 +901,28 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
}
ParsedAttributes Attr(AttrFactory);
+ SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
- /*isVariadic=*/false,
- /*isAmbiguous=*/false,
- /*EllipsisLoc=*/SourceLocation(),
- /*Params=*/0, /*NumParams=*/0,
- /*TypeQuals=*/0,
- /*RefQualifierIsLValueRef=*/true,
- /*RefQualifierLoc=*/SourceLocation(),
- /*ConstQualifierLoc=*/SourceLocation(),
- /*VolatileQualifierLoc=*/SourceLocation(),
- MutableLoc,
- EST_None,
- /*ESpecLoc=*/SourceLocation(),
- /*Exceptions=*/0,
- /*ExceptionRanges=*/0,
- /*NumExceptions=*/0,
- /*NoexceptExpr=*/0,
- DeclLoc, DeclEndLoc, D,
- TrailingReturnType),
+ /*isAmbiguous=*/false,
+ /*LParenLoc=*/NoLoc,
+ /*Params=*/0,
+ /*NumParams=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLValueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ MutableLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ DeclLoc, DeclEndLoc, D,
+ TrailingReturnType),
Attr, DeclEndLoc);
}
@@ -926,10 +977,11 @@ ExprResult Parser::ParseCXXCasts() {
// Check for "<::" which is parsed as "[:". If found, fix token stream,
// diagnose error, suggest fix, and recover parsing.
- Token Next = NextToken();
- if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) &&
- areTokensAdjacent(Tok, Next))
- FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
+ if (Tok.is(tok::l_square) && Tok.getLength() == 2) {
+ Token Next = NextToken();
+ if (Next.is(tok::colon) && areTokensAdjacent(Tok, Next))
+ FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
+ }
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
return ExprError();
@@ -965,7 +1017,7 @@ ExprResult Parser::ParseCXXCasts() {
T.getOpenLocation(), Result.take(),
T.getCloseLocation());
- return move(Result);
+ return Result;
}
/// ParseCXXTypeid - This handles the C++ typeid expression.
@@ -988,6 +1040,22 @@ ExprResult Parser::ParseCXXTypeid() {
ExprResult Result;
+ // C++0x [expr.typeid]p3:
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] The expression is an unevaluated
+ // operand (Clause 5).
+ //
+ // Note that we can't tell whether the expression is an lvalue of a
+ // polymorphic class type until after we've parsed the expression; we
+ // speculatively assume the subexpression is unevaluated, and fix it up
+ // later.
+ //
+ // We enter the unevaluated context before trying to determine whether we
+ // have a type-id, because the tentative parse logic will try to resolve
+ // names, and must treat them as unevaluated.
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
+
if (isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
@@ -1000,16 +1068,6 @@ ExprResult Parser::ParseCXXTypeid() {
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
Ty.get().getAsOpaquePtr(), RParenLoc);
} else {
- // C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] The expression is an unevaluated
- // operand (Clause 5).
- //
- // Note that we can't tell whether the expression is an lvalue of a
- // polymorphic class type until after we've parsed the expression; we
- // speculatively assume the subexpression is unevaluated, and fix it up
- // later.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
Result = ParseExpression();
// Match the ')'.
@@ -1026,7 +1084,7 @@ ExprResult Parser::ParseCXXTypeid() {
}
}
- return move(Result);
+ return Result;
}
/// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression.
@@ -1074,7 +1132,7 @@ ExprResult Parser::ParseCXXUuidof() {
}
}
- return move(Result);
+ return Result;
}
/// \brief Parse a C++ pseudo-destructor expression after the base,
@@ -1196,7 +1254,7 @@ ExprResult Parser::ParseThrowExpression() {
default:
ExprResult Expr(ParseAssignmentExpression());
- if (Expr.isInvalid()) return move(Expr);
+ if (Expr.isInvalid()) return Expr;
return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take());
}
}
@@ -1245,7 +1303,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector Exprs(Actions);
+ ExprVector Exprs;
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren)) {
@@ -1265,7 +1323,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
- move_arg(Exprs),
+ Exprs,
T.getCloseLocation());
}
}
@@ -1280,11 +1338,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
-/// \param ExprResult if the condition was parsed as an expression, the
-/// parsed expression.
+/// \param ExprOut if the condition was parsed as an expression, the parsed
+/// expression.
///
-/// \param DeclResult if the condition was parsed as a declaration, the
-/// parsed declaration.
+/// \param DeclOut if the condition was parsed as a declaration, the parsed
+/// declaration.
///
/// \param Loc The location of the start of the statement that requires this
/// condition, e.g., the "for" in a for loop.
@@ -1714,8 +1772,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
}
// Bundle the template arguments together.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
- TemplateArgs.size());
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
// Constructor and destructor names.
TypeResult Type
@@ -1762,7 +1819,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
/// ptr-operator conversion-declarator[opt]
/// \endcode
///
-/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// \param SS The nested-name-specifier that preceded this unqualified-id. If
/// non-empty, then we are parsing the unqualified-id of a qualified-id.
///
/// \param EnteringContext whether we are entering the scope of the
@@ -1867,8 +1924,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Parse a literal-operator-id.
//
- // literal-operator-id: [C++0x 13.5.8]
- // operator "" identifier
+ // literal-operator-id: C++11 [over.literal]
+ // operator string-literal identifier
+ // operator user-defined-string-literal
if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
@@ -1882,6 +1940,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
llvm::SmallVector<SourceLocation, 4> TokLocs;
while (isTokenStringLiteral()) {
if (!Tok.is(tok::string_literal) && !DiagId) {
+ // C++11 [over.literal]p1:
+ // The string-literal or user-defined-string-literal in a
+ // literal-operator-id shall have no encoding-prefix [...].
DiagLoc = Tok.getLocation();
DiagId = diag::err_literal_operator_string_prefix;
}
@@ -1903,9 +1964,6 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
Literal.getUDSuffixOffset(),
PP.getSourceManager(), getLangOpts());
- // This form is not permitted by the standard (yet).
- DiagLoc = SuffixLoc;
- DiagId = diag::err_literal_operator_missing_space;
} else if (Tok.is(tok::identifier)) {
II = Tok.getIdentifierInfo();
SuffixLoc = ConsumeToken();
@@ -1917,6 +1975,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// The string literal must be empty.
if (!Literal.GetString().empty() || Literal.Pascal) {
+ // C++11 [over.literal]p1:
+ // The string-literal or user-defined-string-literal in a
+ // literal-operator-id shall [...] contain no characters
+ // other than the implicit terminating '\0'.
DiagLoc = TokLocs.front();
DiagId = diag::err_literal_operator_string_not_empty;
}
@@ -1981,7 +2043,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
///
/// \endcode
///
-/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// \param SS The nested-name-specifier that preceded this unqualified-id. If
/// non-empty, then we are parsing the unqualified-id of a qualified-id.
///
/// \param EnteringContext whether we are entering the scope of the
@@ -2209,7 +2271,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
// A '(' now can be a new-placement or the '(' wrapping the type-id in the
// second form of new-expression. It can't be a new-type-id.
- ExprVector PlacementArgs(Actions);
+ ExprVector PlacementArgs;
SourceLocation PlacementLParen, PlacementRParen;
SourceRange TypeIdParens;
@@ -2279,7 +2341,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (Tok.is(tok::l_paren)) {
SourceLocation ConstructorLParen, ConstructorRParen;
- ExprVector ConstructorArgs(Actions);
+ ExprVector ConstructorArgs;
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ConstructorLParen = T.getOpenLocation();
@@ -2298,7 +2360,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
}
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
ConstructorRParen,
- move_arg(ConstructorArgs));
+ ConstructorArgs);
} else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
@@ -2308,7 +2370,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return Initializer;
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
- move_arg(PlacementArgs), PlacementRParen,
+ PlacementArgs, PlacementRParen,
TypeIdParens, DeclaratorInfo, Initializer.take());
}
@@ -2422,7 +2484,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
ExprResult Operand(ParseCastExpression(false));
if (Operand.isInvalid())
- return move(Operand);
+ return Operand;
return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take());
}
@@ -2453,6 +2515,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_function: return UTT_IsFunction;
case tok::kw___is_fundamental: return UTT_IsFundamental;
case tok::kw___is_integral: return UTT_IsIntegral;
+ case tok::kw___is_interface_class: return UTT_IsInterfaceClass;
case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference;
case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer;
case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer;
@@ -2804,7 +2867,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(),
DeclaratorInfo, CastTy,
Tracker.getCloseLocation(), Result.take());
- return move(Result);
+ return Result;
}
// Not a compound literal, and not followed by a cast-expression.
@@ -2823,5 +2886,5 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
}
Tracker.consumeClose();
- return move(Result);
+ return Result;
}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 1c349fddbd57..e47fd9bd24a6 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -313,7 +313,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
Idx = ParseAssignmentExpression();
if (Idx.isInvalid()) {
SkipUntil(tok::r_square);
- return move(Idx);
+ return Idx;
}
}
@@ -341,7 +341,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
ExprResult RHS(ParseConstantExpression());
if (RHS.isInvalid()) {
SkipUntil(tok::r_square);
- return move(RHS);
+ return RHS;
}
Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
RHS.release(),
@@ -405,15 +405,14 @@ ExprResult Parser::ParseBraceInitializer() {
/// InitExprs - This is the actual list of expressions contained in the
/// initializer.
- ExprVector InitExprs(Actions);
+ ExprVector InitExprs;
if (Tok.is(tok::r_brace)) {
// Empty initializers are a C++ feature and a GNU extension to C.
if (!getLangOpts().CPlusPlus)
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
// Match the '}'.
- return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions),
- ConsumeBrace());
+ return Actions.ActOnInitList(LBraceLoc, MultiExprArg(), ConsumeBrace());
}
bool InitExprsOk = true;
@@ -476,7 +475,7 @@ ExprResult Parser::ParseBraceInitializer() {
bool closed = !T.consumeClose();
if (InitExprsOk && closed)
- return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs),
+ return Actions.ActOnInitList(LBraceLoc, InitExprs,
T.getCloseLocation());
return ExprError(); // an error occurred.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index db35a386c350..d321baf836bf 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -1031,7 +1032,6 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Scope::FunctionPrototypeScope|Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
-
while (1) {
ParsedAttributes paramAttrs(AttrFactory);
Sema::ObjCArgInfo ArgInfo;
@@ -1102,6 +1102,14 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SelIdent = ParseObjCSelectorPiece(selLoc);
if (!SelIdent && Tok.isNot(tok::colon))
break;
+ if (!SelIdent) {
+ SourceLocation ColonLoc = Tok.getLocation();
+ if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
+ Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
+ Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
+ Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
+ }
+ }
// We have a selector or a colon, continue parsing.
}
@@ -1806,7 +1814,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
- StmtVector CatchStmts(Actions);
+ StmtVector CatchStmts;
StmtResult FinallyStmt;
ParseScope TryScope(this, Scope::DeclScope);
StmtResult TryBody(ParseCompoundStatementBody());
@@ -1894,7 +1902,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
}
return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(),
- move_arg(CatchStmts),
+ CatchStmts,
FinallyStmt.take());
}
@@ -2061,13 +2069,13 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
if (Lit.isInvalid()) {
- return move(Lit);
+ return Lit;
}
ConsumeToken(); // Consume the literal token.
Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take());
if (Lit.isInvalid())
- return move(Lit);
+ return Lit;
return ParsePostfixExpressionSuffix(
Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
@@ -2134,7 +2142,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
}
}
-/// \brirg Parse the receiver of an Objective-C++ message send.
+/// \brief Parse the receiver of an Objective-C++ message send.
///
/// This routine parses the receiver of a message send in
/// Objective-C++ either as a type or as an expression. Note that this
@@ -2346,7 +2354,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
ExprResult Res(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
@@ -2418,7 +2426,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SmallVector<IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
- ExprVector KeyExprs(Actions);
+ ExprVector KeyExprs;
if (Tok.is(tok::colon)) {
while (1) {
@@ -2465,7 +2473,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
// We have a valid expression.
@@ -2512,7 +2520,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
// We have a valid expression.
@@ -2551,32 +2559,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
if (SuperLoc.isValid())
return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
- LBracLoc, KeyLocs, RBracLoc,
- MultiExprArg(Actions,
- KeyExprs.take(),
- KeyExprs.size()));
+ LBracLoc, KeyLocs, RBracLoc, KeyExprs);
else if (ReceiverType)
return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
- LBracLoc, KeyLocs, RBracLoc,
- MultiExprArg(Actions,
- KeyExprs.take(),
- KeyExprs.size()));
+ LBracLoc, KeyLocs, RBracLoc, KeyExprs);
return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
- LBracLoc, KeyLocs, RBracLoc,
- MultiExprArg(Actions,
- KeyExprs.take(),
- KeyExprs.size()));
+ LBracLoc, KeyLocs, RBracLoc, KeyExprs);
}
ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
ExprResult Res(ParseStringLiteralExpression());
- if (Res.isInvalid()) return move(Res);
+ if (Res.isInvalid()) return Res;
// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
// expressions. At this point, we know that the only valid thing that starts
// with '@' is an @"".
SmallVector<SourceLocation, 4> AtLocs;
- ExprVector AtStrings(Actions);
+ ExprVector AtStrings;
AtLocs.push_back(AtLoc);
AtStrings.push_back(Res.release());
@@ -2589,12 +2588,12 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
ExprResult Lit(ParseStringLiteralExpression());
if (Lit.isInvalid())
- return move(Lit);
+ return Lit;
AtStrings.push_back(Lit.release());
}
- return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
+ return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
AtStrings.size()));
}
@@ -2615,7 +2614,7 @@ ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
if (Lit.isInvalid()) {
- return move(Lit);
+ return Lit;
}
ConsumeToken(); // Consume the literal token.
return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
@@ -2629,7 +2628,7 @@ ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
if (Lit.isInvalid()) {
- return move(Lit);
+ return Lit;
}
ConsumeToken(); // Consume the literal token.
return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
@@ -2661,7 +2660,7 @@ Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
}
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
- ExprVector ElementExprs(Actions); // array elements.
+ ExprVector ElementExprs; // array elements.
ConsumeBracket(); // consume the l_square.
while (Tok.isNot(tok::r_square)) {
@@ -2672,7 +2671,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
// Parse the ellipsis that indicates a pack expansion.
@@ -2689,7 +2688,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma));
}
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
- MultiExprArg Args(Actions, ElementExprs.take(), ElementExprs.size());
+ MultiExprArg Args(ElementExprs);
return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args));
}
@@ -2707,7 +2706,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// stop at the '}' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_brace);
- return move(KeyExpr);
+ return KeyExpr;
}
}
@@ -2723,7 +2722,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// stop at the '}' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_brace);
- return move(ValueExpr);
+ return ValueExpr;
}
// Parse the ellipsis that designates this as a pack expansion.
@@ -2752,7 +2751,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
}
/// objc-encode-expression:
-/// @encode ( type-name )
+/// \@encode ( type-name )
ExprResult
Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index eb13e0d3574a..a7605f0cf4e0 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -40,7 +40,7 @@ void Parser::HandlePragmaVisibility() {
struct PragmaPackInfo {
Sema::PragmaPackKind Kind;
IdentifierInfo *Name;
- Expr *Alignment;
+ Token Alignment;
SourceLocation LParenLoc;
SourceLocation RParenLoc;
};
@@ -50,10 +50,107 @@ void Parser::HandlePragmaPack() {
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
SourceLocation PragmaLoc = ConsumeToken();
- Actions.ActOnPragmaPack(Info->Kind, Info->Name, Info->Alignment, PragmaLoc,
+ ExprResult Alignment;
+ if (Info->Alignment.is(tok::numeric_constant)) {
+ Alignment = Actions.ActOnNumericConstant(Info->Alignment);
+ if (Alignment.isInvalid())
+ return;
+ }
+ Actions.ActOnPragmaPack(Info->Kind, Info->Name, Alignment.get(), PragmaLoc,
Info->LParenLoc, Info->RParenLoc);
}
+void Parser::HandlePragmaMSStruct() {
+ assert(Tok.is(tok::annot_pragma_msstruct));
+ Sema::PragmaMSStructKind Kind =
+ static_cast<Sema::PragmaMSStructKind>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ Actions.ActOnPragmaMSStruct(Kind);
+ ConsumeToken(); // The annotation token.
+}
+
+void Parser::HandlePragmaAlign() {
+ assert(Tok.is(tok::annot_pragma_align));
+ Sema::PragmaOptionsAlignKind Kind =
+ static_cast<Sema::PragmaOptionsAlignKind>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ SourceLocation PragmaLoc = ConsumeToken();
+ Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
+}
+
+void Parser::HandlePragmaWeak() {
+ assert(Tok.is(tok::annot_pragma_weak));
+ SourceLocation PragmaLoc = ConsumeToken();
+ Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc,
+ Tok.getLocation());
+ ConsumeToken(); // The weak name.
+}
+
+void Parser::HandlePragmaWeakAlias() {
+ assert(Tok.is(tok::annot_pragma_weakalias));
+ SourceLocation PragmaLoc = ConsumeToken();
+ IdentifierInfo *WeakName = Tok.getIdentifierInfo();
+ SourceLocation WeakNameLoc = Tok.getLocation();
+ ConsumeToken();
+ IdentifierInfo *AliasName = Tok.getIdentifierInfo();
+ SourceLocation AliasNameLoc = Tok.getLocation();
+ ConsumeToken();
+ Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc,
+ WeakNameLoc, AliasNameLoc);
+
+}
+
+void Parser::HandlePragmaRedefineExtname() {
+ assert(Tok.is(tok::annot_pragma_redefine_extname));
+ SourceLocation RedefLoc = ConsumeToken();
+ IdentifierInfo *RedefName = Tok.getIdentifierInfo();
+ SourceLocation RedefNameLoc = Tok.getLocation();
+ ConsumeToken();
+ IdentifierInfo *AliasName = Tok.getIdentifierInfo();
+ SourceLocation AliasNameLoc = Tok.getLocation();
+ ConsumeToken();
+ Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc,
+ RedefNameLoc, AliasNameLoc);
+}
+
+void Parser::HandlePragmaFPContract() {
+ assert(Tok.is(tok::annot_pragma_fp_contract));
+ tok::OnOffSwitch OOS =
+ static_cast<tok::OnOffSwitch>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ Actions.ActOnPragmaFPContract(OOS);
+ ConsumeToken(); // The annotation token.
+}
+
+namespace {
+ typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData;
+}
+
+void Parser::HandlePragmaOpenCLExtension() {
+ assert(Tok.is(tok::annot_pragma_opencl_extension));
+ OpenCLExtData data =
+ OpenCLExtData::getFromOpaqueValue(Tok.getAnnotationValue());
+ unsigned state = data.getInt();
+ IdentifierInfo *ename = data.getPointer();
+ SourceLocation NameLoc = Tok.getLocation();
+ ConsumeToken(); // The annotation token.
+
+ OpenCLOptions &f = Actions.getOpenCLOptions();
+ // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
+ // overriding all previously issued extension directives, but only if the
+ // behavior is set to disable."
+ if (state == 0 && ename->isStr("all")) {
+#define OPENCLEXT(nm) f.nm = 0;
+#include "clang/Basic/OpenCLExtensions.def"
+ }
+#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
+#include "clang/Basic/OpenCLExtensions.def"
+ else {
+ PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
+ return;
+ }
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -130,13 +227,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
Sema::PragmaPackKind Kind = Sema::PPK_Default;
IdentifierInfo *Name = 0;
- ExprResult Alignment;
+ Token Alignment;
+ Alignment.startToken();
SourceLocation LParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
- Alignment = Actions.ActOnNumericConstant(Tok);
- if (Alignment.isInvalid())
- return;
+ Alignment = Tok;
PP.Lex(Tok);
@@ -165,9 +261,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
- Alignment = Actions.ActOnNumericConstant(Tok);
- if (Alignment.isInvalid())
- return;
+ Alignment = Tok;
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
@@ -182,9 +276,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
return;
}
- Alignment = Actions.ActOnNumericConstant(Tok);
- if (Alignment.isInvalid())
- return;
+ Alignment = Tok;
PP.Lex(Tok);
}
@@ -219,7 +311,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
new (Info) PragmaPackInfo();
Info->Kind = Kind;
Info->Name = Name;
- Info->Alignment = Alignment.release();
+ Info->Alignment = Alignment;
Info->LParenLoc = LParenLoc;
Info->RParenLoc = RParenLoc;
@@ -265,12 +357,23 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
<< "ms_struct";
return;
}
- Actions.ActOnPragmaMSStruct(Kind);
+
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_msstruct);
+ Toks[0].setLocation(MSStructTok.getLocation());
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(
+ static_cast<uintptr_t>(Kind)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
-static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
+static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
bool IsOptions) {
Token Tok;
@@ -317,7 +420,6 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
return;
}
- SourceLocation KindLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -325,19 +427,29 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
return;
}
- Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_align);
+ Toks[0].setLocation(FirstTok.getLocation());
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(
+ static_cast<uintptr_t>(Kind)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &AlignTok) {
- ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
+ ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false);
}
void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &OptionsTok) {
- ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
+ ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true);
}
// #pragma unused(identifier)
@@ -426,7 +538,6 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &WeakTok) {
- // FIXME: Should we be expanding macros here? My guess is no.
SourceLocation WeakLoc = WeakTok.getLocation();
Token Tok;
@@ -436,19 +547,20 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
return;
}
- IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
- SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
+ Token WeakName = Tok;
+ bool HasAlias = false;
+ Token AliasName;
PP.Lex(Tok);
if (Tok.is(tok::equal)) {
+ HasAlias = true;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "weak";
return;
}
- AliasName = Tok.getIdentifierInfo();
- AliasNameLoc = Tok.getLocation();
+ AliasName = Tok;
PP.Lex(Tok);
}
@@ -457,11 +569,29 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
return;
}
- if (AliasName) {
- Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
- AliasNameLoc);
+ if (HasAlias) {
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 3, llvm::alignOf<Token>());
+ Token &pragmaUnusedTok = Toks[0];
+ pragmaUnusedTok.startToken();
+ pragmaUnusedTok.setKind(tok::annot_pragma_weakalias);
+ pragmaUnusedTok.setLocation(WeakLoc);
+ Toks[1] = WeakName;
+ Toks[2] = AliasName;
+ PP.EnterTokenStream(Toks, 3,
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
} else {
- Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 2, llvm::alignOf<Token>());
+ Token &pragmaUnusedTok = Toks[0];
+ pragmaUnusedTok.startToken();
+ pragmaUnusedTok.setKind(tok::annot_pragma_weak);
+ pragmaUnusedTok.setLocation(WeakLoc);
+ Toks[1] = WeakName;
+ PP.EnterTokenStream(Toks, 2,
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
}
@@ -479,17 +609,16 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
return;
}
- IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0;
- SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc;
-
+ Token RedefName = Tok;
PP.Lex(Tok);
+
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "redefine_extname";
return;
}
- AliasName = Tok.getIdentifierInfo();
- AliasNameLoc = Tok.getLocation();
+
+ Token AliasName = Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
@@ -498,8 +627,17 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
return;
}
- Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc,
- RedefNameLoc, AliasNameLoc);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 3, llvm::alignOf<Token>());
+ Token &pragmaRedefTok = Toks[0];
+ pragmaRedefTok.startToken();
+ pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname);
+ pragmaRedefTok.setLocation(RedefLoc);
+ Toks[1] = RedefName;
+ Toks[2] = AliasName;
+ PP.EnterTokenStream(Toks, 3,
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
@@ -511,7 +649,17 @@ PragmaFPContractHandler::HandlePragma(Preprocessor &PP,
if (PP.LexOnOffSwitch(OOS))
return;
- Actions.ActOnPragmaFPContract(OOS);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_fp_contract);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(
+ static_cast<uintptr_t>(OOS)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
void
@@ -550,19 +698,23 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
return;
}
- OpenCLOptions &f = Actions.getOpenCLOptions();
- // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
- // overriding all previously issued extension directives, but only if the
- // behavior is set to disable."
- if (state == 0 && ename->isStr("all")) {
-#define OPENCLEXT(nm) f.nm = 0;
-#include "clang/Basic/OpenCLExtensions.def"
- }
-#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
-#include "clang/Basic/OpenCLExtensions.def"
- else {
- PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
+ "OPENCL EXTENSION";
return;
}
+
+ OpenCLExtData data(ename, state);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_opencl_extension);
+ Toks[0].setLocation(NameLoc);
+ Toks[0].setAnnotationValue(data.getOpaqueValue());
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index fef6960813d8..b9a2a251fcd4 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -21,9 +21,8 @@ namespace clang {
class Parser;
class PragmaAlignHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaAlignHandler(Sema &A) : PragmaHandler("align"), Actions(A) {}
+ explicit PragmaAlignHandler() : PragmaHandler("align") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
@@ -31,38 +30,31 @@ public:
class PragmaGCCVisibilityHandler : public PragmaHandler {
public:
- explicit PragmaGCCVisibilityHandler(Sema &/*A*/)
- : PragmaHandler("visibility") {}
+ explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaOptionsHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaOptionsHandler(Sema &A) : PragmaHandler("options"),
- Actions(A) {}
+ explicit PragmaOptionsHandler() : PragmaHandler("options") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaPackHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaPackHandler(Sema &A) : PragmaHandler("pack"),
- Actions(A) {}
+ explicit PragmaPackHandler() : PragmaHandler("pack") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaMSStructHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaMSStructHandler(Sema &A) : PragmaHandler("ms_struct"),
- Actions(A) {}
+ explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
@@ -70,48 +62,39 @@ public:
class PragmaUnusedHandler : public PragmaHandler {
public:
- PragmaUnusedHandler(Sema &/*A*/)
- : PragmaHandler("unused") {}
+ PragmaUnusedHandler() : PragmaHandler("unused") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaWeakHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaWeakHandler(Sema &A)
- : PragmaHandler("weak"), Actions(A) {}
+ explicit PragmaWeakHandler() : PragmaHandler("weak") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaRedefineExtnameHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaRedefineExtnameHandler(Sema &A)
- : PragmaHandler("redefine_extname"), Actions(A) {}
+ explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaOpenCLExtensionHandler : public PragmaHandler {
- Sema &Actions;
public:
- PragmaOpenCLExtensionHandler(Sema &A) :
- PragmaHandler("EXTENSION"), Actions(A) {}
+ PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaFPContractHandler : public PragmaHandler {
- Sema &Actions;
public:
- PragmaFPContractHandler(Sema &A) :
- PragmaHandler("FP_CONTRACT"), Actions(A) {}
+ PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index df9b996aa315..f604e038d2ad 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -17,6 +17,7 @@
#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"
@@ -130,96 +131,38 @@ Retry:
return ParseLabeledStatement(Attrs);
}
+ // Look up the identifier, and typo-correct it to a keyword if it's not
+ // found.
if (Next.isNot(tok::coloncolon)) {
- CXXScopeSpec SS;
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation NameLoc = Tok.getLocation();
-
- if (getLangOpts().CPlusPlus)
- CheckForTemplateAndDigraph(Next, ParsedType(),
- /*EnteringContext=*/false, *Name, SS);
-
- Sema::NameClassification Classification
- = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next);
- switch (Classification.getKind()) {
- case Sema::NC_Keyword:
- // The identifier was corrected to a keyword. Update the token
- // to this keyword, and try again.
- if (Name->getTokenID() != tok::identifier) {
- Tok.setIdentifierInfo(Name);
- Tok.setKind(Name->getTokenID());
- goto Retry;
- }
-
- // Fall through via the normal error path.
- // FIXME: This seems like it could only happen for context-sensitive
- // keywords.
-
- case Sema::NC_Error:
+ // Try to limit which sets of keywords should be included in typo
+ // correction based on what the next token is.
+ // FIXME: Pass the next token into the CorrectionCandidateCallback and
+ // do this filtering in a more fine-grained manner.
+ CorrectionCandidateCallback DefaultValidator;
+ DefaultValidator.WantTypeSpecifiers =
+ Next.is(tok::l_paren) || Next.is(tok::less) ||
+ Next.is(tok::identifier) || Next.is(tok::star) ||
+ Next.is(tok::amp) || Next.is(tok::l_square);
+ DefaultValidator.WantExpressionKeywords =
+ Next.is(tok::l_paren) || Next.is(tok::identifier) ||
+ Next.is(tok::arrow) || Next.is(tok::period);
+ DefaultValidator.WantRemainingKeywords =
+ Next.is(tok::l_paren) || Next.is(tok::semi) ||
+ Next.is(tok::identifier) || Next.is(tok::l_brace);
+ DefaultValidator.WantCXXNamedCasts = false;
+ if (TryAnnotateName(/*IsAddressOfOperand*/false, &DefaultValidator)
+ == ANK_Error) {
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
-
- case Sema::NC_Unknown:
- // Either we don't know anything about this identifier, or we know that
- // we're in a syntactic context we haven't handled yet.
- break;
-
- case Sema::NC_Type:
- Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Classification.getType());
- Tok.setAnnotationEndLoc(NameLoc);
- PP.AnnotateCachedTokens(Tok);
- break;
-
- case Sema::NC_Expression:
- Tok.setKind(tok::annot_primary_expr);
- setExprAnnotation(Tok, Classification.getExpression());
- Tok.setAnnotationEndLoc(NameLoc);
- PP.AnnotateCachedTokens(Tok);
- break;
-
- case Sema::NC_TypeTemplate:
- case Sema::NC_FunctionTemplate: {
- ConsumeToken(); // the identifier
- UnqualifiedId Id;
- Id.setIdentifier(Name, NameLoc);
- if (AnnotateTemplateIdToken(
- TemplateTy::make(Classification.getTemplateName()),
- Classification.getTemplateNameKind(),
- SS, SourceLocation(), Id,
- /*AllowTypeAnnotation=*/false)) {
- // Handle errors here by skipping up to the next semicolon or '}', and
- // eat the semicolon if that's what stopped us.
- SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return StmtError();
- }
-
- // If the next token is '::', jump right into parsing a
- // nested-name-specifier. We don't want to leave the template-id
- // hanging.
- if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){
- // Handle errors here by skipping up to the next semicolon or '}', and
- // eat the semicolon if that's what stopped us.
- SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return StmtError();
- }
-
- // We've annotated a template-id, so try again now.
- goto Retry;
}
- case Sema::NC_NestedNameSpecifier:
- // FIXME: Implement this!
- break;
- }
+ // If the identifier was typo-corrected, try again.
+ if (Tok.isNot(tok::identifier))
+ goto Retry;
}
// Fall through
@@ -289,7 +232,7 @@ Retry:
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
Res = Actions.ActOnFinishFullStmt(Res.get());
- if (msAsm) return move(Res);
+ if (msAsm) return Res;
SemiError = "asm";
break;
}
@@ -310,6 +253,41 @@ Retry:
ProhibitAttributes(Attrs);
HandlePragmaPack();
return StmtEmpty();
+
+ case tok::annot_pragma_msstruct:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSStruct();
+ return StmtEmpty();
+
+ case tok::annot_pragma_align:
+ ProhibitAttributes(Attrs);
+ HandlePragmaAlign();
+ return StmtEmpty();
+
+ case tok::annot_pragma_weak:
+ ProhibitAttributes(Attrs);
+ HandlePragmaWeak();
+ return StmtEmpty();
+
+ case tok::annot_pragma_weakalias:
+ ProhibitAttributes(Attrs);
+ HandlePragmaWeakAlias();
+ return StmtEmpty();
+
+ case tok::annot_pragma_redefine_extname:
+ ProhibitAttributes(Attrs);
+ HandlePragmaRedefineExtname();
+ return StmtEmpty();
+
+ case tok::annot_pragma_fp_contract:
+ Diag(Tok, diag::err_pragma_fp_contract_scope);
+ ConsumeToken();
+ return StmtError();
+
+ case tok::annot_pragma_opencl_extension:
+ ProhibitAttributes(Attrs);
+ HandlePragmaOpenCLExtension();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -324,7 +302,7 @@ Retry:
SkipUntil(tok::r_brace, true, true);
}
- return move(Res);
+ return Res;
}
/// \brief Parse an expression statement.
@@ -381,7 +359,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
StmtResult TryBlock(ParseCompoundStatement());
if(TryBlock.isInvalid())
- return move(TryBlock);
+ return TryBlock;
StmtResult Handler;
if (Tok.is(tok::identifier) &&
@@ -396,7 +374,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
}
if(Handler.isInvalid())
- return move(Handler);
+ return Handler;
return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
TryLoc,
@@ -441,7 +419,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
StmtResult Block(ParseCompoundStatement());
if(Block.isInvalid())
- return move(Block);
+ return Block;
return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take());
}
@@ -458,7 +436,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
StmtResult Block(ParseCompoundStatement());
if(Block.isInvalid())
- return move(Block);
+ return Block;
return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take());
}
@@ -603,7 +581,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// Otherwise we link it into the current chain.
Stmt *NextDeepest = Case.get();
if (TopLevelCase.isInvalid())
- TopLevelCase = move(Case);
+ TopLevelCase = Case;
else
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get());
DeepestParsedCaseStmt = NextDeepest;
@@ -636,7 +614,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
// Return the top level parsed statement tree.
- return move(TopLevelCase);
+ return TopLevelCase;
}
/// ParseDefaultStatement
@@ -728,6 +706,48 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
return ParseCompoundStatementBody(isStmtExpr);
}
+/// Parse any pragmas at the start of the compound expression. We handle these
+/// separately since some pragmas (FP_CONTRACT) must appear before any C
+/// statement in the compound, but may be intermingled with other pragmas.
+void Parser::ParseCompoundStatementLeadingPragmas() {
+ bool checkForPragmas = true;
+ while (checkForPragmas) {
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_vis:
+ HandlePragmaVisibility();
+ break;
+ case tok::annot_pragma_pack:
+ HandlePragmaPack();
+ break;
+ case tok::annot_pragma_msstruct:
+ HandlePragmaMSStruct();
+ break;
+ case tok::annot_pragma_align:
+ HandlePragmaAlign();
+ break;
+ case tok::annot_pragma_weak:
+ HandlePragmaWeak();
+ break;
+ case tok::annot_pragma_weakalias:
+ HandlePragmaWeakAlias();
+ break;
+ case tok::annot_pragma_redefine_extname:
+ HandlePragmaRedefineExtname();
+ break;
+ case tok::annot_pragma_opencl_extension:
+ HandlePragmaOpenCLExtension();
+ break;
+ case tok::annot_pragma_fp_contract:
+ HandlePragmaFPContract();
+ break;
+ default:
+ checkForPragmas = false;
+ break;
+ }
+ }
+
+}
+
/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
/// consume the '}' at the end of the block. It does not manipulate the scope
@@ -736,6 +756,11 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
"in compound statement ('{}')");
+
+ // Record the state of the FP_CONTRACT pragma, restore on leaving the
+ // compound statement.
+ Sema::FPContractStateRAII SaveFPContractState(Actions);
+
InMessageExpressionRAIIObject InMessage(*this, false);
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen())
@@ -743,7 +768,10 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- StmtVector Stmts(Actions);
+ // Parse any pragmas at the beginning of the compound statement.
+ ParseCompoundStatementLeadingPragmas();
+
+ StmtVector Stmts;
// "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
// only allowed at the start of a compound stmt regardless of the language.
@@ -850,7 +878,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
}
return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
- move_arg(Stmts), isStmtExpr);
+ Stmts, isStmtExpr);
}
/// ParseParenExprOrCondition:
@@ -1096,7 +1124,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
SkipUntil(tok::r_brace, false, false);
} else
SkipUntil(tok::semi);
- return move(Switch);
+ return Switch;
}
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
@@ -1375,7 +1403,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
DeclEnd, attrs, false,
MightBeForRangeStmt ?
@@ -1498,7 +1526,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(),
ForRangeInit.ColonLoc,
ForRangeInit.RangeExpr.get(),
- T.getCloseLocation());
+ T.getCloseLocation(),
+ Sema::BFRK_Build);
// Similarly, we need to do the semantic analysis for a for-range
@@ -1580,7 +1609,7 @@ StmtResult Parser::ParseGotoStatement() {
return StmtError();
}
- return move(Res);
+ return Res;
}
/// ParseContinueStatement
@@ -1653,6 +1682,9 @@ 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;
@@ -1745,6 +1777,21 @@ 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);
@@ -1806,18 +1853,17 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
SmallVector<IdentifierInfo *, 4> Names;
- ExprVector Constraints(Actions);
- ExprVector Exprs(Actions);
- ExprVector Clobbers(Actions);
+ ExprVector Constraints;
+ ExprVector Exprs;
+ ExprVector Clobbers;
if (Tok.is(tok::r_paren)) {
// We have a simple asm expression like 'asm("foo")'.
T.consumeClose();
- return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
- /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
- move_arg(Constraints), move_arg(Exprs),
- AsmString.take(), move_arg(Clobbers),
- T.getCloseLocation());
+ return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
+ /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
+ Constraints, Exprs, AsmString.take(),
+ Clobbers, T.getCloseLocation());
}
// Parse Outputs, if present.
@@ -1878,11 +1924,10 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
T.consumeClose();
- return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile,
- NumOutputs, NumInputs, Names.data(),
- move_arg(Constraints), move_arg(Exprs),
- AsmString.take(), move_arg(Clobbers),
- T.getCloseLocation());
+ return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs,
+ NumInputs, Names.data(), Constraints, Exprs,
+ AsmString.take(), Clobbers,
+ T.getCloseLocation());
}
/// ParseAsmOperands - Parse the asm-operands production as used by
@@ -1975,7 +2020,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
- MultiStmtArg(Actions), false);
+ MultiStmtArg(), false);
}
BodyScope.Exit();
@@ -2006,13 +2051,13 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
}
SourceLocation LBraceLoc = Tok.getLocation();
- StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
+ StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true));
// If we failed to parse the try-catch, we just give the function an empty
// compound statement as the body.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
- MultiStmtArg(Actions), false);
+ MultiStmtArg(), false);
}
BodyScope.Exit();
@@ -2024,12 +2069,18 @@ bool Parser::trySkippingFunctionBody() {
assert(SkipFunctionBodies &&
"Should only be called when SkipFunctionBodies is enabled");
+ if (!PP.isCodeCompletionEnabled()) {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false);
+ return true;
+ }
+
// We're in code-completion mode. Skip parsing for all function bodies unless
// the body contains the code-completion point.
TentativeParsingAction PA(*this);
ConsumeBrace();
if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false,
- /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) {
+ /*StopAtCodeCompletion=*/true)) {
PA.Commit();
return true;
}
@@ -2066,15 +2117,16 @@ StmtResult Parser::ParseCXXTryBlock() {
/// 'try' compound-statement seh-except-block
/// 'try' compound-statment seh-finally-block
///
-StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
+StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope|Scope::TryScope));
+ Scope::DeclScope |
+ (FnTry ? Scope::FnTryScope : Scope::TryScope)));
if (TryBlock.isInvalid())
- return move(TryBlock);
+ return TryBlock;
// Borland allows SEH-handlers with 'try'
@@ -2092,7 +2144,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
Handler = ParseSEHFinallyBlock(Loc);
}
if(Handler.isInvalid())
- return move(Handler);
+ return Handler;
return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
TryLoc,
@@ -2100,7 +2152,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
Handler.take());
}
else {
- StmtVector Handlers(Actions);
+ StmtVector Handlers;
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
ProhibitAttributes(attrs);
@@ -2108,7 +2160,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::kw_catch))
return StmtError(Diag(Tok, diag::err_expected_catch));
while (Tok.is(tok::kw_catch)) {
- StmtResult Handler(ParseCXXCatchBlock());
+ StmtResult Handler(ParseCXXCatchBlock(FnTry));
if (!Handler.isInvalid())
Handlers.push_back(Handler.release());
}
@@ -2117,7 +2169,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Handlers.empty())
return StmtError();
- return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),move_arg(Handlers));
+ return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),Handlers);
}
}
@@ -2132,7 +2184,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
/// type-specifier-seq
/// '...'
///
-StmtResult Parser::ParseCXXCatchBlock() {
+StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
SourceLocation CatchLoc = ConsumeToken();
@@ -2144,7 +2196,8 @@ StmtResult Parser::ParseCXXCatchBlock() {
// C++ 3.3.2p3:
// 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);
+ ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope |
+ (FnCatch ? Scope::FnCatchScope : 0));
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
@@ -2169,7 +2222,7 @@ StmtResult Parser::ParseCXXCatchBlock() {
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult Block(ParseCompoundStatement());
if (Block.isInvalid())
- return move(Block);
+ return Block;
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index ade918fb221a..2e0411e8a81c 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -246,7 +246,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
return 0;
}
- LateParsedAttrList LateParsedAttrs;
+ LateParsedAttrList LateParsedAttrs(true);
if (DeclaratorInfo.isFunctionDeclarator())
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
@@ -889,8 +889,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
return true;
}
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
- TemplateArgs.size());
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
@@ -942,8 +941,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
Tok.setLocation(TemplateKWLoc);
else
Tok.setLocation(TemplateNameLoc);
-
- TemplateArgsPtr.release();
}
// Common fields for the annotation token
@@ -969,8 +966,7 @@ void Parser::AnnotateTemplateIdTokenAsType() {
TemplateId->Kind == TNK_Dependent_template_name) &&
"Only works for type and dependent templates");
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult Type
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 1a4df4791b5f..40c4eee1994b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -104,16 +104,27 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
// isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
// a case.
- TPResult TPR = isCXXDeclarationSpecifier();
+ bool InvalidAsDeclaration = false;
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ &InvalidAsDeclaration);
if (TPR != TPResult::Ambiguous())
return TPR != TPResult::False(); // Returns true for TPResult::True() or
// TPResult::Error().
+ // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer,
+ // and so gets some cases wrong. We can't carry on if we've already seen
+ // something which makes this statement invalid as a declaration in this case,
+ // since it can cause us to misparse valid code. Revisit this once
+ // TryParseInitDeclaratorList is fixed.
+ if (InvalidAsDeclaration)
+ return false;
+
// FIXME: Add statistics about the number of ambiguous statements encountered
// and how they were resolved (number of declarations+number of expressions).
- // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
- // We need tentative parsing...
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '(',
+ // or an identifier which doesn't resolve as anything. We need tentative
+ // parsing...
TentativeParsingAction PA(*this);
TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
@@ -140,20 +151,28 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
/// attribute-specifier-seqopt type-specifier-seq declarator
///
Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
- // We know that we have a simple-type-specifier/typename-specifier followed
- // by a '('.
- assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
-
if (Tok.is(tok::kw_typeof))
TryParseTypeofSpecifier();
else {
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
ConsumeToken();
-
+
if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
-
- assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // Two decl-specifiers in a row conclusively disambiguate this as being a
+ // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
+ // overwhelmingly common case that the next token is a '('.
+ if (Tok.isNot(tok::l_paren)) {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR == TPResult::Ambiguous())
+ return TPResult::True();
+ if (TPR == TPResult::True() || TPR == TPResult::Error())
+ return TPR;
+ assert(TPR == TPResult::False());
+ }
TPResult TPR = TryParseInitDeclaratorList();
if (TPR != TPResult::Ambiguous())
@@ -623,6 +642,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// declarator-id
if (Tok.is(tok::annot_cxxscope))
ConsumeToken();
+ else
+ TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
ConsumeToken();
} else if (Tok.is(tok::l_paren)) {
ConsumeParen();
@@ -761,6 +782,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___is_convertible_to:
case tok::kw___is_empty:
case tok::kw___is_enum:
+ case tok::kw___is_interface_class:
case tok::kw___is_final:
case tok::kw___is_literal:
case tok::kw___is_literal_type:
@@ -824,6 +846,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
return TPResult::Ambiguous();
}
+bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
+ return std::find(TentativelyDeclaredIdentifiers.begin(),
+ TentativelyDeclaredIdentifiers.end(), II)
+ != TentativelyDeclaredIdentifiers.end();
+}
+
/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
/// be either a decl-specifier or a function-style cast, and TPResult::Error()
@@ -831,7 +859,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
///
/// If HasMissingTypename is provided, a name with a dependent scope specifier
/// will be treated as ambiguous if the 'typename' keyword is missing. If this
-/// happens, *HasMissingTypename will be set to 'true'.
+/// happens, *HasMissingTypename will be set to 'true'. This will also be used
+/// as an indicator that undeclared identifiers (which will trigger a later
+/// parse error) should be treated as types. Returns TPResult::Ambiguous() in
+/// such cases.
///
/// decl-specifier:
/// storage-class-specifier
@@ -927,22 +958,64 @@ Parser::TPResult
Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
bool *HasMissingTypename) {
switch (Tok.getKind()) {
- case tok::identifier: // foo::bar
+ case tok::identifier: {
// Check for need to substitute AltiVec __vector keyword
// for "vector" identifier.
if (TryAltiVecVectorToken())
return TPResult::True();
- // Fall through.
+
+ const Token &Next = NextToken();
+ // In 'foo bar', 'foo' is always a type name outside of Objective-C.
+ if (!getLangOpts().ObjC1 && Next.is(tok::identifier))
+ return TPResult::True();
+
+ if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) {
+ // Determine whether this is a valid expression. If not, we will hit
+ // a parse error one way or another. In that case, tell the caller that
+ // this is ambiguous. Typo-correct to type and expression keywords and
+ // to types and identifiers, in order to try to recover from errors.
+ CorrectionCandidateCallback TypoCorrection;
+ TypoCorrection.WantRemainingKeywords = false;
+ switch (TryAnnotateName(false /* no nested name specifier */,
+ &TypoCorrection)) {
+ case ANK_Error:
+ return TPResult::Error();
+ case ANK_TentativeDecl:
+ return TPResult::False();
+ case ANK_TemplateName:
+ // A bare type template-name which can't be a template template
+ // argument is an error, and was probably intended to be a type.
+ return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ case ANK_Unresolved:
+ return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False();
+ case ANK_Success:
+ break;
+ }
+ assert(Tok.isNot(tok::identifier) &&
+ "TryAnnotateName succeeded without producing an annotation");
+ } else {
+ // This might possibly be a type with a dependent scope specifier and
+ // a missing 'typename' keyword. Don't use TryAnnotateName in this case,
+ // since it will annotate as a primary expression, and we want to use the
+ // "missing 'typename'" logic.
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error();
+ // If annotation failed, assume it's a non-type.
+ // FIXME: If this happens due to an undeclared identifier, treat it as
+ // ambiguous.
+ if (Tok.is(tok::identifier))
+ return TPResult::False();
+ }
+
+ // We annotated this token as something. Recurse to handle whatever we got.
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+ }
+
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error();
- if (Tok.is(tok::identifier)) {
- const Token &Next = NextToken();
- return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ?
- TPResult::True() : TPResult::False();
- }
return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
case tok::coloncolon: { // ::foo::bar
@@ -1073,6 +1146,28 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
*HasMissingTypename = true;
return TPResult::Ambiguous();
}
+ } else {
+ // Try to resolve the name. If it doesn't exist, assume it was
+ // intended to name a type and keep disambiguating.
+ switch (TryAnnotateName(false /* SS is not dependent */)) {
+ case ANK_Error:
+ return TPResult::Error();
+ case ANK_TentativeDecl:
+ return TPResult::False();
+ case ANK_TemplateName:
+ // A bare type template-name which can't be a template template
+ // argument is an error, and was probably intended to be a type.
+ return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ case ANK_Unresolved:
+ return HasMissingTypename ? TPResult::Ambiguous()
+ : TPResult::False();
+ case ANK_Success:
+ // Annotated it, check again.
+ assert(Tok.isNot(tok::annot_cxxscope) ||
+ NextToken().isNot(tok::identifier));
+ return isCXXDeclarationSpecifier(BracedCastResult,
+ HasMissingTypename);
+ }
}
}
return TPResult::False();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 3725e2b84550..f4cdd619cef4 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/ASTConsumer.h"
using namespace clang;
+
namespace {
/// \brief A comment handler that passes comments found by the preprocessor
/// to the parser action.
@@ -47,11 +48,13 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
return Ident__except;
}
-Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies)
+Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
: PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
GreaterThanIsOperator(true), ColonIsSacred(false),
InMessageExpression(false), TemplateParameterDepth(0),
- ParsingInObjCContainer(false), SkipFunctionBodies(SkipFunctionBodies) {
+ ParsingInObjCContainer(false) {
+ SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
+ Tok.startToken();
Tok.setKind(tok::eof);
Actions.CurScope = 0;
NumCachedScopes = 0;
@@ -60,35 +63,35 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies)
// Add #pragma handlers. These are removed and destroyed in the
// destructor.
- AlignHandler.reset(new PragmaAlignHandler(actions));
+ AlignHandler.reset(new PragmaAlignHandler());
PP.AddPragmaHandler(AlignHandler.get());
- GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions));
+ GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler());
PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
- OptionsHandler.reset(new PragmaOptionsHandler(actions));
+ OptionsHandler.reset(new PragmaOptionsHandler());
PP.AddPragmaHandler(OptionsHandler.get());
- PackHandler.reset(new PragmaPackHandler(actions));
+ PackHandler.reset(new PragmaPackHandler());
PP.AddPragmaHandler(PackHandler.get());
- MSStructHandler.reset(new PragmaMSStructHandler(actions));
+ MSStructHandler.reset(new PragmaMSStructHandler());
PP.AddPragmaHandler(MSStructHandler.get());
- UnusedHandler.reset(new PragmaUnusedHandler(actions));
+ UnusedHandler.reset(new PragmaUnusedHandler());
PP.AddPragmaHandler(UnusedHandler.get());
- WeakHandler.reset(new PragmaWeakHandler(actions));
+ WeakHandler.reset(new PragmaWeakHandler());
PP.AddPragmaHandler(WeakHandler.get());
- RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions));
+ RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler());
PP.AddPragmaHandler(RedefineExtnameHandler.get());
- FPContractHandler.reset(new PragmaFPContractHandler(actions));
+ FPContractHandler.reset(new PragmaFPContractHandler());
PP.AddPragmaHandler("STDC", FPContractHandler.get());
if (getLangOpts().OpenCL) {
- OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler(actions));
+ OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
@@ -135,7 +138,7 @@ DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) {
/// given range.
///
/// \param Loc The location where we'll emit the diagnostic.
-/// \param Loc The kind of diagnostic to emit.
+/// \param DK The kind of diagnostic to emit.
/// \param ParenRange Source range enclosing code that should be parenthesized.
void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange) {
@@ -154,7 +157,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) {
switch (ExpectedTok) {
- case tok::semi: return Tok.is(tok::colon); // : for ;
+ case tok::semi:
+ return Tok.is(tok::colon) || Tok.is(tok::comma); // : or , for ;
default: return false;
}
}
@@ -466,9 +470,6 @@ void Parser::Initialize() {
EnterScope(Scope::DeclScope);
Actions.ActOnTranslationUnitScope(getCurScope());
- // Prime the lexer look-ahead.
- ConsumeToken();
-
// Initialization for Objective-C context sensitive keywords recognition.
// Referenced in Parser::ParseObjCTypeQualifierList.
if (getLangOpts().ObjC1) {
@@ -523,6 +524,11 @@ void Parser::Initialize() {
PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block);
PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
}
+
+ Actions.Initialize();
+
+ // Prime the lexer look-ahead.
+ ConsumeToken();
}
namespace {
@@ -634,6 +640,27 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_pack:
HandlePragmaPack();
return DeclGroupPtrTy();
+ case tok::annot_pragma_msstruct:
+ HandlePragmaMSStruct();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_align:
+ HandlePragmaAlign();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_weak:
+ HandlePragmaWeak();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_weakalias:
+ HandlePragmaWeakAlias();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_redefine_extname:
+ HandlePragmaRedefineExtname();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_fp_contract:
+ HandlePragmaFPContract();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_opencl_extension:
+ HandlePragmaOpenCLExtension();
+ return DeclGroupPtrTy();
case tok::semi:
ConsumeExtraSemi(OutsideFunction);
// TODO: Invoke action for top-level semicolon.
@@ -693,7 +720,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
@@ -704,7 +731,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
goto dont_know;
@@ -716,7 +743,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// Inline namespaces. Allowed as an extension even in C++03.
if (NextKind == tok::kw_namespace) {
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
@@ -726,7 +753,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
}
@@ -972,16 +999,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (getLangOpts().DelayedTemplateParsing &&
Tok.isNot(tok::equal) &&
TemplateInfo.Kind == ParsedTemplateInfo::Template) {
- MultiTemplateParamsArg TemplateParameterLists(Actions,
- TemplateInfo.TemplateParams->data(),
- TemplateInfo.TemplateParams->size());
+ MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = Actions.HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists));
+ TemplateParameterLists);
D.complete(DP);
D.getMutableDeclSpec().abort();
@@ -1009,13 +1034,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
(Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
Tok.is(tok::colon)) &&
Actions.CurContext->isTranslationUnit()) {
- MultiTemplateParamsArg TemplateParameterLists(Actions, 0, 0);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
Decl *FuncDecl = Actions.HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists));
+ MultiTemplateParamsArg());
D.complete(FuncDecl);
D.getMutableDeclSpec().abort();
if (FuncDecl) {
@@ -1033,10 +1057,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// specified Declarator for the function.
Decl *Res = TemplateInfo.TemplateParams?
Actions.ActOnStartOfFunctionTemplateDef(getCurScope(),
- MultiTemplateParamsArg(Actions,
- TemplateInfo.TemplateParams->data(),
- TemplateInfo.TemplateParams->size()),
- D)
+ *TemplateInfo.TemplateParams, D)
: Actions.ActOnStartOfFunctionDef(getCurScope(), D);
// Break out of the ParsingDeclarator context before we parse the body.
@@ -1288,7 +1309,7 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
*EndLoc = T.getCloseLocation();
}
- return move(Result);
+ return Result;
}
/// \brief Get the TemplateIdAnnotation from the token and put it in the
@@ -1301,6 +1322,143 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) {
return Id;
}
+void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
+ // Push the current token back into the token stream (or revert it if it is
+ // cached) and use an annotation scope token for current token.
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::annot_cxxscope);
+ Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
+ Tok.setAnnotationRange(SS.getRange());
+
+ // In case the tokens were cached, have Preprocessor replace them
+ // with the annotation token. We don't need to do this if we've
+ // just reverted back to a prior state.
+ if (IsNewAnnotation)
+ PP.AnnotateCachedTokens(Tok);
+}
+
+/// \brief Attempt to classify the name at the current token position. This may
+/// form a type, scope or primary expression annotation, or replace the token
+/// with a typo-corrected keyword. This is only appropriate when the current
+/// name must refer to an entity which has already been declared.
+///
+/// \param IsAddressOfOperand Must be \c true if the name is preceded by an '&'
+/// and might possibly have a dependent nested name specifier.
+/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
+/// no typo correction will be performed.
+Parser::AnnotatedNameKind
+Parser::TryAnnotateName(bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC) {
+ assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
+
+ const bool EnteringContext = false;
+ const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+
+ CXXScopeSpec SS;
+ if (getLangOpts().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
+ return ANK_Error;
+
+ if (Tok.isNot(tok::identifier) || SS.isInvalid()) {
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, false, SS,
+ !WasScopeAnnotation))
+ return ANK_Error;
+ return ANK_Unresolved;
+ }
+
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = Tok.getLocation();
+
+ // FIXME: Move the tentative declaration logic into ClassifyName so we can
+ // typo-correct to tentatively-declared identifiers.
+ if (isTentativelyDeclared(Name)) {
+ // Identifier has been tentatively declared, and thus cannot be resolved as
+ // an expression. Fall back to annotating it as a type.
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, false, SS,
+ !WasScopeAnnotation))
+ return ANK_Error;
+ return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl;
+ }
+
+ Token Next = NextToken();
+
+ // Look up and classify the identifier. We don't perform any typo-correction
+ // after a scope specifier, because in general we can't recover from typos
+ // there (eg, after correcting 'A::tempalte B<X>::C', we would need to jump
+ // back into scope specifier parsing).
+ Sema::NameClassification Classification
+ = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
+ IsAddressOfOperand, SS.isEmpty() ? CCC : 0);
+
+ switch (Classification.getKind()) {
+ case Sema::NC_Error:
+ return ANK_Error;
+
+ case Sema::NC_Keyword:
+ // The identifier was typo-corrected to a keyword.
+ Tok.setIdentifierInfo(Name);
+ Tok.setKind(Name->getTokenID());
+ PP.TypoCorrectToken(Tok);
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ // We've "annotated" this as a keyword.
+ return ANK_Success;
+
+ case Sema::NC_Unknown:
+ // It's not something we know about. Leave it unannotated.
+ break;
+
+ case Sema::NC_Type:
+ Tok.setKind(tok::annot_typename);
+ setTypeAnnotation(Tok, Classification.getType());
+ Tok.setAnnotationEndLoc(NameLoc);
+ if (SS.isNotEmpty())
+ Tok.setLocation(SS.getBeginLoc());
+ PP.AnnotateCachedTokens(Tok);
+ return ANK_Success;
+
+ case Sema::NC_Expression:
+ Tok.setKind(tok::annot_primary_expr);
+ setExprAnnotation(Tok, Classification.getExpression());
+ Tok.setAnnotationEndLoc(NameLoc);
+ if (SS.isNotEmpty())
+ Tok.setLocation(SS.getBeginLoc());
+ PP.AnnotateCachedTokens(Tok);
+ return ANK_Success;
+
+ case Sema::NC_TypeTemplate:
+ if (Next.isNot(tok::less)) {
+ // This may be a type template being used as a template template argument.
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return ANK_TemplateName;
+ }
+ // Fall through.
+ case Sema::NC_FunctionTemplate: {
+ // We have a type or function template followed by '<'.
+ ConsumeToken();
+ UnqualifiedId Id;
+ Id.setIdentifier(Name, NameLoc);
+ if (AnnotateTemplateIdToken(
+ TemplateTy::make(Classification.getTemplateName()),
+ Classification.getTemplateNameKind(), SS, SourceLocation(), Id))
+ return ANK_Error;
+ return ANK_Success;
+ }
+
+ case Sema::NC_NestedNameSpecifier:
+ llvm_unreachable("already parsed nested name specifier");
+ }
+
+ // Unable to classify the name, but maybe we can annotate a scope specifier.
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return ANK_Unresolved;
+}
+
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
@@ -1377,8 +1535,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
return true;
}
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
@@ -1404,13 +1561,24 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
}
// Remembers whether the token was originally a scope annotation.
- bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+ bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus)
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
return true;
+ return TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, NeedType,
+ SS, !WasScopeAnnotation);
+}
+
+/// \brief Try to annotate a type or scope token, having already parsed an
+/// optional scope specifier. \p IsNewScope should be \c true unless the scope
+/// specifier was extracted from an existing tok::annot_cxxscope annotation.
+bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
+ bool NeedType,
+ CXXScopeSpec &SS,
+ bool IsNewScope) {
if (Tok.is(tok::identifier)) {
IdentifierInfo *CorrectedII = 0;
// Determine whether the identifier is a type name.
@@ -1492,21 +1660,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
return false;
// A C++ scope specifier that isn't followed by a typename.
- // Push the current token back into the token stream (or revert it if it is
- // cached) and use an annotation scope token for current token.
- if (PP.isBacktrackEnabled())
- PP.RevertCachedTokens(1);
- else
- PP.EnterToken(Tok);
- Tok.setKind(tok::annot_cxxscope);
- Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
- Tok.setAnnotationRange(SS.getRange());
-
- // In case the tokens were cached, have Preprocessor replace them
- // with the annotation token. We don't need to do this if we've
- // just reverted back to the state we were in before being called.
- if (!wasScopeAnnotation)
- PP.AnnotateCachedTokens(Tok);
+ AnnotateScopeToken(SS, IsNewScope);
return false;
}
@@ -1529,19 +1683,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
if (SS.isEmpty())
return false;
- // Push the current token back into the token stream (or revert it if it is
- // cached) and use an annotation scope token for current token.
- if (PP.isBacktrackEnabled())
- PP.RevertCachedTokens(1);
- else
- PP.EnterToken(Tok);
- Tok.setKind(tok::annot_cxxscope);
- Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
- Tok.setAnnotationRange(SS.getRange());
-
- // In case the tokens were cached, have Preprocessor replace them with the
- // annotation token.
- PP.AnnotateCachedTokens(Tok);
+ AnnotateScopeToken(SS, true);
return false;
}
@@ -1798,8 +1940,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() {
}
P.Diag(P.Tok, DID);
P.Diag(LOpen, diag::note_matching) << LHSName;
- if (P.SkipUntil(Close))
- LClose = P.Tok.getLocation();
+ if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true))
+ LClose = P.ConsumeAnyToken();
return true;
}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 455c4af2ffae..060fd206cd71 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -87,9 +87,8 @@ namespace clang {
Sema::ParsingDeclState State;
bool Popped;
- // Do not implement.
- ParsingDeclRAIIObject(const ParsingDeclRAIIObject &other);
- ParsingDeclRAIIObject &operator=(const ParsingDeclRAIIObject &other);
+ ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION;
+ void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION;
public:
enum NoParent_t { NoParent };
@@ -245,8 +244,9 @@ namespace clang {
/// the way they used to be. This is used to handle __extension__ in the
/// parser.
class ExtensionRAIIObject {
- void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
- ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
+ ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION;
+ void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION;
+
DiagnosticsEngine &Diags;
public:
ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index af8f6d4f90dd..d3d75430233f 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -1,33 +1,2 @@
-add_clang_library(clangRewrite
- DeltaTree.cpp
- FixItRewriter.cpp
- FrontendActions.cpp
- HTMLPrint.cpp
- HTMLRewrite.cpp
- InclusionRewriter.cpp
- RewriteMacros.cpp
- RewriteModernObjC.cpp
- RewriteObjC.cpp
- RewriteRope.cpp
- RewriteTest.cpp
- Rewriter.cpp
- TokenRewriter.cpp
- )
-
-add_dependencies(clangRewrite
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-
-target_link_libraries(clangRewrite
- clangBasic
- clangAST
- clangParse
- clangFrontend
- )
+add_subdirectory(Core)
+add_subdirectory(Frontend)
diff --git a/lib/Rewrite/Core/CMakeLists.txt b/lib/Rewrite/Core/CMakeLists.txt
new file mode 100644
index 000000000000..07978187ff19
--- /dev/null
+++ b/lib/Rewrite/Core/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_clang_library(clangRewriteCore
+ DeltaTree.cpp
+ HTMLRewrite.cpp
+ RewriteRope.cpp
+ Rewriter.cpp
+ TokenRewriter.cpp
+ )
+
+add_dependencies(clangRewriteCore
+ ClangAttrClasses
+ ClangAttrList
+ ClangAttrParsedAttrList
+ ClangCommentNodes
+ ClangDeclNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangRewriteCore
+ clangBasic
+ clangAST
+ clangParse
+ )
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/Core/DeltaTree.cpp
index 4297dc8de62f..46922772c5a2 100644
--- a/lib/Rewrite/DeltaTree.cpp
+++ b/lib/Rewrite/Core/DeltaTree.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/DeltaTree.h"
+#include "clang/Rewrite/Core/DeltaTree.h"
#include "clang/Basic/LLVM.h"
#include <cstring>
#include <cstdio>
@@ -113,8 +113,6 @@ namespace {
void RecomputeFullDeltaLocally();
void Destroy();
-
- //static inline bool classof(const DeltaTreeNode *) { return true; }
};
} // end anonymous namespace
@@ -149,7 +147,6 @@ namespace {
return Children[i];
}
- //static inline bool classof(const DeltaTreeInteriorNode *) { return true; }
static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
};
}
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/Core/HTMLRewrite.cpp
index 236b98fc2828..0e8e4fec9f4a 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/Core/HTMLRewrite.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/Rewriter.h"
-#include "clang/Rewrite/HTMLRewrite.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"
@@ -484,6 +484,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// Temporarily change the diagnostics object so that we ignore any generated
// diagnostics from this pass.
DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
+ &PP.getDiagnostics().getDiagnosticOptions(),
new IgnoringDiagConsumer);
// FIXME: This is a huge hack; we reuse the input preprocessor because we want
diff --git a/lib/Rewrite/Core/Makefile b/lib/Rewrite/Core/Makefile
new file mode 100644
index 000000000000..8c8d2e478135
--- /dev/null
+++ b/lib/Rewrite/Core/Makefile
@@ -0,0 +1,18 @@
+##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements code transformation / rewriting facilities.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangRewriteCore
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/Core/RewriteRope.cpp
index cc8de1b11a18..fe7aa2d6477d 100644
--- a/lib/Rewrite/RewriteRope.cpp
+++ b/lib/Rewrite/Core/RewriteRope.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/RewriteRope.h"
+#include "clang/Rewrite/Core/RewriteRope.h"
#include "clang/Basic/LLVM.h"
#include <algorithm>
using namespace clang;
@@ -117,8 +117,6 @@ namespace {
/// guaranteed that there is a split at Offset.
void erase(unsigned Offset, unsigned NumBytes);
- //static inline bool classof(const RopePieceBTreeNode *) { return true; }
-
};
} // end anonymous namespace
@@ -221,7 +219,6 @@ namespace {
/// guaranteed that there is a split at Offset.
void erase(unsigned Offset, unsigned NumBytes);
- //static inline bool classof(const RopePieceBTreeLeaf *) { return true; }
static inline bool classof(const RopePieceBTreeNode *N) {
return N->isLeaf();
}
@@ -458,7 +455,6 @@ namespace {
/// guaranteed that there is a split at Offset.
void erase(unsigned Offset, unsigned NumBytes);
- //static inline bool classof(const RopePieceBTreeInterior *) { return true; }
static inline bool classof(const RopePieceBTreeNode *N) {
return !N->isLeaf();
}
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp
index 7c27114f1cfd..4df967f39bc0 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Core/Rewriter.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/DiagnosticIDs.h"
diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/Core/TokenRewriter.cpp
index 03ce63ea1174..940ece2f9e03 100644
--- a/lib/Rewrite/TokenRewriter.cpp
+++ b/lib/Rewrite/Core/TokenRewriter.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/TokenRewriter.h"
+#include "clang/Rewrite/Core/TokenRewriter.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/ScratchBuffer.h"
#include "clang/Basic/SourceManager.h"
diff --git a/lib/Rewrite/Frontend/CMakeLists.txt b/lib/Rewrite/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..9017e479ab77
--- /dev/null
+++ b/lib/Rewrite/Frontend/CMakeLists.txt
@@ -0,0 +1,28 @@
+add_clang_library(clangRewriteFrontend
+ FixItRewriter.cpp
+ FrontendActions.cpp
+ HTMLPrint.cpp
+ InclusionRewriter.cpp
+ RewriteMacros.cpp
+ RewriteModernObjC.cpp
+ RewriteObjC.cpp
+ RewriteTest.cpp
+ )
+
+add_dependencies(clangRewriteFrontend
+ ClangAttrClasses
+ ClangAttrList
+ ClangAttrParsedAttrList
+ ClangCommentNodes
+ ClangDeclNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangRewriteFrontend
+ clangBasic
+ clangAST
+ clangParse
+ clangFrontend
+ )
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp
index 3863adb4f162..43a1ab1ac100 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/Frontend/FixItRewriter.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Basic/FileManager.h"
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp
index 9bc218e994fe..7d29b6d4219d 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/Frontend/FrontendActions.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/FrontendActions.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
@@ -16,9 +16,9 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Rewrite/ASTConsumers.h"
-#include "clang/Rewrite/FixItRewriter.h"
-#include "clang/Rewrite/Rewriters.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"
diff --git a/lib/Rewrite/HTMLPrint.cpp b/lib/Rewrite/Frontend/HTMLPrint.cpp
index 3d190abffcf8..79e44470ada5 100644
--- a/lib/Rewrite/HTMLPrint.cpp
+++ b/lib/Rewrite/Frontend/HTMLPrint.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/ASTConsumers.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -19,8 +19,8 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/HTMLRewrite.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Rewrite/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp
index 3dfc3b008987..9d1bec957d6d 100644
--- a/lib/Rewrite/InclusionRewriter.cpp
+++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriters.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
@@ -57,10 +57,11 @@ private:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
void WriteLineInfo(const char *Filename, int Line,
SrcMgr::CharacteristicKind FileType,
StringRef EOL, StringRef Extra = StringRef());
@@ -152,10 +153,11 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
const Token &/*IncludeTok*/,
StringRef /*FileName*/,
bool /*IsAngled*/,
+ CharSourceRange /*FilenameRange*/,
const FileEntry * /*File*/,
- SourceLocation /*EndLoc*/,
StringRef /*SearchPath*/,
- StringRef /*RelativePath*/) {
+ StringRef /*RelativePath*/,
+ const Module * /*Imported*/) {
assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion "
"directive was found before the previous one was processed");
std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert(
diff --git a/lib/Rewrite/Frontend/Makefile b/lib/Rewrite/Frontend/Makefile
new file mode 100644
index 000000000000..ac97d4074ecb
--- /dev/null
+++ b/lib/Rewrite/Frontend/Makefile
@@ -0,0 +1,18 @@
+##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements code transformation / rewriting facilities.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangRewriteFrontend
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Rewrite/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp
index 3fa0bdb74534..f399dd5d7ce9 100644
--- a/lib/Rewrite/RewriteMacros.cpp
+++ b/lib/Rewrite/Frontend/RewriteMacros.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriters.h"
-#include "clang/Rewrite/Rewriter.h"
+#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"
diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index dcd003f50160..4b56b3720a3f 100644
--- a/lib/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/ASTConsumers.h"
-#include "clang/Rewrite/Rewriter.h"
+#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/ParentMap.h"
@@ -278,6 +278,9 @@ namespace {
// Syntactic Rewriting.
void RewriteRecordBody(RecordDecl *RD);
void RewriteInclude();
+ void RewriteLineDirective(const Decl *D);
+ void ConvertSourceLocationToLineDirective(SourceLocation Loc,
+ std::string &LineString);
void RewriteForwardClassDecl(DeclGroupRef D);
void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
@@ -1602,6 +1605,19 @@ Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) {
return 0;
}
+void RewriteModernObjC::ConvertSourceLocationToLineDirective(
+ SourceLocation Loc,
+ std::string &LineString) {
+ if (Loc.isFileID()) {
+ LineString += "\n#line ";
+ PresumedLoc PLoc = SM->getPresumedLoc(Loc);
+ LineString += utostr(PLoc.getLine());
+ LineString += " \"";
+ LineString += Lexer::Stringify(PLoc.getFilename());
+ LineString += "\"\n";
+ }
+}
+
/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
/// statement to continue with its inner synthesized loop.
///
@@ -1664,7 +1680,10 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
StringRef elementName;
std::string elementTypeAsString;
std::string buf;
- buf = "\n{\n\t";
+ // line directive first.
+ SourceLocation ForEachLoc = S->getForLoc();
+ ConvertSourceLocationToLineDirective(ForEachLoc, buf);
+ buf += "{\n\t";
if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
// type elem;
NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl());
@@ -1836,7 +1855,9 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S)
assert((*startBuf == '@') && "bogus @synchronized location");
std::string buf;
- buf = "{ id _rethrow = 0; id _sync_obj = ";
+ SourceLocation SynchLoc = S->getAtSynchronizedLoc();
+ ConvertSourceLocationToLineDirective(SynchLoc, buf);
+ buf += "{ id _rethrow = 0; id _sync_obj = ";
const char *lparenBuf = startBuf;
while (*lparenBuf != '(') lparenBuf++;
@@ -1902,12 +1923,14 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt();
bool noCatch = S->getNumCatchStmts() == 0;
std::string buf;
+ SourceLocation TryLocation = S->getAtTryLoc();
+ ConvertSourceLocationToLineDirective(TryLocation, buf);
if (finalStmt) {
if (noCatch)
- buf = "{ id volatile _rethrow = 0;\n";
+ buf += "{ id volatile _rethrow = 0;\n";
else {
- buf = "{ id volatile _rethrow = 0;\ntry {\n";
+ buf += "{ id volatile _rethrow = 0;\ntry {\n";
}
}
// Get the start location and compute the semi location.
@@ -1934,13 +1957,15 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface();
if (IDecl) {
std::string Result;
+ ConvertSourceLocationToLineDirective(Catch->getLocStart(), Result);
+
startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @catch location");
SourceLocation rParenLoc = Catch->getRParenLoc();
const char *rParenBuf = SM->getCharacterData(rParenLoc);
// _objc_exc_Foo *_e as argument to catch.
- Result = "catch (_objc_exc_"; Result += IDecl->getNameAsString();
+ Result += "catch (_objc_exc_"; Result += IDecl->getNameAsString();
Result += " *_"; Result += catchDecl->getNameAsString();
Result += ")";
ReplaceText(startLoc, rParenBuf-startBuf+1, Result);
@@ -1966,11 +1991,18 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
if (finalStmt) {
buf.clear();
- if (noCatch)
- buf = "catch (id e) {_rethrow = e;}\n";
- else
- buf = "}\ncatch (id e) {_rethrow = e;}\n";
-
+ SourceLocation FinallyLoc = finalStmt->getLocStart();
+
+ if (noCatch) {
+ ConvertSourceLocationToLineDirective(FinallyLoc, buf);
+ buf += "catch (id e) {_rethrow = e;}\n";
+ }
+ else {
+ buf += "}\n";
+ ConvertSourceLocationToLineDirective(FinallyLoc, buf);
+ buf += "catch (id e) {_rethrow = e;}\n";
+ }
+
SourceLocation startFinalLoc = finalStmt->getLocStart();
ReplaceText(startFinalLoc, 8, buf);
Stmt *body = finalStmt->getFinallyBody();
@@ -2070,7 +2102,7 @@ CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl(
const FunctionType *FT = msgSendType->getAs<FunctionType>();
CallExpr *Exp =
- new (Context) CallExpr(*Context, ICE, args, nargs,
+ new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs),
FT->getCallResultType(*Context),
VK_RValue, EndLoc);
return Exp;
@@ -2675,8 +2707,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
ReplaceStmt(Exp, CE);
@@ -2718,7 +2749,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
for (unsigned i = 0; i < NumElements; i++)
InitExprs.push_back(Exp->getElement(i));
Expr *NSArrayCallExpr =
- new (Context) CallExpr(*Context, NSArrayDRE, &InitExprs[0], InitExprs.size(),
+ new (Context) CallExpr(*Context, NSArrayDRE, InitExprs,
NSArrayFType, VK_LValue, SourceLocation());
FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
@@ -2814,8 +2845,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
ReplaceStmt(Exp, CE);
@@ -2865,7 +2895,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// (const id [])objects
Expr *NSValueCallExpr =
- new (Context) CallExpr(*Context, NSDictDRE, &ValueExprs[0], ValueExprs.size(),
+ new (Context) CallExpr(*Context, NSDictDRE, ValueExprs,
NSDictFType, VK_LValue, SourceLocation());
FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
@@ -2887,7 +2917,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
DictLiteralValueME);
// (const id <NSCopying> [])keys
Expr *NSKeyCallExpr =
- new (Context) CallExpr(*Context, NSDictDRE, &KeyExprs[0], KeyExprs.size(),
+ new (Context) CallExpr(*Context, NSDictDRE, KeyExprs,
NSDictFType, VK_LValue, SourceLocation());
MemberExpr *DictLiteralKeyME =
@@ -2989,8 +3019,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
ReplaceStmt(Exp, CE);
@@ -3078,6 +3107,34 @@ static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R,
return FD->getTypeSpecStartLoc();
}
+void RewriteModernObjC::RewriteLineDirective(const Decl *D) {
+
+ SourceLocation Location = D->getLocation();
+
+ if (Location.isFileID()) {
+ std::string LineString("\n#line ");
+ PresumedLoc PLoc = SM->getPresumedLoc(Location);
+ LineString += utostr(PLoc.getLine());
+ LineString += " \"";
+ LineString += Lexer::Stringify(PLoc.getFilename());
+ if (isa<ObjCMethodDecl>(D))
+ LineString += "\"";
+ else LineString += "\"\n";
+
+ Location = D->getLocStart();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isExternC() && !FD->isMain()) {
+ const DeclContext *DC = FD->getDeclContext();
+ if (const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(DC))
+ // if it is extern "C" {...}, return function decl's own location.
+ if (!LSD->getRBraceLoc().isValid())
+ Location = LSD->getExternLoc();
+ }
+ }
+ InsertText(Location, LineString);
+ }
+}
+
/// SynthMsgSendStretCallExpr - This routine translates message expression
/// into a call to objc_msgSend_stret() entry point. Tricky part is that
/// nil check on receiver must be performed before calling objc_msgSend_stret.
@@ -3140,7 +3197,14 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy());
str += " s;\n";
str += "};\n\n";
- SourceLocation FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef);
+ SourceLocation FunLocStart;
+ if (CurFunctionDef)
+ FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef);
+ else {
+ assert(CurMethodDef && "SynthMsgSendStretCallExpr - CurMethodDef is null");
+ FunLocStart = CurMethodDef->getLocStart();
+ }
+
InsertText(FunLocStart, str);
++stretCount;
@@ -3151,7 +3215,7 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
SC_None, false, false);
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue,
SourceLocation());
- CallExpr *STCE = new (Context) CallExpr(*Context, DRE, &MsgExprs[0], MsgExprs.size(),
+ CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs,
castType, VK_LValue, SourceLocation());
FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(),
@@ -3260,8 +3324,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue,
SourceLocation());
// The code for super is a little tricky to prevent collision with
@@ -3280,8 +3343,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct __rw_objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -3370,8 +3432,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
@@ -3389,8 +3450,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct __rw_objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -3544,10 +3604,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
- FT->getResultType(), VK_RValue,
- EndLoc);
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
+ FT->getResultType(), VK_RValue, EndLoc);
Stmt *ReplacingStmt = CE;
if (MsgSendStretFlavor) {
// We have the method which returns a struct/union. Must also generate
@@ -3578,7 +3636,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation());
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
- VK_RValue, OK_Ordinary, SourceLocation());
+ VK_RValue, OK_Ordinary, SourceLocation(),
+ false);
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -3968,8 +4027,12 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
const FunctionType *AFT = CE->getFunctionType();
QualType RT = AFT->getResultType();
std::string StructRef = "struct " + Tag;
- std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
- funcName.str() + "_block_func_" + utostr(i);
+ SourceLocation BlockLoc = CE->getExprLoc();
+ std::string S;
+ ConvertSourceLocationToLineDirective(BlockLoc, S);
+
+ S += "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
+ funcName.str() + "_block_func_" + utostr(i);
BlockDecl *BD = CE->getBlockDecl();
@@ -4585,8 +4648,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
E = Exp->arg_end(); I != E; ++I) {
BlkExprs.push_back(*I);
}
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
- BlkExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs,
Exp->getType(), VK_RValue,
SourceLocation());
return CE;
@@ -4869,7 +4931,7 @@ void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
else if (*argListBegin == '<') {
buf += "/*";
buf += *argListBegin++;
- OrigLength++;;
+ OrigLength++;
while (*argListBegin != '>') {
buf += *argListBegin++;
OrigLength++;
@@ -5347,7 +5409,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
Context->IntTy, SourceLocation());
InitExprs.push_back(FlagExp);
}
- NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ NewRep = new (Context) CallExpr(*Context, DRE, InitExprs,
FType, VK_LValue, SourceLocation());
if (GlobalBlockExpr) {
@@ -5666,6 +5728,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
// This synthesizes and inserts the block "impl" struct, invoke function,
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
+ RewriteLineDirective(D);
CurFunctionDef = 0;
}
break;
@@ -5684,6 +5747,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
PropParentMap = 0;
}
InsertBlockLiteralsWithinMethod(MD);
+ RewriteLineDirective(D);
CurMethodDef = 0;
}
break;
@@ -5894,8 +5958,8 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += "(const char *);\n";
Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);\n";
// @synchronized hooks.
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter( struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit( struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);\n";
Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
Preamble += "struct __objcFastEnumerationState {\n\t";
@@ -7476,7 +7540,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BinaryOperator *addExpr =
new (Context) BinaryOperator(castExpr, DRE, BO_Add,
Context->getPointerType(Context->CharTy),
- VK_RValue, OK_Ordinary, SourceLocation());
+ VK_RValue, OK_Ordinary, SourceLocation(), false);
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
SourceLocation(),
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index 37c17e63db94..a6dcc6b8d804 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/ASTConsumers.h"
-#include "clang/Rewrite/Rewriter.h"
+#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/ParentMap.h"
@@ -2059,7 +2059,7 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
const FunctionType *FT = msgSendType->getAs<FunctionType>();
CallExpr *Exp =
- new (Context) CallExpr(*Context, ICE, args, nargs,
+ new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs),
FT->getCallResultType(*Context),
VK_RValue, EndLoc);
return Exp;
@@ -2661,8 +2661,7 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *STCE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
SourceLocation());
return STCE;
@@ -2766,8 +2765,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue,
SourceLocation());
// The code for super is a little tricky to prevent collision with
@@ -2786,8 +2784,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -2876,8 +2873,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
@@ -2895,8 +2891,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -3050,8 +3045,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
Stmt *ReplacingStmt = CE;
@@ -3084,7 +3078,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation());
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
- VK_RValue, OK_Ordinary, SourceLocation());
+ VK_RValue, OK_Ordinary, SourceLocation(),
+ false);
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -3923,8 +3918,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
E = Exp->arg_end(); I != E; ++I) {
BlkExprs.push_back(*I);
}
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
- BlkExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs,
Exp->getType(), VK_RValue,
SourceLocation());
return CE;
@@ -4190,7 +4184,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
else if (*argListBegin == '<') {
buf += "/*";
buf += *argListBegin++;
- OrigLength++;;
+ OrigLength++;
while (*argListBegin != '>') {
buf += *argListBegin++;
OrigLength++;
@@ -4651,7 +4645,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
Context->IntTy, SourceLocation());
InitExprs.push_back(FlagExp);
}
- NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ NewRep = new (Context) CallExpr(*Context, DRE, InitExprs,
FType, VK_LValue, SourceLocation());
NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
Context->getPointerType(NewRep->getType()),
@@ -5119,8 +5113,8 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) {
Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
Preamble += "(struct objc_class *, struct objc_object *);\n";
// @synchronized hooks.
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit(struct objc_object *);\n";
Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
Preamble += "struct __objcFastEnumerationState {\n\t";
diff --git a/lib/Rewrite/RewriteTest.cpp b/lib/Rewrite/Frontend/RewriteTest.cpp
index 019e5e73120d..722c5e80b443 100644
--- a/lib/Rewrite/RewriteTest.cpp
+++ b/lib/Rewrite/Frontend/RewriteTest.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriters.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/TokenRewriter.h"
+#include "clang/Rewrite/Core/TokenRewriter.h"
#include "llvm/Support/raw_ostream.h"
void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) {
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
index 5fef9b2c0d38..0be84d406405 100644
--- a/lib/Rewrite/Makefile
+++ b/lib/Rewrite/Makefile
@@ -1,4 +1,4 @@
-##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+##===- clang/lib/StaticAnalyzer/Makefile -------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -6,13 +6,9 @@
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
-#
-# This implements code transformation / rewriting facilities.
-#
-##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../..
-LIBRARYNAME := clangRewrite
+DIRS := Frontend
+PARALLEL_DIRS := Core
include $(CLANG_LEVEL)/Makefile
-
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 19a7d6f35c8f..801a1b1e0264 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/AnalysisContext.h"
@@ -36,10 +37,12 @@
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.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"
@@ -182,13 +185,6 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
HasFakeEdge = true;
continue;
}
- if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
- if (AS->isMSAsm()) {
- HasFakeEdge = true;
- HasLiveReturn = true;
- continue;
- }
- }
if (isa<MSAsmStmt>(S)) {
// TODO: Verify this is correct.
HasFakeEdge = true;
@@ -506,7 +502,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
// Information used when building the diagnostic.
unsigned DiagKind;
- const char *Str;
+ StringRef Str;
SourceRange Range;
// FixIts to suppress the diagnosic by removing the dead condition.
@@ -822,6 +818,18 @@ namespace {
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
+ // Only perform this analysis when using C++11. There is no good workflow
+ // for this warning when not using C++11. There is no good way to silence
+ // the warning (no attribute is available) unless we are using C++11's support
+ // for generalized attributes. Once could use pragmas to silence the warning,
+ // but as a general solution that is gross and not in the spirit of this
+ // warning.
+ //
+ // 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)
+ return;
+
FallthroughMapper FM(S);
FM.TraverseStmt(AC.getBody());
@@ -859,8 +867,21 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
if (S.getLangOpts().CPlusPlus0x) {
const Stmt *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"),
+ tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+ StringRef AnnotationSpelling = "[[clang::fallthrough]]";
+ StringRef MacroName = PP.getLastMacroWithSpelling(L, Tokens);
+ if (!MacroName.empty())
+ AnnotationSpelling = MacroName;
+ SmallString<64> TextToInsert(AnnotationSpelling);
+ TextToInsert += "; ";
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
- FixItHint::CreateInsertion(L, "[[clang::fallthrough]]; ");
+ AnnotationSpelling <<
+ FixItHint::CreateInsertion(L, TextToInsert);
}
}
S.Diag(L, diag::note_insert_break_fixit) <<
@@ -878,6 +899,199 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
namespace {
+typedef std::pair<const Stmt *,
+ sema::FunctionScopeInfo::WeakObjectUseMap::const_iterator>
+ StmtUsesPair;
+
+class StmtUseSorter {
+ const SourceManager &SM;
+
+public:
+ explicit StmtUseSorter(const SourceManager &SM) : SM(SM) { }
+
+ bool operator()(const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(),
+ RHS.first->getLocStart());
+ }
+};
+}
+
+static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
+ const Stmt *S) {
+ assert(S);
+
+ do {
+ switch (S->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ return true;
+ case Stmt::DoStmtClass: {
+ const Expr *Cond = cast<DoStmt>(S)->getCond();
+ llvm::APSInt Val;
+ if (!Cond->EvaluateAsInt(Val, Ctx))
+ return true;
+ return Val.getBoolValue();
+ }
+ default:
+ break;
+ }
+ } while ((S = PM.getParent(S)));
+
+ return false;
+}
+
+
+static void diagnoseRepeatedUseOfWeak(Sema &S,
+ const sema::FunctionScopeInfo *CurFn,
+ const Decl *D,
+ const ParentMap &PM) {
+ typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
+ typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
+ typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
+
+ ASTContext &Ctx = S.getASTContext();
+
+ const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses();
+
+ // Extract all weak objects that are referenced more than once.
+ SmallVector<StmtUsesPair, 8> UsesByStmt;
+ for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
+ I != E; ++I) {
+ const WeakUseVector &Uses = I->second;
+
+ // Find the first read of the weak object.
+ WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
+ for ( ; UI != UE; ++UI) {
+ if (UI->isUnsafe())
+ break;
+ }
+
+ // If there were only writes to this object, don't warn.
+ if (UI == UE)
+ continue;
+
+ // If there was only one read, followed by any number of writes, and the
+ // read is not within a loop, don't warn. Additionally, don't warn in a
+ // loop if the base object is a local variable -- local variables are often
+ // changed in loops.
+ if (UI == Uses.begin()) {
+ WeakUseVector::const_iterator UI2 = UI;
+ for (++UI2; UI2 != UE; ++UI2)
+ if (UI2->isUnsafe())
+ break;
+
+ if (UI2 == UE) {
+ if (!isInLoop(Ctx, PM, UI->getUseExpr()))
+ continue;
+
+ const WeakObjectProfileTy &Profile = I->first;
+ if (!Profile.isExactProfile())
+ continue;
+
+ const NamedDecl *Base = Profile.getBase();
+ if (!Base)
+ Base = Profile.getProperty();
+ assert(Base && "A profile always has a base or property.");
+
+ if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base))
+ if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base))
+ continue;
+ }
+ }
+
+ UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
+ }
+
+ if (UsesByStmt.empty())
+ return;
+
+ // Sort by first use so that we emit the warnings in a deterministic order.
+ std::sort(UsesByStmt.begin(), UsesByStmt.end(),
+ StmtUseSorter(S.getSourceManager()));
+
+ // Classify the current code body for better warning text.
+ // This enum should stay in sync with the cases in
+ // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
+ // FIXME: Should we use a common classification enum and the same set of
+ // possibilities all throughout Sema?
+ enum {
+ Function,
+ Method,
+ Block,
+ Lambda
+ } FunctionKind;
+
+ if (isa<sema::BlockScopeInfo>(CurFn))
+ FunctionKind = Block;
+ else if (isa<sema::LambdaScopeInfo>(CurFn))
+ FunctionKind = Lambda;
+ else if (isa<ObjCMethodDecl>(D))
+ FunctionKind = Method;
+ else
+ FunctionKind = Function;
+
+ // Iterate through the sorted problems and emit warnings for each.
+ for (SmallVectorImpl<StmtUsesPair>::const_iterator I = UsesByStmt.begin(),
+ E = UsesByStmt.end();
+ I != E; ++I) {
+ const Stmt *FirstRead = I->first;
+ const WeakObjectProfileTy &Key = I->second->first;
+ const WeakUseVector &Uses = I->second->second;
+
+ // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy
+ // may not contain enough information to determine that these are different
+ // properties. We can only be 100% sure of a repeated use in certain cases,
+ // and we adjust the diagnostic kind accordingly so that the less certain
+ // case can be turned off if it is too noisy.
+ unsigned DiagKind;
+ if (Key.isExactProfile())
+ DiagKind = diag::warn_arc_repeated_use_of_weak;
+ else
+ DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
+
+ // Classify the weak object being accessed for better warning text.
+ // This enum should stay in sync with the cases in
+ // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
+ enum {
+ Variable,
+ Property,
+ ImplicitProperty,
+ Ivar
+ } ObjectKind;
+
+ const NamedDecl *D = Key.getProperty();
+ if (isa<VarDecl>(D))
+ ObjectKind = Variable;
+ else if (isa<ObjCPropertyDecl>(D))
+ ObjectKind = Property;
+ else if (isa<ObjCMethodDecl>(D))
+ ObjectKind = ImplicitProperty;
+ else if (isa<ObjCIvarDecl>(D))
+ ObjectKind = Ivar;
+ else
+ llvm_unreachable("Unexpected weak object kind!");
+
+ // Show the first time the object was read.
+ S.Diag(FirstRead->getLocStart(), DiagKind)
+ << ObjectKind << D << FunctionKind
+ << FirstRead->getSourceRange();
+
+ // Print all the other accesses as notes.
+ for (WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
+ UI != UE; ++UI) {
+ if (UI->getUseExpr() == FirstRead)
+ continue;
+ S.Diag(UI->getUseExpr()->getLocStart(),
+ diag::note_arc_weak_also_accessed_here)
+ << UI->getUseExpr()->getSourceRange();
+ }
+ }
+}
+
+
+namespace {
struct SLocSort {
bool operator()(const UninitUse &a, const UninitUse &b) {
// Prefer a more confident report over a less confident one.
@@ -1091,27 +1305,47 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
diag::warn_variable_requires_any_lock:
diag::warn_var_deref_requires_any_lock;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D->getName() << getLockKindFromAccessKind(AK));
+ << D->getNameAsString() << getLockKindFromAccessKind(AK));
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
- Name LockName, LockKind LK, SourceLocation Loc) {
+ Name LockName, LockKind LK, SourceLocation Loc,
+ Name *PossibleMatch) {
unsigned DiagID = 0;
- switch (POK) {
- case POK_VarAccess:
- DiagID = diag::warn_variable_requires_lock;
- break;
- case POK_VarDereference:
- DiagID = diag::warn_var_deref_requires_lock;
- break;
- case POK_FunctionCall:
- DiagID = diag::warn_fun_requires_lock;
- break;
+ if (PossibleMatch) {
+ switch (POK) {
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock_precise;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock_precise;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock_precise;
+ break;
+ }
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << D->getNameAsString() << LockName << LK);
+ PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
+ << *PossibleMatch);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ } else {
+ switch (POK) {
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock;
+ break;
+ }
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << D->getNameAsString() << LockName << LK);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D->getName() << LockName << LK);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
@@ -1206,7 +1440,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
AC.getCFGBuildOptions().AddEHEdges = false;
AC.getCFGBuildOptions().AddInitializers = true;
AC.getCFGBuildOptions().AddImplicitDtors = true;
-
+ AC.getCFGBuildOptions().AddTemporaryDtors = true;
+
// Force that certain expressions appear as CFGElements in the CFG. This
// is used to speed up various analyses.
// FIXME: This isn't the right factoring. This is here for initial
@@ -1350,6 +1585,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
}
+ if (S.getLangOpts().ObjCARCWeak &&
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ D->getLocStart()) != DiagnosticsEngine::Ignored)
+ diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
+
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 46dfa05adec1..7cfe3ae8462c 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -13,7 +13,9 @@ add_clang_library(clangSema
DelayedDiagnostic.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
+ MultiplexExternalSemaSource.cpp
Scope.cpp
+ ScopeInfo.cpp
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
@@ -39,6 +41,7 @@ add_clang_library(clangSema
SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp
+ SemaStmtAsm.cpp
SemaStmtAttr.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index a8357255343d..0a236018bdfd 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -193,11 +193,10 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks,
CXAvailabilityKind Availability,
const char **Annotations,
unsigned NumAnnotations,
- CXCursorKind ParentKind,
StringRef ParentName,
const char *BriefComment)
: NumChunks(NumChunks), NumAnnotations(NumAnnotations),
- Priority(Priority), Availability(Availability), ParentKind(ParentKind),
+ Priority(Priority), Availability(Availability),
ParentName(ParentName), BriefComment(BriefComment)
{
assert(NumChunks <= 0xffff);
@@ -339,7 +338,7 @@ CodeCompletionString *CodeCompletionBuilder::TakeString() {
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
Priority, Availability,
Annotations.data(), Annotations.size(),
- ParentKind, ParentName, BriefComment);
+ ParentName, BriefComment);
Chunks.clear();
return Result;
}
@@ -380,7 +379,6 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (DC->isTranslationUnit()) {
- ParentKind = CXCursor_TranslationUnit;
return;
}
@@ -391,7 +389,6 @@ void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (!ND)
return;
- ParentKind = getCursorKindForDecl(ND);
ParentName = getCodeCompletionTUInfo().getParentName(DC);
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index d12ca7839095..b3066eb08013 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -144,11 +144,13 @@ CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
-DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
bool isAmbiguous,
- SourceLocation EllipsisLoc,
+ SourceLocation LParenLoc,
ParamInfo *ArgInfo,
unsigned NumArgs,
+ SourceLocation EllipsisLoc,
+ SourceLocation RParenLoc,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
@@ -173,9 +175,11 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.EndLoc = LocalRangeEnd;
I.Fun.AttrList = 0;
I.Fun.hasPrototype = hasProto;
- I.Fun.isVariadic = isVariadic;
+ I.Fun.isVariadic = EllipsisLoc.isValid();
I.Fun.isAmbiguous = isAmbiguous;
+ I.Fun.LParenLoc = LParenLoc.getRawEncoding();
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ I.Fun.RParenLoc = RParenLoc.getRawEncoding();
I.Fun.DeleteArgInfo = false;
I.Fun.TypeQuals = TypeQuals;
I.Fun.NumArgs = NumArgs;
@@ -270,6 +274,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_int:
case TST_int128:
case TST_struct:
+ case TST_interface:
case TST_union:
case TST_unknown_anytype:
case TST_unspecified:
@@ -325,10 +330,14 @@ unsigned DeclSpec::getParsedSpecifiers() const {
template <class T> static bool BadSpecifier(T TNew, T TPrev,
const char *&PrevSpec,
- unsigned &DiagID) {
+ unsigned &DiagID,
+ bool IsExtension = true) {
PrevSpec = DeclSpec::getSpecifierName(TPrev);
- DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec
- : diag::err_invalid_decl_spec_combination);
+ if (TNew != TPrev)
+ DiagID = diag::err_invalid_decl_spec_combination;
+ else
+ DiagID = IsExtension ? diag::ext_duplicate_declspec :
+ diag::warn_duplicate_declspec;
return true;
}
@@ -396,6 +405,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_class: return "class";
case DeclSpec::TST_union: return "union";
case DeclSpec::TST_struct: return "struct";
+ case DeclSpec::TST_interface: return "__interface";
case DeclSpec::TST_typename: return "type-name";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
@@ -670,12 +680,16 @@ bool DeclSpec::SetTypeSpecError() {
}
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID, const LangOptions &Lang,
- bool IsTypeSpec) {
- // Duplicates are permitted in C99, and are permitted in C++11 unless the
- // cv-qualifier appears as a type-specifier.
- if ((TypeQualifiers & T) && !Lang.C99 && (!Lang.CPlusPlus0x || IsTypeSpec))
- return BadSpecifier(T, T, PrevSpec, DiagID);
+ unsigned &DiagID, const LangOptions &Lang) {
+ // Duplicates are permitted in C99, but are not permitted in C++. However,
+ // since this is likely not what the user intended, we will always warn. We
+ // do not need to set the qualifier's location since we already have it.
+ if (TypeQualifiers & T) {
+ bool IsExtension = true;
+ if (Lang.C99)
+ IsExtension = false;
+ return BadSpecifier(T, T, PrevSpec, DiagID, IsExtension);
+ }
TypeQualifiers |= T;
switch (T) {
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index 876f9d7a9545..310043288554 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -22,6 +22,7 @@ using namespace sema;
DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
const NamedDecl *D,
const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
StringRef Msg) {
DelayedDiagnostic DD;
DD.Kind = Deprecation;
@@ -29,6 +30,7 @@ DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
DD.Loc = Loc;
DD.DeprecationData.Decl = D;
DD.DeprecationData.UnknownObjCClass = UnknownObjCClass;
+ DD.DeprecationData.ObjCProperty = ObjCProperty;
char *MessageData = 0;
if (Msg.size()) {
MessageData = new char [Msg.size()];
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 4d62cab16765..00939151c673 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -135,8 +135,16 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
// of the controlled statement.
//
assert(S->getParent() && "No TUScope?");
- if (S->getParent()->getFlags() & Scope::ControlScope)
+ if (S->getFlags() & Scope::FnTryScope)
return S->getParent()->isDeclScope(D);
+ if (S->getParent()->getFlags() & Scope::ControlScope) {
+ if (S->getParent()->getFlags() & Scope::FnCatchScope) {
+ S = S->getParent();
+ if (S->isDeclScope(D))
+ return true;
+ }
+ return S->getParent()->isDeclScope(D);
+ }
}
return false;
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index ab786c65aab9..e2ec1ccebdcf 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -123,7 +123,7 @@ typedef std::pair<unsigned,unsigned> ScopePair;
/// diagnostic that should be emitted if control goes over it. If not, return 0.
static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- unsigned InDiag = 0, OutDiag = 0;
+ unsigned InDiag = 0;
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
@@ -164,43 +164,53 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
// where it is in scope is ill-formed unless the variable has
// POD type and is declared without an initializer.
- if (const Expr *init = VD->getInit()) {
- // We actually give variables of record type (or array thereof)
- // an initializer even if that initializer only calls a trivial
- // ctor. Detect that case.
- // FIXME: With generalized initializer lists, this may
- // classify "X x{};" as having no initializer.
- unsigned inDiagToUse = diag::note_protected_by_variable_init;
-
- const CXXRecordDecl *record = 0;
-
- if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
- const CXXConstructorDecl *ctor = cce->getConstructor();
- record = ctor->getParent();
-
- if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
- if (!record->hasTrivialDestructor())
- inDiagToUse = diag::note_protected_by_variable_nontriv_destructor;
- else if (!record->isPOD())
- inDiagToUse = diag::note_protected_by_variable_non_pod;
- else
- inDiagToUse = 0;
- }
- } else if (VD->getType()->isArrayType()) {
- record = VD->getType()->getBaseElementTypeUnsafe()
- ->getAsCXXRecordDecl();
+ const Expr *Init = VD->getInit();
+ if (!Init)
+ return ScopePair(InDiag, 0);
+
+ const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init);
+ if (EWC)
+ Init = EWC->getSubExpr();
+
+ const MaterializeTemporaryExpr *M = NULL;
+ Init = Init->findMaterializedTemporary(M);
+
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ Init = Init->skipRValueSubobjectAdjustments(Adjustments);
+
+ QualType QT = Init->getType();
+ if (QT.isNull())
+ return ScopePair(diag::note_protected_by_variable_init, 0);
+
+ const Type *T = QT.getTypePtr();
+ if (T->isArrayType())
+ T = T->getBaseElementTypeUnsafe();
+
+ const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+ if (!Record)
+ return ScopePair(diag::note_protected_by_variable_init, 0);
+
+ // If we need to call a non trivial destructor for this variable,
+ // record an out diagnostic.
+ unsigned OutDiag = 0;
+ if (!Init->isGLValue() && !Record->hasTrivialDestructor())
+ OutDiag = diag::note_exits_dtor;
+
+ if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
+ const CXXConstructorDecl *ctor = cce->getConstructor();
+ if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+ if (OutDiag)
+ InDiag = diag::note_protected_by_variable_nontriv_destructor;
+ else if (!Record->isPOD())
+ InDiag = diag::note_protected_by_variable_non_pod;
+ return ScopePair(InDiag, OutDiag);
}
-
- if (inDiagToUse)
- InDiag = inDiagToUse;
-
- // Also object to indirect jumps which leave scopes with dtors.
- if (record && !record->hasTrivialDestructor())
- OutDiag = diag::note_exits_dtor;
}
+
+ return ScopePair(diag::note_protected_by_variable_init, OutDiag);
}
-
- return ScopePair(InDiag, OutDiag);
+
+ return ScopePair(InDiag, 0);
}
if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
@@ -322,6 +332,29 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
Jumps.push_back(S);
break;
+ case Stmt::CXXTryStmtClass: {
+ CXXTryStmt *TS = cast<CXXTryStmt>(S);
+ unsigned newParentScope;
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_try,
+ diag::note_exits_cxx_try,
+ TS->getSourceRange().getBegin()));
+ if (Stmt *TryBlock = TS->getTryBlock())
+ BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
+
+ // Jump from the catch into the try is not allowed either.
+ for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
+ CXXCatchStmt *CS = TS->getHandler(I);
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_catch,
+ diag::note_exits_cxx_catch,
+ CS->getSourceRange().getBegin()));
+ BuildScopeInformation(CS->getHandlerBlock(),
+ (newParentScope = Scopes.size()-1));
+ }
+ return;
+ }
+
default:
break;
}
@@ -418,30 +451,6 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
continue;
}
- // Disallow jumps into any part of a C++ try statement. This is pretty
- // much the same as for Obj-C.
- if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_cxx_try,
- diag::note_exits_cxx_try,
- TS->getSourceRange().getBegin()));
- if (Stmt *TryBlock = TS->getTryBlock())
- BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
-
- // Jump from the catch into the try is not allowed either.
- for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
- CXXCatchStmt *CS = TS->getHandler(I);
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_cxx_catch,
- diag::note_exits_cxx_catch,
- CS->getSourceRange().getBegin()));
- BuildScopeInformation(CS->getHandlerBlock(),
- (newParentScope = Scopes.size()-1));
- }
-
- continue;
- }
-
// Disallow jumps into the protected statement of an @autoreleasepool.
if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
// Recursively walk the AST for the @autoreleasepool part, protected by a new
@@ -453,14 +462,19 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1));
continue;
}
-
- if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) {
- const BlockDecl *BDecl = BE->getBlockDecl();
+
+ // Disallow jumps past full-expressions that use blocks with
+ // non-trivial cleanups of their captures. This is theoretically
+ // implementable but a lot of work which we haven't felt up to doing.
+ if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) {
+ for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
+ const BlockDecl *BDecl = EWC->getObject(i);
for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(),
ce = BDecl->capture_end(); ci != ce; ++ci) {
VarDecl *variable = ci->getVariable();
BuildScopeInformation(variable, BDecl, ParentScope);
}
+ }
}
// Recursively walk the AST.
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
new file mode 100644
index 000000000000..f930fb348a25
--- /dev/null
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -0,0 +1,271 @@
+//===--- MultiplexExternalSemaSource.cpp ---------------------------------===//
+//
+// 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 event dispatching to the subscribed clients.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/Sema/Lookup.h"
+
+using namespace clang;
+
+///\brief Constructs a new multiplexing external sema source and appends the
+/// given element to it.
+///
+///\param[in] source - An ExternalSemaSource.
+///
+MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1,
+ ExternalSemaSource &s2){
+ Sources.push_back(&s1);
+ Sources.push_back(&s2);
+}
+
+// pin the vtable here.
+MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {}
+
+///\brief Appends new source to the source list.
+///
+///\param[in] source - An ExternalSemaSource.
+///
+void MultiplexExternalSemaSource::addSource(ExternalSemaSource &source) {
+ Sources.push_back(&source);
+}
+
+//===----------------------------------------------------------------------===//
+// ExternalASTSource.
+//===----------------------------------------------------------------------===//
+
+Decl *MultiplexExternalSemaSource::GetExternalDecl(uint32_t ID) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (Decl *Result = Sources[i]->GetExternalDecl(ID))
+ return Result;
+ return 0;
+}
+
+Selector MultiplexExternalSemaSource::GetExternalSelector(uint32_t ID) {
+ Selector Sel;
+ for(size_t i = 0; i < Sources.size(); ++i) {
+ Sel = Sources[i]->GetExternalSelector(ID);
+ if (!Sel.isNull())
+ return Sel;
+ }
+ return Sel;
+}
+
+uint32_t MultiplexExternalSemaSource::GetNumExternalSelectors() {
+ uint32_t total = 0;
+ for(size_t i = 0; i < Sources.size(); ++i)
+ total += Sources[i]->GetNumExternalSelectors();
+ return total;
+}
+
+Stmt *MultiplexExternalSemaSource::GetExternalDeclStmt(uint64_t Offset) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
+ return Result;
+ return 0;
+}
+
+CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
+ uint64_t Offset){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (CXXBaseSpecifier *R = Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
+ return R;
+ return 0;
+}
+
+DeclContextLookupResult 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();
+}
+
+void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->completeVisibleDeclsMap(DC);
+}
+
+ExternalLoadResult MultiplexExternalSemaSource::
+FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Result) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ // FIXME: The semantics of the return result is unclear to me...
+ Sources[i]->FindExternalLexicalDecls(DC, isKindWeWant, Result);
+
+ return ELR_Success;
+}
+
+void MultiplexExternalSemaSource::FindFileRegionDecls(FileID File,
+ unsigned Offset,
+ unsigned Length,
+ SmallVectorImpl<Decl *> &Decls){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls);
+}
+
+void MultiplexExternalSemaSource::CompleteType(TagDecl *Tag) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteType(Tag);
+}
+
+void MultiplexExternalSemaSource::CompleteType(ObjCInterfaceDecl *Class) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteType(Class);
+}
+
+void MultiplexExternalSemaSource::ReadComments() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadComments();
+}
+
+void MultiplexExternalSemaSource::StartedDeserializing() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartedDeserializing();
+}
+
+void MultiplexExternalSemaSource::FinishedDeserializing() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FinishedDeserializing();
+}
+
+void MultiplexExternalSemaSource::StartTranslationUnit(ASTConsumer *Consumer) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartTranslationUnit(Consumer);
+}
+
+void MultiplexExternalSemaSource::PrintStats() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->PrintStats();
+}
+
+bool MultiplexExternalSemaSource::layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets))
+ return true;
+ return false;
+}
+
+void MultiplexExternalSemaSource::
+getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->getMemoryBufferSizes(sizes);
+
+}
+
+//===----------------------------------------------------------------------===//
+// ExternalSemaSource.
+//===----------------------------------------------------------------------===//
+
+
+void MultiplexExternalSemaSource::InitializeSema(Sema &S) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->InitializeSema(S);
+}
+
+void MultiplexExternalSemaSource::ForgetSema() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ForgetSema();
+}
+
+void MultiplexExternalSemaSource::ReadMethodPool(Selector Sel) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadMethodPool(Sel);
+}
+
+void MultiplexExternalSemaSource::ReadKnownNamespaces(
+ SmallVectorImpl<NamespaceDecl*> &Namespaces){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadKnownNamespaces(Namespaces);
+}
+
+bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R, Scope *S){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->LookupUnqualified(R, S);
+
+ return !R.empty();
+}
+
+void MultiplexExternalSemaSource::ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl*> &TentativeDefs) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadTentativeDefinitions(TentativeDefs);
+}
+
+void MultiplexExternalSemaSource::ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUnusedFileScopedDecls(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadDelegatingConstructors(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadExtVectorDecls(
+ SmallVectorImpl<TypedefNameDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadExtVectorDecls(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadDynamicClasses(
+ SmallVectorImpl<CXXRecordDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadDynamicClasses(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadLocallyScopedExternalDecls(
+ SmallVectorImpl<NamedDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadLocallyScopedExternalDecls(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadReferencedSelectors(Sels);
+}
+
+void MultiplexExternalSemaSource::ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadWeakUndeclaredIdentifiers(WI);
+}
+
+void MultiplexExternalSemaSource::ReadUsedVTables(
+ SmallVectorImpl<ExternalVTableUse> &VTables) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUsedVTables(VTables);
+}
+
+void MultiplexExternalSemaSource::ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl*,
+ SourceLocation> > &Pending) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadPendingInstantiations(Pending);
+}
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
new file mode 100644
index 000000000000..4d29a34a73ef
--- /dev/null
+++ b/lib/Sema/ScopeInfo.cpp
@@ -0,0 +1,189 @@
+//===--- ScopeInfo.cpp - Information about a semantic context -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements FunctionScopeInfo and its subclasses, which contain
+// information about a single function, block, lambda, or method body.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+
+using namespace clang;
+using namespace sema;
+
+void FunctionScopeInfo::Clear() {
+ HasBranchProtectedScope = false;
+ HasBranchIntoScope = false;
+ HasIndirectGoto = false;
+
+ SwitchStack.clear();
+ Returns.clear();
+ ErrorTrap.reset();
+ PossiblyUnreachableDiags.clear();
+ WeakObjectUses.clear();
+}
+
+static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
+ if (PropE->isExplicitProperty())
+ return PropE->getExplicitProperty();
+
+ return PropE->getImplicitPropertyGetter();
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::BaseInfoTy
+FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
+ E = E->IgnoreParenCasts();
+
+ const NamedDecl *D = 0;
+ bool IsExact = false;
+
+ switch (E->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ D = cast<DeclRefExpr>(E)->getDecl();
+ IsExact = isa<VarDecl>(D);
+ break;
+ case Stmt::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ D = ME->getMemberDecl();
+ IsExact = isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts());
+ break;
+ }
+ case Stmt::ObjCIvarRefExprClass: {
+ const ObjCIvarRefExpr *IE = cast<ObjCIvarRefExpr>(E);
+ D = IE->getDecl();
+ IsExact = IE->getBase()->isObjCSelfExpr();
+ break;
+ }
+ case Stmt::PseudoObjectExprClass: {
+ const PseudoObjectExpr *POE = cast<PseudoObjectExpr>(E);
+ const ObjCPropertyRefExpr *BaseProp =
+ dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
+ if (BaseProp) {
+ D = getBestPropertyDecl(BaseProp);
+
+ const Expr *DoubleBase = BaseProp->getBase();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase))
+ DoubleBase = OVE->getSourceExpr();
+
+ IsExact = DoubleBase->isObjCSelfExpr();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return BaseInfoTy(D, IsExact);
+}
+
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const ObjCPropertyRefExpr *PropE)
+ : Base(0, true), Property(getBestPropertyDecl(PropE)) {
+
+ if (PropE->isObjectReceiver()) {
+ const OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(PropE->getBase());
+ const Expr *E = OVE->getSourceExpr();
+ Base = getBaseInfo(E);
+ } else if (PropE->isClassReceiver()) {
+ Base.setPointer(PropE->getClassReceiver());
+ } else {
+ assert(PropE->isSuperReceiver());
+ }
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(const Expr *BaseE,
+ const ObjCPropertyDecl *Prop)
+ : Base(0, true), Property(Prop) {
+ if (BaseE)
+ Base = getBaseInfo(BaseE);
+ // else, this is a message accessing a property on super.
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const DeclRefExpr *DRE)
+ : Base(0, true), Property(DRE->getDecl()) {
+ assert(isa<VarDecl>(Property));
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const ObjCIvarRefExpr *IvarE)
+ : Base(getBaseInfo(IvarE->getBase())), Property(IvarE->getDecl()) {
+}
+
+void FunctionScopeInfo::recordUseOfWeak(const ObjCMessageExpr *Msg,
+ const ObjCPropertyDecl *Prop) {
+ assert(Msg && Prop);
+ WeakUseVector &Uses =
+ WeakObjectUses[WeakObjectProfileTy(Msg->getInstanceReceiver(), Prop)];
+ Uses.push_back(WeakUseTy(Msg, Msg->getNumArgs() == 0));
+}
+
+void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
+ E = E->IgnoreParenCasts();
+
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
+ markSafeWeakUse(POE->getSyntacticForm());
+ return;
+ }
+
+ if (const ConditionalOperator *Cond = dyn_cast<ConditionalOperator>(E)) {
+ markSafeWeakUse(Cond->getTrueExpr());
+ markSafeWeakUse(Cond->getFalseExpr());
+ return;
+ }
+
+ if (const BinaryConditionalOperator *Cond =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ markSafeWeakUse(Cond->getCommon());
+ markSafeWeakUse(Cond->getFalseExpr());
+ return;
+ }
+
+ // Has this weak object been seen before?
+ FunctionScopeInfo::WeakObjectUseMap::iterator Uses;
+ if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr));
+ else if (const ObjCIvarRefExpr *IvarE = dyn_cast<ObjCIvarRefExpr>(E))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE));
+ else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE));
+ else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
+ Uses = WeakObjectUses.end();
+ if (const ObjCMethodDecl *MD = MsgE->getMethodDecl()) {
+ if (const ObjCPropertyDecl *Prop = MD->findPropertyDecl()) {
+ Uses =
+ WeakObjectUses.find(WeakObjectProfileTy(MsgE->getInstanceReceiver(),
+ Prop));
+ }
+ }
+ }
+ else
+ return;
+
+ if (Uses == WeakObjectUses.end())
+ return;
+
+ // Has there been a read from the object using this Expr?
+ FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse =
+ std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true));
+ if (ThisUse == Uses->second.rend())
+ return;
+
+ ThisUse->markSafe();
+}
+
+FunctionScopeInfo::~FunctionScopeInfo() { }
+BlockScopeInfo::~BlockScopeInfo() { }
+LambdaScopeInfo::~LambdaScopeInfo() { }
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7f79f0c6d98a..13a33b785b43 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -22,6 +22,7 @@
#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"
@@ -43,22 +44,6 @@
using namespace clang;
using namespace sema;
-FunctionScopeInfo::~FunctionScopeInfo() { }
-
-void FunctionScopeInfo::Clear() {
- HasBranchProtectedScope = false;
- HasBranchIntoScope = false;
- HasIndirectGoto = false;
-
- SwitchStack.clear();
- Returns.clear();
- ErrorTrap.reset();
- PossiblyUnreachableDiags.clear();
-}
-
-BlockScopeInfo::~BlockScopeInfo() { }
-LambdaScopeInfo::~LambdaScopeInfo() { }
-
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -84,12 +69,14 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
- : TheTargetAttributesSema(0), FPFeatures(pp.getLangOpts()),
+ : TheTargetAttributesSema(0), ExternalSource(0),
+ isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
+ CollectStats(false), CodeCompleter(CodeCompleter),
CurContext(0), OriginalLexicalContext(0),
PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ IsBuildingRecoveryCallExpr(false),
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
NSNumberDecl(0),
@@ -203,6 +190,10 @@ Sema::~Sema() {
if (ExternalSemaSource *ExternalSema
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->ForgetSema();
+
+ // If Sema's ExternalSource is the multiplexer - we own it.
+ if (isMultiplexExternalSource)
+ delete ExternalSource;
}
/// makeUnavailableInSystemHeader - There is an error in the current
@@ -234,6 +225,27 @@ ASTMutationListener *Sema::getASTMutationListener() const {
return getASTConsumer().GetASTMutationListener();
}
+///\brief Registers an external source. If an external source already exists,
+/// creates a multiplex external source and appends to it.
+///
+///\param[in] E - A non-null external sema source.
+///
+void Sema::addExternalSource(ExternalSemaSource *E) {
+ assert(E && "Cannot use with NULL ptr");
+
+ if (!ExternalSource) {
+ ExternalSource = E;
+ return;
+ }
+
+ if (isMultiplexExternalSource)
+ static_cast<MultiplexExternalSemaSource*>(ExternalSource)->addSource(*E);
+ else {
+ ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E);
+ isMultiplexExternalSource = true;
+ }
+}
+
/// \brief Print out statistics about the semantic analysis.
void Sema::PrintStats() const {
llvm::errs() << "\n*** Semantic Analysis Stats:\n";
@@ -507,6 +519,11 @@ void Sema::ActOnEndOfTranslationUnit() {
assert(DelayedDiagnostics.getCurrentPool() == NULL
&& "reached end of translation unit with a pool attached?");
+ // If code completion is enabled, don't perform any end-of-translation-unit
+ // work.
+ if (PP.isCodeCompletionEnabled())
+ return;
+
// Only complete translation units define vtables and perform implicit
// instantiations.
if (TUKind == TU_Complete) {
@@ -648,6 +665,8 @@ void Sema::ActOnEndOfTranslationUnit() {
diag::err_tentative_def_incomplete_type))
VD->setInvalidDecl();
+ CheckCompleteVariableDeclaration(VD);
+
// Notify the consumer that we've completed a tentative definition.
if (!VD->isInvalidDecl())
Consumer.CompleteTentativeDefinition(VD);
@@ -1021,6 +1040,9 @@ LambdaScopeInfo *Sema::getCurLambda() {
}
void Sema::ActOnComment(SourceRange Comment) {
+ if (!LangOpts.RetainCommentsFromSystemHeaders &&
+ SourceMgr.isInSystemHeader(Comment.getBegin()))
+ return;
RawComment RC(SourceMgr, Comment);
if (RC.isAlmostTrailingComment()) {
SourceRange MagicMarkerRange(Comment.getBegin(),
@@ -1165,8 +1187,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
// FIXME: Magic number for max shown overloads stolen from
// OverloadCandidateSet::NoteCandidates.
- if (ShownOverloads >= 4 &&
- S.Diags.getShowOverloads() == DiagnosticsEngine::Ovl_Best) {
+ if (ShownOverloads >= 4 && S.Diags.getShowOverloads() == Ovl_Best) {
++SuppressedOverloads;
continue;
}
@@ -1237,8 +1258,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// FIXME: Try this before emitting the fixit, and suppress diagnostics
// while doing so.
E = ActOnCallExpr(0, E.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getLocWithOffset(1));
+ MultiExprArg(), ParenInsertionLoc.getLocWithOffset(1));
return true;
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 3481171c7735..58b1a51ae573 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -97,14 +97,19 @@ struct EffectiveContext {
// functions (which can gain privileges through friendship), but we
// take that as an oversight.
while (true) {
+ // We want to add canonical declarations to the EC lists for
+ // simplicity of checking, but we need to walk up through the
+ // actual current DC chain. Otherwise, something like a local
+ // extern or friend which happens to be the canonical
+ // declaration will really mess us up.
+
if (isa<CXXRecordDecl>(DC)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
- Records.push_back(Record);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ Records.push_back(Record->getCanonicalDecl());
DC = Record->getDeclContext();
} else if (isa<FunctionDecl>(DC)) {
- FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
- Functions.push_back(Function);
-
+ FunctionDecl *Function = cast<FunctionDecl>(DC);
+ Functions.push_back(Function->getCanonicalDecl());
if (Function->getFriendObjectKind())
DC = Function->getLexicalDeclContext();
else
@@ -1791,7 +1796,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
/// specifiers into account, but no member access expressions and such.
///
/// \param Decl the declaration to check if it can be accessed
-/// \param Class the class/context from which to start the search
+/// \param Ctx the class/context from which to start the search
/// \return true if the Decl is accessible from the Class, false otherwise.
bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) {
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index e935fc735b23..f1154c1a8aeb 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -136,23 +136,12 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
}
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
- SourceLocation PragmaLoc,
- SourceLocation KindLoc) {
+ SourceLocation PragmaLoc) {
if (PackContext == 0)
PackContext = new PragmaPackStack();
PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
- // Reset just pops the top of the stack, or resets the current alignment to
- // default.
- if (Kind == Sema::POAK_Reset) {
- if (!Context->pop(0, /*IsReset=*/true)) {
- Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
- << "stack empty";
- }
- return;
- }
-
switch (Kind) {
// For all targets we support native and natural are the same.
//
@@ -181,9 +170,13 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
break;
- default:
- Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
- << KindLoc;
+ case POAK_Reset:
+ // Reset just pops the top of the stack, or resets the current alignment to
+ // default.
+ if (!Context->pop(0, /*IsReset=*/true)) {
+ Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+ << "stack empty";
+ }
break;
}
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 0de9dd5f64c9..15bfd1ce6294 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -520,7 +520,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
<< Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
<< Name << CorrectedQuotedStr
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index d8d51e77ee24..bf25c6178541 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -227,7 +227,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
CheckExtraCXXDefaultArguments(D);
}
- return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E),
+ return BuildCXXNamedCast(OpLoc, Kind, TInfo, E,
SourceRange(LAngleBracketLoc, RAngleBracketLoc),
SourceRange(LParenLoc, RParenLoc));
}
@@ -1331,8 +1331,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
- ExprResult Result
- = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExprRaw, 1));
+ ExprResult Result = InitSeq.Perform(Self, Entity, InitKind, SrcExprRaw);
if (Result.isInvalid()) {
msg = 0;
return TC_Failed;
@@ -1343,7 +1342,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
else
Kind = CK_NoOp;
- SrcExpr = move(Result);
+ SrcExpr = Result;
return TC_Success;
}
@@ -1492,6 +1491,22 @@ static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
}
}
+static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
+ const Expr *SrcExpr, QualType DestType,
+ Sema &Self) {
+ QualType SrcType = SrcExpr->getType();
+
+ // Not warning on reinterpret_cast, boolean, constant expressions, etc
+ // are not explicit design choices, but consistent with GCC's behavior.
+ // Feel free to modify them if you've reason/evidence for an alternative.
+ if (CStyle && SrcType->isIntegralType(Self.Context)
+ && !SrcType->isBooleanType()
+ && !SrcType->isEnumeralType()
+ && !SrcExpr->isIntegerConstantExpr(Self.Context)
+ && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType))
+ Self.Diag(Loc, diag::warn_int_to_pointer_cast) << SrcType << DestType;
+}
+
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
@@ -1513,7 +1528,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
SingleFunctionExpr,
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
) && SingleFunctionExpr.isUsable()) {
- SrcExpr = move(SingleFunctionExpr);
+ SrcExpr = SingleFunctionExpr;
SrcType = SrcExpr.get()->getType();
} else {
return TC_NotApplicable;
@@ -1690,6 +1705,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (SrcType->isIntegralOrEnumerationType()) {
assert(destIsPtr && "One type must be a pointer");
+ checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType,
+ Self);
// C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
// converted to a pointer.
// C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not
@@ -1903,6 +1920,43 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
SrcExpr = ExprError();
}
+/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a
+/// non-matching type. Such as enum function call to int, int call to
+/// pointer; etc. Cast to 'void' is an exception.
+static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ if (Self.Diags.getDiagnosticLevel(diag::warn_bad_function_cast,
+ SrcExpr.get()->getExprLoc())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (!isa<CallExpr>(SrcExpr.get()))
+ return;
+
+ QualType SrcType = SrcExpr.get()->getType();
+ if (DestType.getUnqualifiedType()->isVoidType())
+ return;
+ if ((SrcType->isAnyPointerType() || SrcType->isBlockPointerType())
+ && (DestType->isAnyPointerType() || DestType->isBlockPointerType()))
+ return;
+ if (SrcType->isIntegerType() && DestType->isIntegerType() &&
+ (SrcType->isBooleanType() == DestType->isBooleanType()) &&
+ (SrcType->isEnumeralType() == DestType->isEnumeralType()))
+ return;
+ if (SrcType->isRealFloatingType() && DestType->isRealFloatingType())
+ return;
+ if (SrcType->isEnumeralType() && DestType->isEnumeralType())
+ return;
+ if (SrcType->isComplexType() && DestType->isComplexType())
+ return;
+ if (SrcType->isComplexIntegerType() && DestType->isComplexIntegerType())
+ return;
+
+ Self.Diag(SrcExpr.get()->getExprLoc(),
+ diag::warn_bad_function_cast)
+ << SrcType << DestType << SrcExpr.get()->getSourceRange();
+}
+
/// Check the semantics of a C-style cast operation, in C.
void CastOperation::CheckCStyleCast() {
assert(!Self.getLangOpts().CPlusPlus);
@@ -2035,6 +2089,8 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
+ checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
+ DestType, Self);
} else if (!SrcType->isArithmeticType()) {
if (!DestType->isIntegralType(Self.Context) &&
DestType->isArithmeticType()) {
@@ -2076,7 +2132,7 @@ void CastOperation::CheckCStyleCast() {
}
}
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
-
+ DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
Kind = Self.PrepareScalarCast(SrcExpr, DestType);
if (SrcExpr.isInvalid())
return;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 2559f00f71e0..692a210ef304 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -266,11 +266,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_swap_4:
case Builtin::BI__sync_swap_8:
case Builtin::BI__sync_swap_16:
- return SemaBuiltinAtomicOverloaded(move(TheCallResult));
+ return SemaBuiltinAtomicOverloaded(TheCallResult);
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case Builtin::BI##ID: \
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::AO##ID);
+ return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
#include "clang/Basic/Builtins.def"
case Builtin::BI__builtin_annotation:
if (SemaBuiltinAnnotation(*this, TheCall))
@@ -299,7 +299,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
}
- return move(TheCallResult);
+ return TheCallResult;
}
// Get the valid immediate range for the specified NEON type code.
@@ -437,6 +437,11 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
default: return false;
case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break;
case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break;
+ case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break;
+ case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break;
+ case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break;
+ case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break;
+ case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break;
};
// We can't check the value of a dependent argument.
@@ -490,9 +495,8 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
SourceLocation Loc,
SourceRange Range,
VariadicCallType CallType) {
- // FIXME: This mechanism should be abstracted to be less fragile and
- // more efficient. For example, just map function ids to custom
- // handlers.
+ if (CurContext->isDependentContext())
+ return;
// Printf and scanf checking.
bool HandledFormatString = false;
@@ -506,8 +510,11 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
// Refuse POD arguments that weren't caught by the format string
// checks above.
if (!HandledFormatString && CallType != VariadicDoesNotApply)
- for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx)
- variadicArgumentPODCheck(Args[ArgIdx], CallType);
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) {
+ // Args[ArgIdx] can be null in malformed code.
+ if (Expr *Arg = Args[ArgIdx])
+ variadicArgumentPODCheck(Arg, CallType);
+ }
for (specific_attr_iterator<NonNullAttr>
I = FDecl->specific_attr_begin<NonNullAttr>(),
@@ -538,11 +545,23 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
/// and safety properties not strictly enforced by the C type system.
bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
const FunctionProtoType *Proto) {
- bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall);
+ bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) &&
+ isa<CXXMethodDecl>(FDecl);
+ bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) ||
+ IsMemberOperatorCall;
VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
TheCall->getCallee());
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
- checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs,
+ Expr** Args = TheCall->getArgs();
+ unsigned NumArgs = TheCall->getNumArgs();
+ if (IsMemberOperatorCall) {
+ // If this is a call to a member operator, hide the first argument
+ // from checkCall.
+ // FIXME: Our choice of AST representation here is less than ideal.
+ ++Args;
+ --NumArgs;
+ }
+ checkCall(FDecl, Args, NumArgs, NumProtoArgs,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -737,6 +756,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
+ if (AtomTy.isConstQualified()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
ValType = AtomTy->getAs<AtomicType>()->getValueType();
}
@@ -885,8 +909,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
}
return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
- SubExprs.data(), SubExprs.size(),
- ResultType, Op,
+ SubExprs, ResultType, Op,
TheCall->getRParenLoc()));
}
@@ -1189,10 +1212,19 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID);
- IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName);
- FunctionDecl *NewBuiltinDecl =
- cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID,
- TUScope, false, DRE->getLocStart()));
+ FunctionDecl *NewBuiltinDecl;
+ if (NewBuiltinID == BuiltinID)
+ NewBuiltinDecl = FDecl;
+ else {
+ // Perform builtin lookup to avoid redeclaring it.
+ DeclarationName DN(&Context.Idents.get(NewBuiltinName));
+ LookupResult Res(*this, DN, DRE->getLocStart(), LookupOrdinaryName);
+ LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true);
+ assert(Res.getFoundDecl());
+ NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl());
+ if (NewBuiltinDecl == 0)
+ return ExprError();
+ }
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
@@ -1228,14 +1260,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
NewBuiltinDecl,
/*enclosing*/ false,
DRE->getLocation(),
- NewBuiltinDecl->getType(),
+ Context.BuiltinFnTy,
DRE->getValueKind());
// Set the callee in the CallExpr.
- // FIXME: This leaks the original parens and implicit casts.
- ExprResult PromotedCall = UsualUnaryConversions(NewDRE);
- if (PromotedCall.isInvalid())
- return ExprError();
+ // FIXME: This loses syntactic information.
+ QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
+ ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
+ CK_BuiltinFnToFnPtr);
TheCall->setCallee(PromotedCall.take());
// Change the result type of the call to match the original value type. This
@@ -1243,7 +1275,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// gracefully.
TheCall->setType(ResultType);
- return move(TheCallResult);
+ return TheCallResult;
}
/// CheckObjCString - Checks that the argument to the builtin
@@ -1264,7 +1296,7 @@ bool Sema::CheckObjCString(Expr *Arg) {
StringRef String = Literal->getString();
unsigned NumBytes = String.size();
SmallVector<UTF16, 128> ToBuf(NumBytes);
- const UTF8 *FromPtr = (UTF8 *)String.data();
+ const UTF8 *FromPtr = (const UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes,
@@ -1503,8 +1535,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->setArg(i, 0);
}
- return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(),
- exprs.size(), resType,
+ return Owned(new (Context) ShuffleVectorExpr(Context, exprs, resType,
TheCall->getCallee()->getLocStart(),
TheCall->getRParenLoc()));
}
@@ -1935,19 +1966,19 @@ public:
void HandleIncompleteSpecifier(const char *startSpecifier,
unsigned specifierLen);
+ void HandleInvalidLengthModifier(
+ const analyze_format_string::FormatSpecifier &FS,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen, unsigned DiagID);
+
void HandleNonStandardLengthModifier(
- const analyze_format_string::LengthModifier &LM,
+ const analyze_format_string::FormatSpecifier &FS,
const char *startSpecifier, unsigned specifierLen);
void HandleNonStandardConversionSpecifier(
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen);
- void HandleNonStandardConversionSpecification(
- const analyze_format_string::LengthModifier &LM,
- const analyze_format_string::ConversionSpecifier &CS,
- const char *startSpecifier, unsigned specifierLen);
-
virtual void HandlePosition(const char *startPos, unsigned posLen);
virtual void HandleInvalidPosition(const char *startSpecifier,
@@ -1964,7 +1995,7 @@ public:
PartialDiagnostic PDiag,
SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- FixItHint Fixit = FixItHint());
+ ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>());
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
@@ -1991,7 +2022,7 @@ protected:
template <typename Range>
void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- FixItHint Fixit = FixItHint());
+ ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>());
void CheckPositionalAndNonpositionalArgs(
const analyze_format_string::FormatSpecifier *FS);
@@ -2025,35 +2056,95 @@ void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier,
getSpecifierRange(startSpecifier, specifierLen));
}
+void CheckFormatHandler::HandleInvalidLengthModifier(
+ const analyze_format_string::FormatSpecifier &FS,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen, unsigned DiagID) {
+ using namespace analyze_format_string;
+
+ const LengthModifier &LM = FS.getLengthModifier();
+ CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
+
+ // See if we know how to fix this length modifier.
+ llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ if (FixedLM) {
+ EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+
+ S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
+ << FixedLM->toString()
+ << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
+
+ } else {
+ FixItHint Hint;
+ if (DiagID == diag::warn_format_nonsensical_length)
+ Hint = FixItHint::CreateRemoval(LMRange);
+
+ EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ Hint);
+ }
+}
+
void CheckFormatHandler::HandleNonStandardLengthModifier(
- const analyze_format_string::LengthModifier &LM,
+ const analyze_format_string::FormatSpecifier &FS,
const char *startSpecifier, unsigned specifierLen) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString()
- << 0,
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
+ using namespace analyze_format_string;
+
+ const LengthModifier &LM = FS.getLengthModifier();
+ CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
+
+ // See if we know how to fix this length modifier.
+ llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ if (FixedLM) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << LM.toString() << 0,
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+
+ S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
+ << FixedLM->toString()
+ << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
+
+ } else {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << LM.toString() << 0,
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
}
void CheckFormatHandler::HandleNonStandardConversionSpecifier(
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString()
- << 1,
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
-}
+ using namespace analyze_format_string;
-void CheckFormatHandler::HandleNonStandardConversionSpecification(
- const analyze_format_string::LengthModifier &LM,
- const analyze_format_string::ConversionSpecifier &CS,
- const char *startSpecifier, unsigned specifierLen) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_conversion_spec)
- << LM.toString() << CS.toString(),
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
+ // See if we know how to fix this conversion specifier.
+ llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ if (FixedCS) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << CS.toString() << /*conversion specifier*/1,
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+
+ CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength());
+ S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier)
+ << FixedCS->toString()
+ << FixItHint::CreateReplacement(CSRange, FixedCS->toString());
+ } else {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << CS.toString() << /*conversion specifier*/1,
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
}
void CheckFormatHandler::HandlePosition(const char *startPos,
@@ -2182,7 +2273,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
SourceLocation Loc,
bool IsStringLocation,
Range StringRange,
- FixItHint FixIt) {
+ ArrayRef<FixItHint> FixIt) {
EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
Loc, IsStringLocation, StringRange, FixIt);
}
@@ -2190,7 +2281,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
/// \brief If the format string is not within the funcion call, emit a note
/// so that the function call and string are in diagnostic messages.
///
-/// \param inFunctionCall if true, the format string is within the function
+/// \param InFunctionCall if true, the format string is within the function
/// call and only one diagnostic message will be produced. Otherwise, an
/// extra note will be emitted pointing to location of the format string.
///
@@ -2213,7 +2304,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
/// \param StringRange some or all of the string to highlight. This is
/// templated so it can accept either a CharSourceRange or a SourceRange.
///
-/// \param Fixit optional fix it hint for the format string.
+/// \param FixIt optional fix it hint for the format string.
template<typename Range>
void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
const Expr *ArgumentExpr,
@@ -2221,15 +2312,27 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
SourceLocation Loc,
bool IsStringLocation,
Range StringRange,
- FixItHint FixIt) {
- if (InFunctionCall)
- S.Diag(Loc, PDiag) << StringRange << FixIt;
- else {
+ ArrayRef<FixItHint> FixIt) {
+ if (InFunctionCall) {
+ const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag);
+ D << StringRange;
+ for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end();
+ I != E; ++I) {
+ D << *I;
+ }
+ } else {
S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
<< ArgumentExpr->getSourceRange();
- S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
- diag::note_format_string_defined)
- << StringRange << FixIt;
+
+ const Sema::SemaDiagnosticBuilder &Note =
+ S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
+ diag::note_format_string_defined);
+
+ Note << StringRange;
+ for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end();
+ I != E; ++I) {
+ Note << *I;
+ }
}
}
@@ -2550,23 +2653,17 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
startSpecifier, specifierLen);
// Check the length modifier is valid with the given conversion specifier.
- const LengthModifier &LM = FS.getLengthModifier();
- if (!FS.hasValidLengthModifier())
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
- << LM.toString() << CS.toString(),
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen),
- FixItHint::CreateRemoval(
- getSpecifierRange(LM.getStart(),
- LM.getLength())));
- if (!FS.hasStandardLengthModifier())
- HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen);
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_nonsensical_length);
+ else if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+ else if (!FS.hasStandardLengthConversionCombination())
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_non_standard_conversion_spec);
+
if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
- if (!FS.hasStandardLengthConversionCombination())
- HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
- specifierLen);
// The remaining checks depend on the data arguments.
if (HasVAListArg)
@@ -2582,6 +2679,30 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
return checkFormatExpr(FS, startSpecifier, specifierLen, Arg);
}
+static bool requiresParensToAddCast(const Expr *E) {
+ // FIXME: We should have a general way to reason about operator
+ // precedence and whether parens are actually needed here.
+ // Take care of a few common cases where they aren't.
+ const Expr *Inside = E->IgnoreImpCasts();
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(Inside))
+ Inside = POE->getSyntacticForm()->IgnoreImpCasts();
+
+ switch (Inside->getStmtClass()) {
+ case Stmt::ArraySubscriptExprClass:
+ case Stmt::CallExprClass:
+ case Stmt::DeclRefExprClass:
+ case Stmt::MemberExprClass:
+ case Stmt::ObjCIvarRefExprClass:
+ case Stmt::ObjCMessageExprClass:
+ case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ParenExprClass:
+ case Stmt::UnaryOperatorClass:
+ return false;
+ default:
+ return true;
+ }
+}
+
bool
CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
@@ -2593,81 +2714,151 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// format specifier.
const analyze_printf::ArgType &AT = FS.getArgType(S.Context,
ObjCContext);
- if (AT.isValid() && !AT.matchesType(S.Context, E->getType())) {
- // Look through argument promotions for our error message's reported type.
- // This includes the integral and floating promotions, but excludes array
- // and function pointer decay; seeing that an argument intended to be a
- // string has type 'char [6]' is probably more confusing than 'char *'.
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() == CK_IntegralCast ||
- ICE->getCastKind() == CK_FloatingCast) {
- E = ICE->getSubExpr();
-
- // 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
- // function.
- if (ICE->getType() == S.Context.IntTy ||
- ICE->getType() == S.Context.UnsignedIntTy) {
- // All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, E->getType()))
- return true;
- }
+ if (!AT.isValid())
+ return true;
+
+ QualType IntendedTy = E->getType();
+ if (AT.matchesType(S.Context, IntendedTy))
+ return true;
+
+ // Look through argument promotions for our error message's reported type.
+ // This includes the integral and floating promotions, but excludes array
+ // and function pointer decay; seeing that an argument intended to be a
+ // string has type 'char [6]' is probably more confusing than 'char *'.
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CK_IntegralCast ||
+ ICE->getCastKind() == CK_FloatingCast) {
+ E = ICE->getSubExpr();
+ IntendedTy = 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
+ // function.
+ 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))
+ return true;
}
}
+ }
- // We may be able to offer a FixItHint if it is a supported type.
- PrintfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
- S.Context, ObjCContext);
+ if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
+ // Special-case some of Darwin's platform-independence types.
+ if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) {
+ StringRef Name = UserTy->getDecl()->getName();
+ IntendedTy = 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);
+ }
+ }
- if (success) {
- // Get the fix string from the fixed format specifier
- SmallString<16> buf;
- llvm::raw_svector_ostream os(buf);
- fixedFS.toString(os);
+ // We may be able to offer a FixItHint if it is a supported type.
+ PrintfSpecifier fixedFS = FS;
+ bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(),
+ S.Context, ObjCContext);
+
+ if (success) {
+ // Get the fix string from the fixed format specifier
+ SmallString<16> buf;
+ llvm::raw_svector_ostream os(buf);
+ fixedFS.toString(os);
+
+ CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
+
+ if (IntendedTy != E->getType()) {
+ // 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
+ // should be printed as 'long' for 64-bit compatibility.)
+ // Rather than emitting a normal format/argument mismatch, we want to
+ // add a cast to the recommended type (and correct the format string
+ // if necessary).
+ SmallString<16> CastBuf;
+ llvm::raw_svector_ostream CastFix(CastBuf);
+ CastFix << "(";
+ IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
+ CastFix << ")";
+
+ SmallVector<FixItHint,4> Hints;
+ if (!AT.matchesType(S.Context, IntendedTy))
+ Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
+
+ if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) {
+ // If there's already a cast present, just replace it.
+ SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc());
+ Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str()));
+
+ } else if (!requiresParensToAddCast(E)) {
+ // If the expression has high enough precedence,
+ // just write the C-style cast.
+ Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(),
+ CastFix.str()));
+ } else {
+ // Otherwise, add parens around the expression as well as the cast.
+ CastFix << "(";
+ Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(),
+ CastFix.str()));
+
+ SourceLocation After = S.PP.getLocForEndOfToken(E->getLocEnd());
+ 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) << E->getType()
+ << AT.getRepresentativeTypeName(S.Context) << IntendedTy
<< E->getSourceRange(),
E->getLocStart(),
/*IsStringLocation*/false,
- getSpecifierRange(StartSpecifier, SpecifierLen),
- FixItHint::CreateReplacement(
- getSpecifierRange(StartSpecifier, SpecifierLen),
- os.str()));
- } else {
- const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
- SpecifierLen);
- // 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) {
- unsigned DiagKind;
- if (E->getType()->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()
- << CallType
- << AT.getRepresentativeTypeName(S.Context)
- << CSR
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation*/false, CSR);
-
- checkForCStrMembers(AT, E, CSR);
- } else
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << E->getType()
- << CSR
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation*/false, CSR);
+ SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
}
+ } else {
+ const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
+ SpecifierLen);
+ // 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) {
+ unsigned DiagKind;
+ if (E->getType()->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()
+ << CallType
+ << AT.getRepresentativeTypeName(S.Context)
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
+
+ checkForCStrMembers(AT, E, CSR);
+ } else
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
}
return true;
@@ -2776,24 +2967,17 @@ bool CheckScanfHandler::HandleScanfSpecifier(
}
// Check the length modifier is valid with the given conversion specifier.
- const LengthModifier &LM = FS.getLengthModifier();
- if (!FS.hasValidLengthModifier()) {
- const CharSourceRange &R = getSpecifierRange(LM.getStart(), LM.getLength());
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
- << LM.toString() << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen),
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true, R,
- FixItHint::CreateRemoval(R));
- }
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_nonsensical_length);
+ else if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+ else if (!FS.hasStandardLengthConversionCombination())
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_non_standard_conversion_spec);
- if (!FS.hasStandardLengthModifier())
- HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen);
if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
- if (!FS.hasStandardLengthConversionCombination())
- HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
- specifierLen);
// The remaining checks depend on the data arguments.
if (HasVAListArg)
@@ -2881,7 +3065,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
- getLangOpts()))
+ getLangOpts(),
+ Context.getTargetInfo()))
H.DoneProcessing();
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
@@ -2889,7 +3074,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
- getLangOpts()))
+ getLangOpts(),
+ Context.getTargetInfo()))
H.DoneProcessing();
} // TODO: handle other formats
}
@@ -4138,6 +4324,44 @@ static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
}
}
+static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
+ Expr *Constant, Expr *Other,
+ llvm::APSInt Value,
+ bool RhsConstant) {
+ BinaryOperatorKind op = E->getOpcode();
+ QualType OtherT = Other->getType();
+ QualType ConstantT = Constant->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
+ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
+ if (OtherRange.Width >= LitRange.Width)
+ return;
+ bool IsTrue = true;
+ if (op == BO_EQ)
+ IsTrue = false;
+ else if (op == BO_NE)
+ IsTrue = true;
+ else if (RhsConstant) {
+ if (op == BO_GT || op == BO_GE)
+ IsTrue = !LitRange.NonNegative;
+ else // op == BO_LT || op == BO_LE
+ IsTrue = LitRange.NonNegative;
+ } else {
+ if (op == BO_LT || op == BO_LE)
+ IsTrue = !LitRange.NonNegative;
+ else // op == BO_GT || op == BO_GE
+ IsTrue = LitRange.NonNegative;
+ }
+ SmallString<16> PrettySourceValue(Value.toString(10));
+ S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
+ << PrettySourceValue << OtherT << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+}
+
/// Analyze the operands of the given comparison. Implements the
/// fallback case from AnalyzeComparison.
static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
@@ -4153,20 +4377,42 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
QualType T = E->getLHS()->getType();
assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
&& "comparison with mismatched types");
+ if (E->isValueDependent())
+ return AnalyzeImpConvsInComparison(S, E);
+ Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
+ Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
+
+ bool IsComparisonConstant = false;
+
+ // Check whether an integer constant comparison results in a value
+ // of 'true' or 'false'.
+ if (T->isIntegralType(S.Context)) {
+ llvm::APSInt RHSValue;
+ bool IsRHSIntegralLiteral =
+ RHS->isIntegerConstantExpr(RHSValue, S.Context);
+ llvm::APSInt LHSValue;
+ bool IsLHSIntegralLiteral =
+ LHS->isIntegerConstantExpr(LHSValue, S.Context);
+ if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral)
+ DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true);
+ else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral)
+ DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false);
+ else
+ IsComparisonConstant =
+ (IsRHSIntegralLiteral && IsLHSIntegralLiteral);
+ } else if (!T->hasUnsignedIntegerRepresentation())
+ IsComparisonConstant = E->isIntegerConstantExpr(S.Context);
+
// We don't do anything special if this isn't an unsigned integral
// comparison: we're only interested in integral comparisons, and
// signed comparisons only happen in cases we don't care to warn about.
//
// We also don't care about value-dependent expressions or expressions
// whose result is a constant.
- if (!T->hasUnsignedIntegerRepresentation()
- || E->isValueDependent() || E->isIntegerConstantExpr(S.Context))
+ if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant)
return AnalyzeImpConvsInComparison(S, E);
-
- Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
- Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
-
+
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;
@@ -4353,6 +4599,46 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
+static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
+ if (!isa<ImplicitCastExpr>(Ex))
+ return false;
+
+ Expr *InnerE = Ex->IgnoreParenImpCasts();
+ const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr();
+ const Type *Source =
+ S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
+ if (Target->isDependentType())
+ return false;
+
+ const BuiltinType *FloatCandidateBT =
+ dyn_cast<BuiltinType>(ToBool ? Source : Target);
+ const Type *BoolCandidateType = ToBool ? Target : Source;
+
+ return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) &&
+ FloatCandidateBT && (FloatCandidateBT->isFloatingPoint()));
+}
+
+void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
+ SourceLocation CC) {
+ unsigned NumArgs = TheCall->getNumArgs();
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ Expr *CurrA = TheCall->getArg(i);
+ if (!IsImplicitBoolFloatConversion(S, CurrA, true))
+ continue;
+
+ bool IsSwapped = ((i > 0) &&
+ IsImplicitBoolFloatConversion(S, TheCall->getArg(i - 1), false));
+ IsSwapped |= ((i < (NumArgs - 1)) &&
+ IsImplicitBoolFloatConversion(S, TheCall->getArg(i + 1), false));
+ if (IsSwapped) {
+ // Warn on this floating-point to bool conversion.
+ DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(),
+ CurrA->getType(), CC,
+ diag::warn_impcast_floating_point_to_bool);
+ }
+ }
+}
+
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -4488,12 +4774,33 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
+ // If the target is bool, warn if expr is a function or method call.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool) &&
+ isa<CallExpr>(E)) {
+ // Check last argument of function call to see if it is an
+ // implicit cast from a type matching the type the result
+ // is being cast to.
+ CallExpr *CEx = cast<CallExpr>(E);
+ unsigned NumArgs = CEx->getNumArgs();
+ if (NumArgs > 0) {
+ Expr *LastA = CEx->getArg(NumArgs - 1);
+ Expr *InnerE = LastA->IgnoreParenImpCasts();
+ const Type *InnerType =
+ S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
+ if (isa<ImplicitCastExpr>(LastA) && (InnerType == Target)) {
+ // Warn on this floating-point to bool conversion
+ DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_floating_point_to_bool);
+ }
+ }
+ }
return;
}
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
== Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
- && !Target->isBlockPointerType() && !Target->isMemberPointerType()) {
+ && !Target->isBlockPointerType() && !Target->isMemberPointerType()
+ && Target->isScalarType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
@@ -4658,6 +4965,10 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
return;
}
+ // Check implicit argument conversions for function calls.
+ if (CallExpr *Call = dyn_cast<CallExpr>(E))
+ CheckImplicitArgumentConversions(S, Call, CC);
+
// Go ahead and check any implicit conversions we might have skipped.
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.
@@ -5077,7 +5388,8 @@ static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
return false;
owner.Variable = var;
- owner.setLocsFrom(ref);
+ if (ref)
+ owner.setLocsFrom(ref);
return true;
}
@@ -5186,6 +5498,12 @@ namespace {
if (block->getBlockDecl()->capturesVariable(Variable))
Visit(block->getBlockDecl()->getBody());
}
+
+ void VisitOpaqueValueExpr(OpaqueValueExpr *OVE) {
+ if (Capturer) return;
+ if (OVE->getSourceExpr())
+ Visit(OVE->getSourceExpr());
+ }
};
}
@@ -5195,6 +5513,28 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
assert(owner.Variable && owner.Loc.isValid());
e = e->IgnoreParenCasts();
+
+ // Look through [^{...} copy] and Block_copy(^{...}).
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(e)) {
+ Selector Cmd = ME->getSelector();
+ if (Cmd.isUnarySelector() && Cmd.getNameForSlot(0) == "copy") {
+ e = ME->getInstanceReceiver();
+ if (!e)
+ return 0;
+ e = e->IgnoreParenCasts();
+ }
+ } else if (CallExpr *CE = dyn_cast<CallExpr>(e)) {
+ if (CE->getNumArgs() == 1) {
+ FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
+ if (Fn) {
+ const IdentifierInfo *FnI = Fn->getIdentifier();
+ if (FnI && FnI->isStr("_Block_copy")) {
+ e = CE->getArg(0)->IgnoreParenCasts();
+ }
+ }
+ }
+ }
+
BlockExpr *block = dyn_cast<BlockExpr>(e);
if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
return 0;
@@ -5271,6 +5611,20 @@ void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
diagnoseRetainCycle(*this, capturer, owner);
}
+void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) {
+ RetainCycleOwner Owner;
+ if (!considerVariable(Var, /*DeclRefExpr=*/0, Owner))
+ return;
+
+ // Because we don't have an expression for the variable, we have to set the
+ // location explicitly here.
+ Owner.Loc = Var->getLocation();
+ Owner.Range = Var->getSourceRange();
+
+ if (Expr *Capturer = findCapturingExpr(*this, Init, Owner))
+ diagnoseRetainCycle(*this, Capturer, Owner);
+}
+
bool Sema::checkUnsafeAssigns(SourceLocation Loc,
QualType LHS, Expr *RHS) {
Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
@@ -5304,9 +5658,19 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
if (LHSType.isNull())
LHSType = LHS->getType();
+
+ Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+
+ if (LT == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(LHS);
+ }
+
if (checkUnsafeAssigns(Loc, LHSType, RHS))
return;
- Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+
// FIXME. Check for other life times.
if (LT != Qualifiers::OCL_None)
return;
@@ -5826,7 +6190,8 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
if (IsPointerAttr) {
// Skip implicit cast of pointer to `void *' (as a function argument).
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
- if (ICE->getType()->isVoidPointerType())
+ if (ICE->getType()->isVoidPointerType() &&
+ ICE->getCastKind() == CK_BitCast)
ArgumentExpr = ICE->getSubExpr();
}
QualType ArgumentType = ArgumentExpr->getType();
@@ -5881,4 +6246,3 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
<< ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
-
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index adf132715738..b1aead8f026d 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1059,10 +1059,12 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
// Allow us to find class templates, too.
if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
-
+
+ // For purposes of this check, interfaces match too.
if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
return RD->getTagKind() == TTK_Class ||
- RD->getTagKind() == TTK_Struct;
+ RD->getTagKind() == TTK_Struct ||
+ RD->getTagKind() == TTK_Interface;
return false;
}
@@ -1422,7 +1424,8 @@ static const char *GetCompletionTypeString(QualType T,
if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
switch (Tag->getTagKind()) {
case TTK_Struct: return "struct <anonymous>";
- case TTK_Class: return "class <anonymous>";
+ case TTK_Interface: return "__interface <anonymous>";
+ case TTK_Class: return "class <anonymous>";
case TTK_Union: return "union <anonymous>";
case TTK_Enum: return "enum <anonymous>";
}
@@ -1449,7 +1452,7 @@ static void addThisCompletion(Sema &S, ResultBuilder &Results) {
Policy,
Allocator));
Builder.AddTypedTextChunk("this");
- Results.AddResult(CodeCompletionResult(Builder.TakeString()));
+ Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
/// \brief Add language constructs that show up for "ordinary" names.
@@ -2480,7 +2483,6 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
if (Declaration) {
Result.addParentContext(Declaration->getDeclContext());
- Pattern->ParentKind = Result.getParentKind();
Pattern->ParentName = Result.getParentName();
}
@@ -2493,7 +2495,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
if (Kind == RK_Macro) {
- MacroInfo *MI = PP.getMacroInfo(Macro);
+ MacroInfo *MI = PP.getMacroInfoHistory(Macro);
assert(MI && "Not a macro?");
Result.AddTypedTextChunk(
@@ -2880,10 +2882,14 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case ObjCPropertyImplDecl::Synthesize:
return CXCursor_ObjCSynthesizeDecl;
}
+
+ case Decl::Import:
+ return CXCursor_ModuleImportDecl;
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
+ case TTK_Interface: // fall through
case TTK_Struct: return CXCursor_StructDecl;
case TTK_Class: return CXCursor_ClassDecl;
case TTK_Union: return CXCursor_UnionDecl;
@@ -2896,6 +2902,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
}
static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
+ bool IncludeUndefined,
bool TargetTypeIsPointer = false) {
typedef CodeCompletionResult Result;
@@ -2904,7 +2911,8 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
M != MEnd; ++M) {
- Results.AddResult(Result(M->first,
+ if (IncludeUndefined || M->first->hasMacroDefinition())
+ Results.AddResult(Result(M->first,
getMacroUsagePriority(M->first->getName(),
PP.getLangOpts(),
TargetTypeIsPointer)));
@@ -3125,7 +3133,6 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
void Sema::CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, CompletionContext));
@@ -3204,7 +3211,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
}
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(),Results.size());
@@ -3296,7 +3303,6 @@ struct Sema::CodeCompleteExpressionData {
/// type we're looking for.
void Sema::CodeCompleteExpression(Scope *S,
const CodeCompleteExpressionData &Data) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Expression);
@@ -3336,7 +3342,7 @@ void Sema::CodeCompleteExpression(Scope *S,
AddPrettyFunctionResults(PP.getLangOpts(), Results);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results, PreferredTypeIsPointer);
+ AddMacroResults(PP, Results, false, PreferredTypeIsPointer);
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext(CodeCompletionContext::CCC_Expression,
Data.PreferredType),
@@ -3580,7 +3586,6 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
if (!CodeCompleter)
return;
- typedef CodeCompletionResult Result;
ResultBuilder::LookupFilter Filter = 0;
enum CodeCompletionContext::Kind ContextKind
= CodeCompletionContext::CCC_Other;
@@ -3597,6 +3602,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
case DeclSpec::TST_struct:
case DeclSpec::TST_class:
+ case DeclSpec::TST_interface:
Filter = &ResultBuilder::IsClassOrStruct;
ContextKind = CodeCompletionContext::CCC_ClassOrStructTag;
break;
@@ -3728,7 +3734,7 @@ void Sema::CodeCompleteCase(Scope *S) {
//so only say we include macros if the code completer says we do
enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other;
if (CodeCompleter->includeMacros()) {
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
kind = CodeCompletionContext::CCC_OtherWithMacros;
}
@@ -3898,7 +3904,6 @@ void Sema::CodeCompleteReturn(Scope *S) {
}
void Sema::CodeCompleteAfterIf(Scope *S) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, PCC_Statement));
@@ -3952,7 +3957,7 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
AddPrettyFunctionResults(PP.getLangOpts(), Results);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(),Results.size());
@@ -4408,7 +4413,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
}
void Sema::CodeCompleteObjCAtDirective(Scope *S) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
@@ -4595,26 +4599,23 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
// Check for collisions with "readonly".
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
- ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong)))
+ (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
return true;
- // Check for more than one of { assign, copy, retain, strong }.
+ // Check for more than one of { assign, copy, retain, strong, weak }.
unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign |
ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain|
- ObjCDeclSpec::DQ_PR_strong);
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_weak);
if (AssignCopyRetMask &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong)
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong &&
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_weak)
return true;
return false;
@@ -4626,7 +4627,6 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
unsigned Attributes = ODS.getPropertyAttributes();
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
@@ -4650,6 +4650,12 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.AddResult(CodeCompletionResult("nonatomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic))
Results.AddResult(CodeCompletionResult("atomic"));
+
+ // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC.
+ if (getLangOpts().ObjCARCWeak || getLangOpts().getGC() != LangOptions::NonGC)
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_weak))
+ Results.AddResult(CodeCompletionResult("weak"));
+
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
CodeCompletionBuilder Setter(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
@@ -4837,8 +4843,6 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
- typedef CodeCompletionResult Result;
-
// Try to find the interface where getters might live.
ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext);
if (!Class) {
@@ -4866,8 +4870,6 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
}
void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
- typedef CodeCompletionResult Result;
-
// Try to find the interface where setters might live.
ObjCInterfaceDecl *Class
= dyn_cast_or_null<ObjCInterfaceDecl>(CurContext);
@@ -4898,7 +4900,6 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
bool IsParameter) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Type);
@@ -4957,7 +4958,7 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
CodeCompleter->includeGlobals());
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Type,
@@ -5041,7 +5042,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
///
/// \param S The semantic analysis object.
///
-/// \param S NeedSuperKeyword Whether we need to prefix this completion with
+/// \param NeedSuperKeyword Whether we need to prefix this completion with
/// the "super" keyword. Otherwise, we just need to provide the arguments.
///
/// \param SelIdents The identifiers in the selector that have already been
@@ -5187,7 +5188,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(), Results.size());
@@ -5339,11 +5340,11 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
// If we have an external source, load the entire class method
// pool from the AST file.
- if (SemaRef.ExternalSource) {
+ if (SemaRef.getExternalSource()) {
for (uint32_t I = 0,
- N = SemaRef.ExternalSource->GetNumExternalSelectors();
+ N = SemaRef.getExternalSource()->GetNumExternalSelectors();
I != N; ++I) {
- Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I);
+ Selector Sel = SemaRef.getExternalSource()->GetExternalSelector(I);
if (Sel.isNull() || SemaRef.MethodPool.count(Sel))
continue;
@@ -5868,7 +5869,6 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
}
void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
@@ -7169,7 +7169,9 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) {
M != MEnd; ++M) {
Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(
M->first->getName()));
- Results.AddResult(Builder.TakeString());
+ Results.AddResult(CodeCompletionResult(Builder.TakeString(),
+ CCP_CodePattern,
+ CXCursor_MacroDefinition));
}
Results.ExitScope();
} else if (IsDefinition) {
@@ -7186,7 +7188,7 @@ void Sema::CodeCompletePreprocessorExpression() {
CodeCompletionContext::CCC_PreprocessorExpression);
if (!CodeCompleter || CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, true);
// defined (<macro>)
Results.EnterNewScope();
@@ -7235,7 +7237,7 @@ void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
}
if (!CodeCompleter || CodeCompleter->includeMacros())
- AddMacroResults(PP, Builder);
+ AddMacroResults(PP, Builder, true);
Results.clear();
Results.insert(Results.end(),
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index ea181de00a98..0092d5dab1f4 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -350,8 +350,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
/// isTagName() - This method is called *for error recovery purposes only*
/// to determine if the specified name is a valid tag name ("struct foo"). If
/// so, this returns the TST for the tag corresponding to it (TST_enum,
-/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C
-/// where the user forgot to specify the tag.
+/// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose
+/// cases in C where the user forgot to specify the tag.
DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
// Do a tag name lookup in this scope.
LookupResult R(*this, &II, SourceLocation(), LookupTagName);
@@ -361,6 +361,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
case TTK_Struct: return DeclSpec::TST_struct;
+ case TTK_Interface: return DeclSpec::TST_interface;
case TTK_Union: return DeclSpec::TST_union;
case TTK_Class: return DeclSpec::TST_class;
case TTK_Enum: return DeclSpec::TST_enum;
@@ -434,7 +435,8 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
<< II << DC << CorrectedQuotedStr << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
llvm_unreachable("could not have corrected a typo here");
@@ -517,9 +519,9 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
Scope *S, CXXScopeSpec &SS,
IdentifierInfo *&Name,
SourceLocation NameLoc) {
- Result.clear(Sema::LookupTagName);
- SemaRef.LookupParsedName(Result, S, &SS);
- if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
+ LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
+ SemaRef.LookupParsedName(R, S, &SS);
+ if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
const char *TagName = 0;
const char *FixItTagName = 0;
switch (Tag->getTagKind()) {
@@ -538,6 +540,11 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
FixItTagName = "struct ";
break;
+ case TTK_Interface:
+ TagName = "__interface";
+ FixItTagName = "__interface ";
+ break;
+
case TTK_Union:
TagName = "union";
FixItTagName = "union ";
@@ -548,25 +555,42 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
<< Name << TagName << SemaRef.getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(NameLoc, FixItTagName);
- LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName);
- if (SemaRef.LookupParsedName(R, S, &SS)) {
- for (LookupResult::iterator I = R.begin(), IEnd = R.end();
- I != IEnd; ++I)
- SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
- << Name << TagName;
- }
+ for (LookupResult::iterator I = Result.begin(), IEnd = Result.end();
+ I != IEnd; ++I)
+ SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
+ << Name << TagName;
+
+ // Replace lookup results with just the tag decl.
+ Result.clear(Sema::LookupTagName);
+ SemaRef.LookupParsedName(Result, S, &SS);
return true;
}
- Result.clear(Sema::LookupOrdinaryName);
return false;
}
+/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier.
+static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
+ QualType T, SourceLocation NameLoc) {
+ ASTContext &Context = S.Context;
+
+ TypeLocBuilder Builder;
+ Builder.pushTypeSpec(T).setNameLoc(NameLoc);
+
+ T = S.getElaboratedType(ETK_None, SS, T);
+ ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
Sema::NameClassification Sema::ClassifyName(Scope *S,
CXXScopeSpec &SS,
IdentifierInfo *&Name,
SourceLocation NameLoc,
- const Token &NextToken) {
+ const Token &NextToken,
+ bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
@@ -632,25 +656,11 @@ Corrected:
// Perform typo correction to determine if there is another name that is
// close to this name.
- if (!SecondTry) {
+ if (!SecondTry && CCC) {
SecondTry = true;
- CorrectionCandidateCallback DefaultValidator;
- // Try to limit which sets of keywords should be included in typo
- // correction based on what the next token is.
- DefaultValidator.WantTypeSpecifiers =
- NextToken.is(tok::l_paren) || NextToken.is(tok::less) ||
- NextToken.is(tok::identifier) || NextToken.is(tok::star) ||
- NextToken.is(tok::amp) || NextToken.is(tok::l_square);
- DefaultValidator.WantExpressionKeywords =
- NextToken.is(tok::l_paren) || NextToken.is(tok::identifier) ||
- NextToken.is(tok::arrow) || NextToken.is(tok::period);
- DefaultValidator.WantRemainingKeywords =
- NextToken.is(tok::l_paren) || NextToken.is(tok::semi) ||
- NextToken.is(tok::identifier) || NextToken.is(tok::l_brace);
- DefaultValidator.WantCXXNamedCasts = false;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
- &SS, DefaultValidator)) {
+ &SS, *CCC)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
@@ -675,11 +685,12 @@ Corrected:
Diag(NameLoc, UnqualifiedDiag)
<< Name << CorrectedQuotedStr
<< FixItHint::CreateReplacement(NameLoc, CorrectedStr);
- else
+ else // FIXME: is this even reachable? Test it.
Diag(NameLoc, QualifiedDiag)
<< Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
// Update the name, so that the caller has the new name.
Name = Corrected.getCorrectionAsIdentifierInfo();
@@ -705,7 +716,7 @@ Corrected:
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
Result.clear();
ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
- return move(E);
+ return E;
}
goto Corrected;
@@ -731,8 +742,9 @@ Corrected:
// perform some heroics to see if we actually have a
// template-argument-list, which would indicate a missing 'template'
// keyword here.
- return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/0);
+ return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, IsAddressOfOperand,
+ /*TemplateArgs=*/0);
}
case LookupResult::Found:
@@ -808,14 +820,16 @@ Corrected:
return NameClassification::TypeTemplate(Template);
}
}
-
+
NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
DiagnoseUseOfDecl(Type, NameLoc);
QualType T = Context.getTypeDeclType(Type);
+ if (SS.isNotEmpty())
+ return buildNestedType(*this, SS, T, NameLoc);
return ParsedType::make(T);
}
-
+
ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl);
if (!Class) {
// FIXME: It's unfortunate that we don't have a Type node for handling this.
@@ -838,24 +852,28 @@ Corrected:
return ParsedType::make(T);
}
+ // We can have a type template here if we're classifying a template argument.
+ if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl))
+ return NameClassification::TypeTemplate(
+ TemplateName(cast<TemplateDecl>(FirstDecl)));
+
// Check for a tag type hidden by a non-type decl in a few cases where it
// seems likely a type is wanted instead of the non-type that was found.
- if (!getLangOpts().ObjC1 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) &&
- !isa<TypeAliasTemplateDecl>(FirstDecl)) {
+ if (!getLangOpts().ObjC1) {
bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
if ((NextToken.is(tok::identifier) ||
(NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
- FirstDecl = (*Result.begin())->getUnderlyingDecl();
- if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
- DiagnoseUseOfDecl(Type, NameLoc);
- QualType T = Context.getTypeDeclType(Type);
- return ParsedType::make(T);
- }
+ TypeDecl *Type = Result.getAsSingle<TypeDecl>();
+ DiagnoseUseOfDecl(Type, NameLoc);
+ QualType T = Context.getTypeDeclType(Type);
+ if (SS.isNotEmpty())
+ return buildNestedType(*this, SS, T, NameLoc);
+ return ParsedType::make(T);
}
}
- if (!Result.empty() && (*Result.begin())->isCXXClassMember())
+ if (FirstDecl->isCXXClassMember())
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
@@ -1186,8 +1204,14 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
Context.DeclMustBeEmitted(FD))
return false;
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // Don't warn on variables of const-qualified or reference type, since their
+ // values can be used even if though they're not odr-used, and because const
+ // qualified variables can appear in headers in contexts where they're not
+ // intended to be used.
+ // FIXME: Use more principled rules for these exemptions.
if (!VD->isFileVarDecl() ||
- VD->getType().isConstant(Context) ||
+ VD->getType().isConstQualified() ||
+ VD->getType()->isReferenceType() ||
Context.DeclMustBeEmitted(VD))
return false;
@@ -1248,7 +1272,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
QualType Ty = VD->getType();
// Only look at the outermost level of typedef.
- if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) {
+ if (const TypedefType *TT = Ty->getAs<TypedefType>()) {
if (TT->getDecl()->hasAttr<UnusedAttr>())
return false;
}
@@ -1268,6 +1292,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const Expr *Init = VD->getInit()) {
+ if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(Init))
+ Init = Cleanups->getSubExpr();
const CXXConstructExpr *Construct =
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
@@ -1706,6 +1732,25 @@ DeclHasAttr(const Decl *D, const Attr *A) {
if (AA)
return false;
+ // The following thread safety attributes can also be duplicated.
+ switch (A->getKind()) {
+ case attr::ExclusiveLocksRequired:
+ case attr::SharedLocksRequired:
+ case attr::LocksExcluded:
+ case attr::ExclusiveLockFunction:
+ case attr::SharedLockFunction:
+ case attr::UnlockFunction:
+ case attr::ExclusiveTrylockFunction:
+ case attr::SharedTrylockFunction:
+ case attr::GuardedBy:
+ case attr::PtGuardedBy:
+ case attr::AcquiredBefore:
+ case attr::AcquiredAfter:
+ return false;
+ default:
+ ;
+ }
+
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
@@ -1908,6 +1953,19 @@ static bool canRedefineFunction(const FunctionDecl *FD,
FD->getStorageClass() == SC_Extern);
}
+/// Is the given calling convention the ABI default for the given
+/// declaration?
+static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
+ CallingConv ABIDefaultCC;
+ if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) {
+ ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic());
+ } else {
+ // Free C function or a static method.
+ ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C);
+ }
+ return ABIDefaultCC == CC;
+}
+
/// 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,
@@ -1976,6 +2034,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// later declared or defined without one, the second decl assumes the
// calling convention of the first.
//
+ // It's OK if a function is first declared without a calling convention,
+ // but is later declared or defined with the default calling convention.
+ //
// For the new decl, we have to look at the NON-canonical type to tell the
// difference between a function that really doesn't have a calling
// convention and one that is declared cdecl. That's because in
@@ -1989,10 +2050,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
bool RequiresAdjustment = false;
- if (OldTypeInfo.getCC() != CC_Default &&
- NewTypeInfo.getCC() == CC_Default) {
+ if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) {
+ // Fast path: nothing to do.
+
+ // Inherit the CC from the previous declaration if it was specified
+ // there but not here.
+ } else if (NewTypeInfo.getCC() == CC_Default) {
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
+
+ // Don't complain about mismatches when the default CC is
+ // effectively the same as the explict one.
+ } else if (OldTypeInfo.getCC() == CC_Default &&
+ isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) {
+ NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
+ RequiresAdjustment = true;
+
} else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
NewTypeInfo.getCC())) {
// Calling conventions really aren't compatible, so complain.
@@ -2398,7 +2471,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
}
if (MergedT.isNull()) {
Diag(New->getLocation(), diag::err_redefinition_different_type)
- << New->getDeclName();
+ << New->getDeclName() << New->getType() << Old->getType();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
@@ -2551,8 +2624,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// no declarator (e.g. "struct foo;") is parsed.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS) {
- return ParsedFreeStandingDeclSpec(S, AS, DS,
- MultiTemplateParamsArg(*this, 0, 0));
+ return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
@@ -2565,6 +2637,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
DS.getTypeSpecType() == DeclSpec::TST_struct ||
+ DS.getTypeSpecType() == DeclSpec::TST_interface ||
DS.getTypeSpecType() == DeclSpec::TST_union ||
DS.getTypeSpecType() == DeclSpec::TST_enum) {
TagD = DS.getRepAsDecl();
@@ -2603,7 +2676,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
<< (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
- DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3);
+ DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
+ DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4);
else
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators);
// Don't emit warnings after this error.
@@ -2724,16 +2798,17 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec::TST TypeSpecType = DS.getTypeSpecType();
if (TypeSpecType == DeclSpec::TST_class ||
TypeSpecType == DeclSpec::TST_struct ||
+ TypeSpecType == DeclSpec::TST_interface ||
TypeSpecType == DeclSpec::TST_union ||
TypeSpecType == DeclSpec::TST_enum) {
AttributeList* attrs = DS.getAttributes().getList();
while (attrs) {
- Diag(attrs->getScopeLoc(),
- diag::warn_declspec_attribute_ignored)
+ Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored)
<< attrs->getName()
<< (TypeSpecType == DeclSpec::TST_class ? 0 :
TypeSpecType == DeclSpec::TST_struct ? 1 :
- TypeSpecType == DeclSpec::TST_union ? 2 : 3);
+ TypeSpecType == DeclSpec::TST_union ? 2 :
+ TypeSpecType == DeclSpec::TST_interface ? 3 : 4);
attrs = attrs->getNext();
}
}
@@ -3353,7 +3428,6 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
- case DeclSpec::TST_decltype:
case DeclSpec::TST_underlyingType:
case DeclSpec::TST_atomic: {
// Grab the type from the parser.
@@ -3377,6 +3451,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
break;
}
+ case DeclSpec::TST_decltype:
case DeclSpec::TST_typeofExpr: {
Expr *E = DS.getRepAsExpr();
ExprResult Result = S.RebuildExprInCurrentInstantiation(E);
@@ -3411,7 +3486,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
D.setFunctionDefinitionKind(FDK_Declaration);
- Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
+ Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg());
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
Dcl && Dcl->getDeclContext()->isFileContext())
@@ -3476,7 +3551,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
// void X::f();
// };
if (Cur->Equals(DC)) {
- Diag(Loc, diag::warn_member_extra_qualification)
+ Diag(Loc, LangOpts.MicrosoftExt? diag::warn_member_extra_qualification
+ : diag::err_member_extra_qualification)
<< Name << FixItHint::CreateRemoval(SS.getRange());
SS.clear();
return false;
@@ -3710,11 +3786,11 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous);
} else if (R->isFunctionType()) {
New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous,
- move(TemplateParamLists),
+ TemplateParamLists,
AddToScope);
} else {
New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
- move(TemplateParamLists));
+ TemplateParamLists);
}
if (New == 0)
@@ -3729,9 +3805,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
return New;
}
-/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array
-/// types into constant array types in certain situations which would otherwise
-/// be errors (for GCC compatibility).
+/// Helper method to turn variable array types into constant array
+/// types in certain situations which would otherwise be errors (for
+/// GCC compatibility).
static QualType TryToFixInvalidVariablyModifiedType(QualType T,
ASTContext &Context,
bool &SizeIsNegative,
@@ -3799,6 +3875,52 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
Res, ArrayType::Normal, 0);
}
+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());
+ 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());
+ return;
+ }
+ ArrayTypeLoc* SrcATL = cast<ArrayTypeLoc>(&SrcTL);
+ ArrayTypeLoc* DstATL = cast<ArrayTypeLoc>(&DstTL);
+ TypeLoc SrcElemTL = SrcATL->getElementLoc();
+ TypeLoc DstElemTL = DstATL->getElementLoc();
+ DstElemTL.initializeFullCopy(SrcElemTL);
+ DstATL->setLBracketLoc(SrcATL->getLBracketLoc());
+ DstATL->setSizeExpr(SrcATL->getSizeExpr());
+ DstATL->setRBracketLoc(SrcATL->getRBracketLoc());
+}
+
+/// Helper method to turn variable array types into constant array
+/// types in certain situations which would otherwise be errors (for
+/// GCC compatibility).
+static TypeSourceInfo*
+TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo,
+ ASTContext &Context,
+ bool &SizeIsNegative,
+ llvm::APSInt &Oversized) {
+ QualType FixedTy
+ = TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context,
+ SizeIsNegative, Oversized);
+ if (FixedTy.isNull())
+ return 0;
+ TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy);
+ FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(),
+ FixedTInfo->getTypeLoc());
+ return FixedTInfo;
+}
+
/// \brief Register the given locally-scoped external C declaration so
/// that it can be found later for redeclarations
void
@@ -3926,19 +4048,21 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
// then it shall have block scope.
// Note that variably modified types must be fixed before merging the decl so
// that redeclarations will match.
- QualType T = NewTD->getUnderlyingType();
+ TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo();
+ QualType T = TInfo->getType();
if (T->isVariablyModifiedType()) {
getCurFunction()->setHasBranchProtectedScope();
if (S->getFnParent() == 0) {
bool SizeIsNegative;
llvm::APSInt Oversized;
- QualType FixedTy =
- TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
- Oversized);
- if (!FixedTy.isNull()) {
+ TypeSourceInfo *FixedTInfo =
+ TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
+ SizeIsNegative,
+ Oversized);
+ if (FixedTInfo) {
Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size);
- NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy));
+ NewTD->setTypeSourceInfo(FixedTInfo);
} else {
if (SizeIsNegative)
Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size);
@@ -4203,7 +4327,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getDeclSpec().getLocStart(),
D.getIdentifierLoc(),
D.getCXXScopeSpec(),
- TemplateParamLists.get(),
+ TemplateParamLists.data(),
TemplateParamLists.size(),
/*never a friend*/ false,
isExplicitSpecialization,
@@ -4244,7 +4368,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) {
NewVD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
- TemplateParamLists.release());
+ TemplateParamLists.data());
}
if (D.getDeclSpec().isConstexprSpecified())
@@ -4281,6 +4405,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
+ 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->setStorageClass(SC_Static);
+ }
+
// In auto-retain/release, infer strong retension for variables of
// retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
@@ -4490,7 +4622,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
if (NewVD->isInvalidDecl())
return false;
- QualType T = NewVD->getType();
+ TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo();
+ QualType T = TInfo->getType();
if (T->isObjCObjectType()) {
Diag(NewVD->getLocation(), diag::err_statically_allocated_object)
@@ -4522,8 +4655,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
&& !NewVD->hasAttr<BlocksAttr>()) {
if (getLangOpts().getGC() != LangOptions::NonGC)
Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local);
- else
+ else {
+ assert(!getLangOpts().ObjCAutoRefCount);
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+ }
}
bool isVM = T->isVariablyModifiedType();
@@ -4535,11 +4670,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
bool SizeIsNegative;
llvm::APSInt Oversized;
- QualType FixedTy =
- TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
- Oversized);
-
- if (FixedTy.isNull() && T->isVariableArrayType()) {
+ TypeSourceInfo *FixedTInfo =
+ TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
+ SizeIsNegative, Oversized);
+ if (FixedTInfo == 0 && T->isVariableArrayType()) {
const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
// FIXME: This won't give the correct result for
// int a[10][n];
@@ -4558,7 +4692,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
return false;
}
- if (FixedTy.isNull()) {
+ if (FixedTInfo == 0) {
if (NewVD->isFileVarDecl())
Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
else
@@ -4568,7 +4702,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
}
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
- NewVD->setType(FixedTy);
+ NewVD->setType(FixedTInfo->getType());
+ NewVD->setTypeSourceInfo(FixedTInfo);
}
if (Previous.empty() && NewVD->isExternC()) {
@@ -4655,6 +4790,31 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
return false;
}
+namespace {
+ enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted };
+}
+/// \brief Report an error regarding overriding, along with any relevant
+/// overriden methods.
+///
+/// \param DiagID the primary error to report.
+/// \param MD the overriding method.
+/// \param OEK which overrides to include as notes.
+static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD,
+ OverrideErrorKind OEK = OEK_All) {
+ S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I) {
+ // This check (& the OEK parameter) could be replaced by a predicate, but
+ // without lambdas that would be overkill. This is still nicer than writing
+ // out the diag loop 3 times.
+ if ((OEK == OEK_All) ||
+ (OEK == OEK_NonDeleted && !(*I)->isDeleted()) ||
+ (OEK == OEK_Deleted && (*I)->isDeleted()))
+ S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+ }
+}
+
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4663,6 +4823,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
FindOverriddenMethodData Data;
Data.Method = MD;
Data.S = this;
+ bool hasDeletedOverridenMethods = false;
+ bool hasNonDeletedOverridenMethods = false;
bool AddedAny = false;
if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) {
for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
@@ -4672,12 +4834,21 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
+ hasDeletedOverridenMethods |= OldMD->isDeleted();
+ hasNonDeletedOverridenMethods |= !OldMD->isDeleted();
AddedAny = true;
}
}
}
}
-
+
+ if (hasDeletedOverridenMethods && !MD->isDeleted()) {
+ ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted);
+ }
+ if (hasNonDeletedOverridenMethods && MD->isDeleted()) {
+ ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted);
+ }
+
return AddedAny;
}
@@ -4837,6 +5008,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
if (Correction) {
+ // FIXME: use Correction.getCorrectionRange() instead of computing the range
+ // here. This requires passing in the CXXScopeSpec to CorrectTypo which in
+ // turn causes the correction to fully qualify the name. If we fix
+ // CorrectTypo to minimally qualify then this change should be good.
SourceRange FixItLoc(NewFD->getLocation());
CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec();
if (Correction.getCorrectionSpecifier() && SS.isValid())
@@ -5072,6 +5247,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
}
+void Sema::checkVoidParamDecl(ParmVarDecl *Param) {
+ // In C++, the empty parameter-type-list must be spelled "void"; a
+ // typedef of void is not permitted.
+ if (getLangOpts().CPlusPlus &&
+ Param->getType().getUnqualifiedType() != Context.VoidTy) {
+ bool IsTypeAlias = false;
+ if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
+ IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
+ else if (const TemplateSpecializationType *TST =
+ Param->getType()->getAs<TemplateSpecializationType>())
+ IsTypeAlias = TST->isTypeAlias();
+ Diag(Param->getLocation(), diag::err_param_typedef_of_void)
+ << IsTypeAlias;
+ }
+}
+
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -5138,6 +5329,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setImplicitlyInline();
}
+ // If this is a method defined in an __interface, and is not a constructor
+ // or an overloaded operator, then set the pure flag (isVirtual will already
+ // return true).
+ if (const CXXRecordDecl *Parent =
+ dyn_cast<CXXRecordDecl>(NewFD->getDeclContext())) {
+ if (Parent->isInterface() && cast<CXXMethodDecl>(NewFD)->isUserProvided())
+ NewFD->setPure(true);
+ }
+
SetNestedNameSpecifier(NewFD, D);
isExplicitSpecialization = false;
isFunctionTemplateSpecialization = false;
@@ -5157,7 +5357,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getDeclSpec().getLocStart(),
D.getIdentifierLoc(),
D.getCXXScopeSpec(),
- TemplateParamLists.get(),
+ TemplateParamLists.data(),
TemplateParamLists.size(),
isFriend,
isExplicitSpecialization,
@@ -5196,7 +5396,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size() - 1,
- TemplateParamLists.release());
+ TemplateParamLists.data());
}
} else {
// This is a function template specialization.
@@ -5204,7 +5404,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store all the template param lists.
NewFD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
- TemplateParamLists.release());
+ TemplateParamLists.data());
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@@ -5236,7 +5436,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store all the template param lists.
NewFD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
- TemplateParamLists.release());
+ TemplateParamLists.data());
}
if (Invalid) {
@@ -5376,6 +5576,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_static_out_of_line)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
+
+ // C++11 [except.spec]p15:
+ // A deallocation function with no exception-specification is treated
+ // as if it were specified with noexcept(true).
+ const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
+ if ((Name.getCXXOverloadedOperator() == OO_Delete ||
+ Name.getCXXOverloadedOperator() == OO_Array_Delete) &&
+ getLangOpts().CPlusPlus0x && 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));
+ }
}
// Filter out previous declarations that don't match the scope.
@@ -5413,21 +5627,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FTI.ArgInfo[0].Param &&
cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
// Empty arg list, don't push any params.
- ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[0].Param);
-
- // In C++, the empty parameter-type-list must be spelled "void"; a
- // typedef of void is not permitted.
- if (getLangOpts().CPlusPlus &&
- Param->getType().getUnqualifiedType() != Context.VoidTy) {
- bool IsTypeAlias = false;
- if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
- IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
- else if (const TemplateSpecializationType *TST =
- Param->getType()->getAs<TemplateSpecializationType>())
- IsTypeAlias = TST->isTypeAlias();
- Diag(Param->getLocation(), diag::err_param_typedef_of_void)
- << IsTypeAlias;
- }
+ checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param));
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
@@ -5500,6 +5700,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isExplicitSpecialization));
}
+ // Make graceful recovery from an invalid redeclaration.
+ else if (!Previous.empty())
+ D.setRedeclaration(true);
assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
@@ -5510,12 +5713,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr,
TemplateArgs);
- TemplateArgsPtr.release();
HasExplicitTemplateArgs = true;
@@ -5969,20 +6170,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Find any virtual functions that this function overrides.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) {
if (!Method->isFunctionTemplateSpecialization() &&
- !Method->getDescribedFunctionTemplate()) {
+ !Method->getDescribedFunctionTemplate() &&
+ Method->isCanonicalDecl()) {
if (AddOverriddenMethods(Method->getParent(), Method)) {
// If the function was marked as "static", we have a problem.
if (NewFD->getStorageClass() == SC_Static) {
- Diag(NewFD->getLocation(), diag::err_static_overrides_virtual)
- << NewFD->getDeclName();
- for (CXXMethodDecl::method_iterator
- Overridden = Method->begin_overridden_methods(),
- OverriddenEnd = Method->end_overridden_methods();
- Overridden != OverriddenEnd;
- ++Overridden) {
- Diag((*Overridden)->getLocation(),
- diag::note_overridden_virtual_function);
- }
+ ReportOverrides(*this, diag::err_static_overrides_virtual, Method);
}
}
}
@@ -6191,28 +6384,12 @@ namespace {
}
}
- // Sometimes, the expression passed in lacks the casts that are used
- // to determine which DeclRefExpr's to check. Assume that the casts
- // are present and continue visiting the expression.
- void HandleExpr(Expr *E) {
- // Skip checking T a = a where T is not a record or reference type.
- // Doing so is a way to silence uninitialized warnings.
- if (isRecordType || isReferenceType)
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- HandleDeclRefExpr(DRE);
-
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- HandleValue(CO->getTrueExpr());
- HandleValue(CO->getFalseExpr());
- }
-
- Visit(E);
- }
-
// For most expressions, the cast is directly above the DeclRefExpr.
// For conditional operators, the cast can be outside the conditional
// operator if both expressions are DeclRefExpr's.
void HandleValue(Expr *E) {
+ if (isReferenceType)
+ return;
E = E->IgnoreParenImpCasts();
if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) {
HandleDeclRefExpr(DRE);
@@ -6222,11 +6399,32 @@ namespace {
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
HandleValue(CO->getTrueExpr());
HandleValue(CO->getFalseExpr());
+ return;
+ }
+
+ if (isa<MemberExpr>(E)) {
+ Expr *Base = E->IgnoreParenImpCasts();
+ while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
+ // Check for static member variables and don't warn on them.
+ if (!isa<FieldDecl>(ME->getMemberDecl()))
+ return;
+ Base = ME->getBase()->IgnoreParenImpCasts();
+ }
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base))
+ HandleDeclRefExpr(DRE);
+ return;
}
}
+ // Reference types are handled here since all uses of references are
+ // bad, not just r-value uses.
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (isReferenceType)
+ HandleDeclRefExpr(E);
+ }
+
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) ||
+ if (E->getCastKind() == CK_LValueToRValue ||
(isRecordType && E->getCastKind() == CK_NoOp))
HandleValue(E->getSubExpr());
@@ -6237,22 +6435,36 @@ namespace {
// Don't warn on arrays since they can be treated as pointers.
if (E->getType()->canDecayToPointerType()) return;
- ValueDecl *VD = E->getMemberDecl();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD);
- if (isa<FieldDecl>(VD) || (MD && !MD->isStatic()))
- if (DeclRefExpr *DRE
- = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
+ // Warn when a non-static method call is followed by non-static member
+ // field accesses, which is followed by a DeclRefExpr.
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl());
+ bool Warn = (MD && !MD->isStatic());
+ Expr *Base = E->getBase()->IgnoreParenImpCasts();
+ while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
+ if (!isa<FieldDecl>(ME->getMemberDecl()))
+ Warn = false;
+ Base = ME->getBase()->IgnoreParenImpCasts();
+ }
+
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (Warn)
HandleDeclRefExpr(DRE);
- return;
- }
+ return;
+ }
- Inherited::VisitMemberExpr(E);
+ // The base of a MemberExpr is not a MemberExpr or a DeclRefExpr.
+ // Visit that expression.
+ Visit(Base);
}
void VisitUnaryOperator(UnaryOperator *E) {
// For POD record types, addresses of its own members are well-defined.
- if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType &&
- isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) return;
+ if (E->getOpcode() == UO_AddrOf && isRecordType &&
+ isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) {
+ if (!isPODType)
+ HandleValue(E->getSubExpr());
+ return;
+ }
Inherited::VisitUnaryOperator(E);
}
@@ -6261,20 +6473,38 @@ namespace {
void HandleDeclRefExpr(DeclRefExpr *DRE) {
Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
- LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
- Sema::NotForRedeclaration);
+ unsigned diag = isReferenceType
+ ? diag::warn_uninit_self_reference_in_reference_init
+ : diag::warn_uninit_self_reference_in_init;
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
- S.PDiag(diag::warn_uninit_self_reference_in_init)
- << Result.getLookupName()
+ S.PDiag(diag)
+ << DRE->getNameInfo().getName()
<< OrigDecl->getLocation()
<< DRE->getSourceRange());
}
};
-}
-/// CheckSelfReference - Warns if OrigDecl is used in expression E.
-void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) {
- SelfReferenceChecker(*this, OrigDecl).HandleExpr(E);
+ /// CheckSelfReference - Warns if OrigDecl is used in expression E.
+ static void CheckSelfReference(Sema &S, Decl* OrigDecl, Expr *E,
+ bool DirectInit) {
+ // Parameters arguments are occassionially constructed with itself,
+ // for instance, in recursive functions. Skip them.
+ if (isa<ParmVarDecl>(OrigDecl))
+ return;
+
+ E = E->IgnoreParens();
+
+ // Skip checking T a = a where T is not a record or reference type.
+ // Doing so is a way to silence uninitialized warnings.
+ if (!DirectInit && !cast<VarDecl>(OrigDecl)->getType()->isRecordType())
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CK_LValueToRValue)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()))
+ if (DRE->getDecl() == OrigDecl)
+ return;
+
+ SelfReferenceChecker(S, OrigDecl).Visit(E);
+ }
}
/// AddInitializerToDecl - Adds the initializer Init to the
@@ -6311,15 +6541,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
- // Check for self-references within variable initializers.
- // Variables declared within a function/method body (except for references)
- // are handled by a dataflow analysis.
- // Record types initialized by initializer list are handled here.
- // Initialization by constructors are handled in TryConstructorInitialization.
- if ((!VDecl->hasLocalStorage() || VDecl->getType()->isReferenceType()) &&
- (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType()))
- CheckSelfReference(RealDecl, Init);
-
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
@@ -6495,8 +6716,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, Args,NumArgs),
- &DclT);
+ MultiExprArg(Args, NumArgs), &DclT);
if (Result.isInvalid()) {
VDecl->setInvalidDecl();
return;
@@ -6505,6 +6725,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
Init = Result.takeAs<Expr>();
}
+ // Check for self-references within variable initializers.
+ // Variables declared within a function/method body (except for references)
+ // are handled by a dataflow analysis.
+ if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() ||
+ VDecl->getType()->isReferenceType()) {
+ CheckSelfReference(*this, RealDecl, Init, DirectInit);
+ }
+
// If the type changed, it means we had an incomplete type that was
// completed by the initializer. For example:
// int ary[] = { 1, 3, 5 };
@@ -6515,9 +6743,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Check any implicit conversions within the expression.
CheckImplicitConversions(Init, VDecl->getLocation());
- if (!VDecl->isInvalidDecl())
+ if (!VDecl->isInvalidDecl()) {
checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+ if (VDecl->hasAttr<BlocksAttr>())
+ checkRetainCycles(VDecl, Init);
+
+ // It is safe to assign a weak reference into a strong variable.
+ // Although this code can still have problems:
+ // id x = self.weakProp;
+ // id y = self.weakProp;
+ // we do not warn to warn spuriously when 'x' and 'y' are on separate
+ // paths through the function. This should be revisited if
+ // -Wrepeated-use-of-weak is made flow-sensitive.
+ if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ Init->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(Init);
+ }
+ }
+
Init = MaybeCreateExprWithCleanups(Init);
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -6758,8 +7005,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
AbstractVariableType))
Var->setInvalidDecl();
if (!Type->isDependentType() && !Var->isInvalidDecl() &&
- Var->getStorageClass() == SC_PrivateExtern)
+ Var->getStorageClass() == SC_PrivateExtern) {
Diag(Var->getLocation(), diag::warn_private_extern);
+ Diag(Var->getLocation(), diag::note_private_extern);
+ }
return;
@@ -6881,8 +7130,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
= InitializationKind::CreateDefault(Var->getLocation());
InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, 0, 0));
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg());
if (Init.isInvalid())
Var->setInvalidDecl();
else if (Init.get()) {
@@ -6957,11 +7205,22 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
}
+ if (var->isThisDeclarationADefinition() &&
+ var->getLinkage() == ExternalLinkage) {
+ // Find a previous declaration that's not a definition.
+ VarDecl *prev = var->getPreviousDecl();
+ while (prev && prev->isThisDeclarationADefinition())
+ prev = prev->getPreviousDecl();
+
+ if (!prev)
+ Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var;
+ }
+
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) return;
- QualType baseType = Context.getBaseElementType(var->getType());
- if (baseType->isDependentType()) return;
+ QualType type = var->getType();
+ if (type->isDependentType()) return;
// __block variables might require us to capture a copy-initializer.
if (var->hasAttr<BlocksAttr>()) {
@@ -6970,8 +7229,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Regardless, we don't want to ignore array nesting when
// constructing this copy.
- QualType type = var->getType();
-
if (type->isStructureOrClassType()) {
SourceLocation poi = var->getLocation();
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
@@ -6989,8 +7246,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Expr *Init = var->getInit();
bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal();
+ QualType baseType = Context.getBaseElementType(type);
- if (!var->getDeclContext()->isDependentContext() && Init) {
+ if (!var->getDeclContext()->isDependentContext() &&
+ Init && !Init->isValueDependent()) {
if (IsGlobal && !var->isConstexpr() &&
getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor,
var->getLocation())
@@ -7178,7 +7437,7 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
// the lookahead in the lexer: we've consumed the semicolon and looked
// ahead through comments.
for (unsigned i = 0; i != NumDecls; ++i)
- Context.getCommentForDecl(Group[i]);
+ Context.getCommentForDecl(Group[i], &PP);
}
}
@@ -7450,6 +7709,9 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
unsigned DiagID; // unused
DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
PrevSpec, DiagID);
+ // Use the identifier location for the type source range.
+ DS.SetRangeStart(FTI.ArgInfo[i].IdentLoc);
+ DS.SetRangeEnd(FTI.ArgInfo[i].IdentLoc);
Declarator ParamD(DS, Declarator::KNRTypeListContext);
ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD);
@@ -7464,8 +7726,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
Scope *ParentScope = FnBodyScope->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
- Decl *DP = HandleDeclarator(ParentScope, D,
- MultiTemplateParamsArg(*this));
+ Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg());
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
@@ -7707,7 +7968,7 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
}
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
- return ActOnFinishFunctionBody(D, move(BodyArg), false);
+ return ActOnFinishFunctionBody(D, BodyArg, false);
}
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
@@ -7765,22 +8026,16 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (Body)
computeNRVO(Body, getCurFunction());
}
- if (getCurFunction()->ObjCShouldCallSuperDealloc) {
- Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc);
- getCurFunction()->ObjCShouldCallSuperDealloc = false;
- }
- if (getCurFunction()->ObjCShouldCallSuperFinalize) {
- Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize);
- getCurFunction()->ObjCShouldCallSuperFinalize = false;
+ if (getCurFunction()->ObjCShouldCallSuper) {
+ Diag(MD->getLocEnd(), diag::warn_objc_missing_super_call)
+ << MD->getSelector().getAsString();
+ getCurFunction()->ObjCShouldCallSuper = false;
}
} else {
return 0;
}
- assert(!getCurFunction()->ObjCShouldCallSuperDealloc &&
- "This should only be set for ObjC methods, which should have been "
- "handled in the block above.");
- assert(!getCurFunction()->ObjCShouldCallSuperFinalize &&
+ assert(!getCurFunction()->ObjCShouldCallSuper &&
"This should only be set for ObjC methods, which should have been "
"handled in the block above.");
@@ -7916,13 +8171,28 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
+ SourceLocation NoLoc;
Declarator D(DS, Declarator::BlockContext);
- D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false,
- SourceLocation(), 0, 0, 0, true,
- SourceLocation(), SourceLocation(),
- SourceLocation(), SourceLocation(),
- EST_None, SourceLocation(),
- 0, 0, 0, 0, Loc, Loc, D),
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
+ /*IsAmbiguous=*/false,
+ /*RParenLoc=*/NoLoc,
+ /*ArgInfo=*/0,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ Loc, Loc, D),
DS.getAttributes(),
SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -8071,6 +8341,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
switch (D.getDeclSpec().getTypeSpecType()) {
case TST_enum:
case TST_struct:
+ case TST_interface:
case TST_union:
case TST_class: {
TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
@@ -8146,6 +8417,29 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
return false;
}
+/// \brief Get diagnostic %select index for tag kind for
+/// redeclaration diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for redecl diagnostic!");
+ }
+}
+
+/// \brief Determine if tag kind is a class-key compatible with
+/// class for redeclaration (class, struct, or __interface).
+///
+/// \returns true iff the tag kind is compatible.
+static bool isClassCompatTagKind(TagTypeKind Tag)
+{
+ return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface;
+}
+
/// \brief Determine whether a tag with a given kind is acceptable
/// as a redeclaration of the given tag declaration.
///
@@ -8168,12 +8462,11 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// struct class-key shall be used to refer to a class (clause 9)
// declared using the class or struct class-key.
TagTypeKind OldTag = Previous->getTagKind();
- if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct))
+ if (!isDefinition || !isClassCompatTagKind(NewTag))
if (OldTag == NewTag)
return true;
- if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
- (NewTag == TTK_Struct || NewTag == TTK_Class)) {
+ if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) {
// Warn about the struct/class tag mismatch.
bool isTemplate = false;
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
@@ -8183,7 +8476,8 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// In a template instantiation, do not offer fix-its for tag mismatches
// since they usually mess up the template instead of fixing the problem.
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << (NewTag == TTK_Class) << isTemplate << &Name;
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(OldTag);
return true;
}
@@ -8202,13 +8496,13 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
if (!previousMismatch) {
previousMismatch = true;
Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch)
- << (NewTag == TTK_Class) << isTemplate << &Name;
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(I->getTagKind());
}
Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion)
- << (NewTag == TTK_Class)
+ << getRedeclDiagFromTagKind(NewTag)
<< FixItHint::CreateReplacement(I->getInnerLocStart(),
- NewTag == TTK_Class?
- "class" : "struct");
+ TypeWithKeyword::getTagTypeKindName(NewTag));
}
}
return true;
@@ -8224,16 +8518,16 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
}
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << (NewTag == TTK_Class)
- << isTemplate << &Name;
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(OldTag);
Diag(Redecl->getLocation(), diag::note_previous_use);
// If there is a previous defintion, suggest a fix-it.
if (Previous->getDefinition()) {
Diag(NewTagLoc, diag::note_struct_class_suggestion)
- << (Redecl->getTagKind() == TTK_Class)
+ << getRedeclDiagFromTagKind(Redecl->getTagKind())
<< FixItHint::CreateReplacement(SourceRange(NewTagLoc),
- Redecl->getTagKind() == TTK_Class? "class" : "struct");
+ TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind()));
}
return true;
@@ -8276,7 +8570,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS,
- TemplateParameterLists.get(),
+ TemplateParameterLists.data(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
isExplicitSpecialization,
@@ -8293,8 +8587,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SS, Name, NameLoc, Attr,
TemplateParams, AS,
ModulePrivateLoc,
- TemplateParameterLists.size() - 1,
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.size()-1,
+ TemplateParameterLists.data());
return Result.get();
} else {
// The "template<>" header is extraneous.
@@ -8843,7 +9137,7 @@ CreateNewDecl:
if (TemplateParameterLists.size() > 0) {
New->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size(),
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
}
else
@@ -9298,12 +9592,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
if (!InvalidDecl && T->isVariablyModifiedType()) {
bool SizeIsNegative;
llvm::APSInt Oversized;
- QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context,
- SizeIsNegative,
- Oversized);
- if (!FixedTy.isNull()) {
+
+ TypeSourceInfo *FixedTInfo =
+ TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
+ SizeIsNegative,
+ Oversized);
+ if (FixedTInfo) {
Diag(Loc, diag::warn_illegal_constant_array_size);
- T = FixedTy;
+ TInfo = FixedTInfo;
+ T = FixedTInfo->getType();
} else {
if (SizeIsNegative)
Diag(Loc, diag::err_typecheck_negative_array_size);
@@ -9460,12 +9757,12 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
return false;
}
-/// If the given constructor is user-provided, produce a diagnostic explaining
+/// If the given constructor is user-declared, produce a diagnostic explaining
/// that it makes the class non-trivial.
-static bool DiagnoseNontrivialUserProvidedCtor(Sema &S, QualType QT,
+static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT,
CXXConstructorDecl *CD,
Sema::CXXSpecialMember CSM) {
- if (!CD->isUserProvided())
+ if (CD->isImplicit())
return false;
SourceLocation CtorLoc = CD->getLocation();
@@ -9488,17 +9785,17 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
- if (DiagnoseNontrivialUserProvidedCtor(*this, QT, *CI, member))
+ if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member))
return;
- // No user-provided constructors; look for constructor templates.
+ // 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 && DiagnoseNontrivialUserProvidedCtor(*this, QT, CD, member))
+ if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member))
return;
}
}
@@ -10025,42 +10322,6 @@ void Sema::ActOnFields(Scope* S,
Convs->setAccess(I, (*I)->getAccess());
if (!CXXRecord->isDependentType()) {
- // Objective-C Automatic Reference Counting:
- // If a class has a non-static data member of Objective-C pointer
- // type (or array thereof), it is a non-POD type and its
- // default constructor (if any), copy constructor, copy assignment
- // operator, and destructor are non-trivial.
- //
- // This rule is also handled by CXXRecordDecl::completeDefinition().
- // However, here we check whether this particular class is only
- // non-POD because of the presence of an Objective-C pointer member.
- // If so, objects of this type cannot be shared between code compiled
- // with ARC and code compiled with manual retain/release.
- if (getLangOpts().ObjCAutoRefCount &&
- CXXRecord->hasObjectMember() &&
- CXXRecord->getLinkage() == ExternalLinkage) {
- if (CXXRecord->isPOD()) {
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_non_pod_class_with_object_member)
- << CXXRecord;
- } else {
- // FIXME: Fix-Its would be nice here, but finding a good location
- // for them is going to be tricky.
- if (CXXRecord->hasTrivialCopyConstructor())
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_trivial_member_function_with_object_member)
- << CXXRecord << 0;
- if (CXXRecord->hasTrivialCopyAssignment())
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_trivial_member_function_with_object_member)
- << CXXRecord << 1;
- if (CXXRecord->hasTrivialDestructor())
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_trivial_member_function_with_object_member)
- << CXXRecord << 2;
- }
- }
-
// Adjust user-defined destructor exception spec.
if (getLangOpts().CPlusPlus0x &&
CXXRecord->hasUserDeclaredDestructor())
@@ -10092,7 +10353,7 @@ void Sema::ActOnFields(Scope* S,
// class subobject has more than one final overrider the
// program is ill-formed.
Diag(Record->getLocation(), diag::err_multiple_final_overriders)
- << (NamedDecl *)M->first << Record;
+ << (const NamedDecl *)M->first << Record;
Diag(M->first->getLocation(),
diag::note_overridden_virtual_function);
for (OverridingMethods::overriding_iterator
@@ -10100,7 +10361,7 @@ void Sema::ActOnFields(Scope* S,
OMEnd = SO->second.end();
OM != OMEnd; ++OM)
Diag(OM->Method->getLocation(), diag::note_final_overrider)
- << (NamedDecl *)M->first << OM->Method->getParent();
+ << (const NamedDecl *)M->first << OM->Method->getParent();
Record->setInvalidDecl();
}
@@ -10461,57 +10722,6 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
return New;
}
-// Emits a warning if every element in the enum is the same value and if
-// every element is initialized with a integer or boolean literal.
-static void CheckForUniqueEnumValues(Sema &S, Decl **Elements,
- unsigned NumElements, EnumDecl *Enum,
- QualType EnumType) {
- if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values,
- Enum->getLocation()) ==
- DiagnosticsEngine::Ignored)
- return;
-
- if (NumElements < 2)
- return;
-
- if (!Enum->getIdentifier())
- return;
-
- llvm::APSInt FirstVal;
-
- for (unsigned i = 0; i != NumElements; ++i) {
- EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
- if (!ECD)
- return;
-
- Expr *InitExpr = ECD->getInitExpr();
- if (!InitExpr)
- return;
- InitExpr = InitExpr->IgnoreImpCasts();
- if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr))
- return;
-
- if (i == 0) {
- FirstVal = ECD->getInitVal();
- continue;
- }
-
- if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal()))
- return;
- }
-
- S.Diag(Enum->getLocation(), diag::warn_identical_enum_values)
- << EnumType << FirstVal.toString(10)
- << Enum->getSourceRange();
-
- EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]),
- *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]);
-
- S.Diag(Last->getLocation(), diag::note_identical_enum_values)
- << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(),
- Next->getName());
-}
-
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
@@ -10734,8 +10944,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// it needs to go into the function scope.
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
-
- CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
@@ -10834,10 +11042,6 @@ Decl *Sema::getObjCDeclContext() const {
}
AvailabilityResult Sema::getCurContextAvailability() const {
- const Decl *D = cast<Decl>(getCurLexicalContext());
- // A category implicitly has the availability of the interface.
- if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
- D = CatD->getClassInterface();
-
+ const Decl *D = cast<Decl>(getCurObjCLexicalContext());
return D->getAvailability();
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index caa7b2f65a9d..e326a20c87d0 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -415,14 +415,19 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
}
if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
- // Ignore empty strings without warnings
- if (StrLit->getLength() == 0)
+ if (StrLit->getLength() == 0 ||
+ StrLit->getString() == StringRef("*")) {
+ // Pass empty strings to the analyzer without warnings.
+ // Treat "*" as the universal lock.
+ Args.push_back(ArgExp);
continue;
+ }
// We allow constant strings to be used as a placeholder for expressions
// that are not valid C++ syntax, but warn that they are ignored.
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) <<
Attr.getName();
+ Args.push_back(ArgExp);
continue;
}
@@ -859,7 +864,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
if (!checkAttributeNumArgs(S, Attr, 1))
return;
- Expr *Arg = Attr.getArg(0);
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -867,9 +871,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
return;
}
- if (Arg->isTypeDependent())
- return;
-
// check that the argument is lockable object
SmallVector<Expr*, 1> Args;
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
@@ -962,7 +963,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
- if (!FD->getType()->isIncompleteType() &&
+ if (!FD->getType()->isDependentType() &&
+ !FD->getType()->isIncompleteType() &&
S.Context.getTypeAlign(FD->getType()) <= 8)
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
@@ -973,8 +975,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (TagDecl *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context));
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ RD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -1522,6 +1524,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str->getString()));
}
+static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) MinSizeAttr(Attr.getRange(), S.Context));
+}
+
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -2268,16 +2284,14 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
- if (!T->isPointerType() ||
- !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
+ if (!T->isCARCBridgableType()) {
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
return;
}
}
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) {
QualType T = PD->getType();
- if (!T->isPointerType() ||
- !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
+ if (!T->isCARCBridgableType()) {
S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
return;
}
@@ -3583,7 +3597,12 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS));
+ return;
}
+ case AttributeList::AT_PnaclCall:
+ D->addAttr(::new (S.Context) PnaclCallAttr(Attr.getRange(), S.Context));
+ return;
+
default:
llvm_unreachable("unexpected attribute kind");
}
@@ -3636,9 +3655,17 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
Diag(attr.getLoc(), diag::err_invalid_pcs);
return true;
}
+ case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break;
default: llvm_unreachable("unexpected attribute kind");
}
+ const TargetInfo &TI = Context.getTargetInfo();
+ TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
+ if (A == TargetInfo::CCCR_Warning) {
+ Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName();
+ CC = TI.getDefaultCallingConv();
+ }
+
return false;
}
@@ -3878,11 +3905,11 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
returnType = MD->getResultType();
- else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
- returnType = PD->getType();
else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
(Attr.getKind() == AttributeList::AT_NSReturnsRetained))
return; // ignore: was handled as a type attribute
+ else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ returnType = PD->getType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getResultType();
else {
@@ -3971,6 +3998,33 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
}
+static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
+ const AttributeList &attr) {
+ SourceLocation loc = attr.getLoc();
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
+
+ if (!method) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
+ return;
+ }
+ DeclContext *DC = method->getDeclContext();
+ if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
+ S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
+ << attr.getName() << 0;
+ S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
+ return;
+ }
+ if (method->getMethodFamily() == OMF_dealloc) {
+ S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
+ << attr.getName() << 1;
+ return;
+ }
+
+ method->addAttr(
+ ::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context));
+}
+
/// Handle cf_audited_transfer and cf_unknown_transfer.
static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
if (!isa<FunctionDecl>(D)) {
@@ -4149,19 +4203,21 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.MicrosoftExt) {
- AttributeList::Kind Kind = Attr.getKind();
- if (Kind == AttributeList::AT_SingleInheritance)
- D->addAttr(
- ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
- else if (Kind == AttributeList::AT_MultipleInheritance)
- D->addAttr(
- ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
- else if (Kind == AttributeList::AT_VirtualInheritance)
- D->addAttr(
- ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
- } else
+ if (!S.LangOpts.MicrosoftExt) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ return;
+ }
+
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_SingleInheritance)
+ D->addAttr(
+ ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_MultipleInheritance)
+ D->addAttr(
+ ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_VirtualInheritance)
+ D->addAttr(
+ ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
}
static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -4246,6 +4302,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
+ case AttributeList::AT_MinSize:
+ handleMinSizeAttr(S, D, Attr);
+ break;
case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break;
case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break;
case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break;
@@ -4278,6 +4337,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ObjCReturnsInnerPointer:
handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
+ case AttributeList::AT_ObjCRequiresSuper:
+ handleObjCRequiresSuperAttr(S, D, Attr); break;
+
case AttributeList::AT_NSBridged:
handleNSBridgedAttr(S, scope, D, Attr); break;
@@ -4360,6 +4422,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ThisCall:
case AttributeList::AT_Pascal:
case AttributeList::AT_Pcs:
+ case AttributeList::AT_PnaclCall:
handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_OpenCLKernel:
@@ -4774,18 +4837,25 @@ static bool isDeclDeprecated(Decl *D) {
static void
DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message,
SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCPropery) {
DeclarationName Name = D->getDeclName();
if (!Message.empty()) {
S.Diag(Loc, diag::warn_deprecated_message) << Name << Message;
S.Diag(D->getLocation(),
isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
: diag::note_previous_decl) << Name;
+ if (ObjCPropery)
+ S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute)
+ << ObjCPropery->getDeclName() << 0;
} else if (!UnknownObjCClass) {
S.Diag(Loc, diag::warn_deprecated) << D->getDeclName();
S.Diag(D->getLocation(),
isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
: diag::note_previous_decl) << Name;
+ if (ObjCPropery)
+ S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute)
+ << ObjCPropery->getDeclName() << 0;
} else {
S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name;
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
@@ -4800,16 +4870,19 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
DD.Triggered = true;
DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(),
DD.getDeprecationMessage(), DD.Loc,
- DD.getUnknownObjCClass());
+ DD.getUnknownObjCClass(),
+ DD.getObjCProperty());
}
void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D,
UnknownObjCClass,
+ ObjCProperty,
Message));
return;
}
@@ -4817,5 +4890,5 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
// Otherwise, don't warn if our current context is deprecated.
if (isDeclDeprecated(cast<Decl>(getCurLexicalContext())))
return;
- DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass);
+ DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass, ObjCProperty);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index eeac9b8e8d70..16eddf80ae5b 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -246,8 +246,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(),
EqualLoc);
InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &Arg, 1));
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Arg);
if (Result.isInvalid())
return true;
Arg = Result.takeAs<Expr>();
@@ -374,10 +373,10 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
}
}
-// MergeCXXFunctionDecl - Merge two declarations of the same C++
-// function, once we already know that they have the same
-// type. Subroutine of MergeFunctionDecl. Returns true if there was an
-// error, false otherwise.
+/// MergeCXXFunctionDecl - Merge two declarations of the same C++
+/// function, once we already know that they have the same
+/// type. Subroutine of MergeFunctionDecl. Returns true if there was an
+/// error, false otherwise.
bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Scope *S) {
bool Invalid = false;
@@ -676,6 +675,20 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
return true;
}
+/// \brief Get diagnostic %select index for tag kind for
+/// record diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for record diagnostic!");
+ }
+}
+
// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
// the requirements of a constexpr function definition or a constexpr
// constructor definition. If so, return true. If not, produce appropriate
@@ -692,8 +705,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
- << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
- << RD->getNumVBases();
+ << isa<CXXConstructorDecl>(NewFD)
+ << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getLocStart(),
@@ -1005,6 +1018,41 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
return false;
}
+/// \brief Determine whether the given class is a base class of the given
+/// class, including looking at dependent bases.
+static bool findCircularInheritance(const CXXRecordDecl *Class,
+ const CXXRecordDecl *Current) {
+ SmallVector<const CXXRecordDecl*, 8> Queue;
+
+ Class = Class->getCanonicalDecl();
+ while (true) {
+ for (CXXRecordDecl::base_class_const_iterator I = Current->bases_begin(),
+ E = Current->bases_end();
+ I != E; ++I) {
+ CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+ if (!Base)
+ continue;
+
+ Base = Base->getDefinition();
+ if (!Base)
+ continue;
+
+ if (Base->getCanonicalDecl() == Class)
+ return true;
+
+ Queue.push_back(Base);
+ }
+
+ if (Queue.empty())
+ return false;
+
+ Current = Queue.back();
+ Queue.pop_back();
+ }
+
+ return false;
+}
+
/// \brief Check the validity of a C++ base class specifier.
///
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
@@ -1031,13 +1079,32 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
<< TInfo->getTypeLoc().getSourceRange();
EllipsisLoc = SourceLocation();
}
-
- if (BaseType->isDependentType())
+
+ SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc();
+
+ if (BaseType->isDependentType()) {
+ // Make sure that we don't have circular inheritance among our dependent
+ // bases. For non-dependent bases, the check for completeness below handles
+ // this.
+ if (CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl()) {
+ if (BaseDecl->getCanonicalDecl() == Class->getCanonicalDecl() ||
+ ((BaseDecl = BaseDecl->getDefinition()) &&
+ findCircularInheritance(Class, BaseDecl))) {
+ Diag(BaseLoc, diag::err_circular_inheritance)
+ << BaseType << Context.getTypeDeclType(Class);
+
+ if (BaseDecl->getCanonicalDecl() != Class->getCanonicalDecl())
+ Diag(BaseDecl->getLocation(), diag::note_previous_decl)
+ << BaseType;
+
+ return 0;
+ }
+ }
+
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
Class->getTagKind() == TTK_Class,
Access, TInfo, EllipsisLoc);
-
- SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc();
+ }
// Base specifiers must be record types.
if (!BaseType->isRecordType()) {
@@ -1165,10 +1232,21 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
// Okay, add this new base class.
KnownBase = Bases[idx];
Bases[NumGoodBases++] = Bases[idx];
- if (const RecordType *Record = NewBaseType->getAs<RecordType>())
- if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()))
- if (RD->hasAttr<WeakAttr>())
- Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
+ if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (Class->isInterface() &&
+ (!RD->isInterface() ||
+ KnownBase->getAccessSpecifier() != AS_public)) {
+ // The Microsoft extension __interface does not permit bases that
+ // are not themselves public interfaces.
+ Diag(KnownBase->getLocStart(), diag::err_invalid_base_in_interface)
+ << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getName()
+ << RD->getSourceRange();
+ Invalid = true;
+ }
+ if (RD->hasAttr<WeakAttr>())
+ Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
+ }
}
}
@@ -1407,6 +1485,9 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
/// CheckOverrideControl - Check C++11 override control semantics.
void Sema::CheckOverrideControl(Decl *D) {
+ if (D->isInvalidDecl())
+ return;
+
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
// Do we know which functions this declaration might be overriding?
@@ -1496,6 +1577,50 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
bool isFunc = D.isDeclarationOfFunction();
+ if (cast<CXXRecordDecl>(CurContext)->isInterface()) {
+ // The Microsoft extension __interface only permits public member functions
+ // and prohibits constructors, destructors, operators, non-public member
+ // functions, static methods and data members.
+ unsigned InvalidDecl;
+ bool ShowDeclName = true;
+ if (!isFunc)
+ InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1;
+ else if (AS != AS_public)
+ InvalidDecl = 2;
+ else if (DS.getStorageClassSpec() == DeclSpec::SCS_static)
+ InvalidDecl = 3;
+ else switch (Name.getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ InvalidDecl = 4;
+ ShowDeclName = false;
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ InvalidDecl = 5;
+ ShowDeclName = false;
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXConversionFunctionName:
+ InvalidDecl = 6;
+ break;
+
+ default:
+ InvalidDecl = 0;
+ break;
+ }
+
+ if (InvalidDecl) {
+ if (ShowDeclName)
+ Diag(Loc, diag::err_invalid_member_in_interface)
+ << (InvalidDecl-1) << Name;
+ else
+ Diag(Loc, diag::err_invalid_member_in_interface)
+ << (InvalidDecl-1) << "";
+ return 0;
+ }
+ }
+
// C++ 9.2p6: A member shall not be declared to have automatic storage
// duration (auto, register) or with the extern storage-class-specifier.
// C++ 7.1.1p8: The mutable specifier can be applied only to names of class
@@ -1548,7 +1673,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// Member field could not be with "template" keyword.
// So TemplateParameterLists should be empty in this case.
if (TemplateParameterLists.size()) {
- TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0];
+ TemplateParameterList* TemplateParams = TemplateParameterLists[0];
if (TemplateParams->size()) {
// There is no such thing as a member field template.
Diag(D.getIdentifierLoc(), diag::err_template_member)
@@ -1588,7 +1713,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
} else {
assert(InitStyle == ICIS_NoInit);
- Member = HandleDeclarator(S, D, move(TemplateParameterLists));
+ Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member) {
return 0;
}
@@ -1662,6 +1787,99 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return Member;
}
+namespace {
+ class UninitializedFieldVisitor
+ : public EvaluatedExprVisitor<UninitializedFieldVisitor> {
+ Sema &S;
+ ValueDecl *VD;
+ public:
+ typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
+ UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
+ S(S), VD(VD) {
+ }
+
+ void HandleExpr(Expr *E) {
+ if (!E) return;
+
+ // Expressions like x(x) sometimes lack the surrounding expressions
+ // but need to be checked anyways.
+ HandleValue(E);
+ Visit(E);
+ }
+
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParens();
+
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (isa<EnumConstantDecl>(ME->getMemberDecl()))
+ return;
+ Expr *Base = E;
+ while (isa<MemberExpr>(Base)) {
+ ME = dyn_cast<MemberExpr>(Base);
+ if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
+ if (VarD->hasGlobalStorage())
+ return;
+ Base = ME->getBase();
+ }
+
+ if (VD == ME->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;
+ }
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ HandleValue(BCO->getCommon());
+ HandleValue(BCO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+ default:
+ return;
+ case(BO_PtrMemD):
+ case(BO_PtrMemI):
+ HandleValue(BO->getLHS());
+ return;
+ case(BO_Comma):
+ HandleValue(BO->getRHS());
+ return;
+ }
+ }
+ }
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ HandleValue(E->getSubExpr());
+
+ Inherited::VisitImplicitCastExpr(E);
+ }
+
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ Expr *Callee = E->getCallee();
+ if (isa<MemberExpr>(Callee))
+ HandleValue(Callee);
+
+ Inherited::VisitCXXMemberCallExpr(E);
+ }
+ };
+ static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
+ ValueDecl *VD) {
+ UninitializedFieldVisitor(S, VD).HandleExpr(E);
+ }
+} // namespace
+
/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
/// in-class initializer for a non-static C++ class member, and after
/// instantiating an in-class initializer in a class template. Such actions
@@ -1685,8 +1903,17 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
return;
}
+ if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, InitLoc)
+ != DiagnosticsEngine::Ignored) {
+ CheckInitExprContainsUninitializedFields(*this, InitExpr, FD);
+ }
+
ExprResult Init = InitExpr;
- if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
+ 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 (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
<< /*at end of ctor*/1 << InitExpr->getSourceRange();
@@ -1795,7 +2022,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
SourceLocation EllipsisLoc) {
- Expr *List = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ Expr *List = new (Context) ParenListExpr(Context, LParenLoc,
+ llvm::makeArrayRef(Args, NumArgs),
RParenLoc);
return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
DS, IdLoc, List, EllipsisLoc);
@@ -2044,96 +2272,6 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
<< (unsigned)IsPointer;
}
-namespace {
- class UninitializedFieldVisitor
- : public EvaluatedExprVisitor<UninitializedFieldVisitor> {
- Sema &S;
- ValueDecl *VD;
- public:
- typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
- UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
- S(S), VD(VD) {
- }
-
- void HandleExpr(Expr *E) {
- if (!E) return;
-
- // Expressions like x(x) sometimes lack the surrounding expressions
- // but need to be checked anyways.
- HandleValue(E);
- Visit(E);
- }
-
- void HandleValue(Expr *E) {
- E = E->IgnoreParens();
-
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (isa<EnumConstantDecl>(ME->getMemberDecl()))
- return;
- Expr *Base = E;
- while (isa<MemberExpr>(Base)) {
- ME = dyn_cast<MemberExpr>(Base);
- if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
- if (VarD->hasGlobalStorage())
- return;
- Base = ME->getBase();
- }
-
- if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
- S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit);
- return;
- }
- }
-
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- HandleValue(CO->getTrueExpr());
- HandleValue(CO->getFalseExpr());
- return;
- }
-
- if (BinaryConditionalOperator *BCO =
- dyn_cast<BinaryConditionalOperator>(E)) {
- HandleValue(BCO->getCommon());
- HandleValue(BCO->getFalseExpr());
- return;
- }
-
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- switch (BO->getOpcode()) {
- default:
- return;
- case(BO_PtrMemD):
- case(BO_PtrMemI):
- HandleValue(BO->getLHS());
- return;
- case(BO_Comma):
- HandleValue(BO->getRHS());
- return;
- }
- }
- }
-
- void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if (E->getCastKind() == CK_LValueToRValue)
- HandleValue(E->getSubExpr());
-
- Inherited::VisitImplicitCastExpr(E);
- }
-
- void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- Expr *Callee = E->getCallee();
- if (isa<MemberExpr>(Callee))
- HandleValue(Callee);
-
- Inherited::VisitCXXMemberCallExpr(E);
- }
- };
- static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
- ValueDecl *VD) {
- UninitializedFieldVisitor(S, VD).HandleExpr(E);
- }
-} // namespace
-
MemInitResult
Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
SourceLocation IdLoc) {
@@ -2167,11 +2305,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
!= DiagnosticsEngine::Ignored)
for (unsigned i = 0; i < NumArgs; ++i)
// FIXME: Warn about the case when other fields are used before being
- // uninitialized. For example, let this field be the i'th field. When
+ // initialized. For example, let this field be the i'th field. When
// initializing the i'th field, throw a warning if any of the >= i'th
// fields are used, as they are not yet initialized.
// Right now we are only handling the case where the i'th field uses
// itself in its initializer.
+ // Also need to take into account that some fields may be initialized by
+ // in-class initializers, see C++11 [class.base.init]p9.
CheckInitExprContainsUninitializedFields(*this, Args[i], Member);
SourceRange InitRange = Init->getSourceRange();
@@ -2204,7 +2344,7 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind,
- MultiExprArg(*this, Args, NumArgs),
+ MultiExprArg(Args, NumArgs),
0);
if (MemberInit.isInvalid())
return true;
@@ -2273,7 +2413,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
InitRange.getEnd());
InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs);
ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind,
- MultiExprArg(*this, Args,NumArgs),
+ MultiExprArg(Args, NumArgs),
0);
if (DelegationInit.isInvalid())
return true;
@@ -2411,8 +2551,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
InitRange.getEnd());
InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind,
- MultiExprArg(*this, Args, NumArgs),
- 0);
+ MultiExprArg(Args, NumArgs), 0);
if (BaseInit.isInvalid())
return true;
@@ -2480,8 +2619,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
- MultiExprArg(SemaRef, 0, 0));
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg());
break;
}
@@ -2936,7 +3074,11 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
NumInitializers * sizeof(CXXCtorInitializer*));
Constructor->setCtorInitializers(baseOrMemberInitializers);
}
-
+
+ // Let template instantiation know whether we had errors.
+ if (AnyErrors)
+ Constructor->setInvalidDecl();
+
return false;
}
@@ -3324,11 +3466,10 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
} else {
assert(Init->isDelegatingInitializer());
// This must be the only initializer
- if (i != 0 || NumMemInits > 1) {
- Diag(MemInits[0]->getSourceLocation(),
+ if (NumMemInits != 1) {
+ Diag(Init->getSourceLocation(),
diag::err_delegating_initializer_alone)
- << MemInits[0]->getSourceRange();
- HadError = true;
+ << Init->getSourceRange() << MemInits[i ? 0 : 1]->getSourceRange();
// We will treat this as being the only initializer.
}
SetDelegatingInitializer(Constructor, MemInits[i]);
@@ -3812,6 +3953,11 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
diag::warn_non_virtual_dtor) << Context.getRecordType(Record);
}
+ if (Record->isAbstract() && Record->hasAttr<FinalAttr>()) {
+ Diag(Record->getLocation(), diag::warn_abstract_final_class);
+ DiagnoseAbstractType(Record);
+ }
+
// See if a method overloads virtual methods in a base
/// class without overriding any.
if (!Record->isDependentType()) {
@@ -4065,7 +4211,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// Compute argument constness, constexpr, and triviality.
bool CanHaveConstParam = false;
- bool Trivial;
+ bool Trivial = false;
switch (CSM) {
case CXXDefaultConstructor:
Trivial = RD->hasTrivialDefaultConstructor();
@@ -4304,7 +4450,7 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
/// If we're operating on a base class, the object type is the
/// type of this special member.
QualType objectTy;
- AccessSpecifier access = target->getAccess();;
+ AccessSpecifier access = target->getAccess();
if (CXXBaseSpecifier *base = Subobj.dyn_cast<CXXBaseSpecifier*>()) {
objectTy = S.Context.getTypeDeclType(MD->getParent());
access = CXXRecordDecl::MergeAccess(base->getAccessSpecifier(), access);
@@ -4647,6 +4793,19 @@ namespace {
};
}
+/// \brief Check whether any most overriden method from MD in Methods
+static bool CheckMostOverridenMethods(const CXXMethodDecl *MD,
+ const llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+ if (MD->size_overridden_methods() == 0)
+ return Methods.count(MD->getCanonicalDecl());
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I)
+ if (CheckMostOverridenMethods(*I, Methods))
+ return true;
+ return false;
+}
+
/// \brief Member lookup function that determines whether a given C++
/// method overloads virtual methods in a base class without overriding any,
/// to be used with CXXRecordDecl::lookupInBases().
@@ -4678,7 +4837,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
if (!Data.S->IsOverload(Data.Method, MD, false))
return true;
// Collect the overload only if its hidden.
- if (!Data.OverridenAndUsingBaseMethods.count(MD))
+ if (!CheckMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods))
overloadedMethods.push_back(MD);
}
}
@@ -4689,6 +4848,17 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
return foundSameNameMethod;
}
+/// \brief Add the most overriden methods from MD to Methods
+static void AddMostOverridenMethods(const CXXMethodDecl *MD,
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+ if (MD->size_overridden_methods() == 0)
+ Methods.insert(MD->getCanonicalDecl());
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I)
+ AddMostOverridenMethods(*I, Methods);
+}
+
/// \brief See if a method overloads virtual methods in a base class without
/// overriding any.
void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4709,14 +4879,11 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
// 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) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*res.first))
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods();
- I != E; ++I)
- Data.OverridenAndUsingBaseMethods.insert((*I)->getCanonicalDecl());
+ NamedDecl *ND = *res.first;
if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first))
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(shad->getTargetDecl()))
- Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl());
+ ND = shad->getTargetDecl();
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+ AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods);
}
if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) &&
@@ -5307,7 +5474,47 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// Namespace Handling
//===----------------------------------------------------------------------===//
+/// \brief Diagnose a mismatch in 'inline' qualifiers when a namespace is
+/// reopened.
+static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
+ SourceLocation Loc,
+ IdentifierInfo *II, bool *IsInline,
+ NamespaceDecl *PrevNS) {
+ assert(*IsInline != PrevNS->isInline());
+
+ // HACK: Work around a bug in libstdc++4.6's <atomic>, where
+ // std::__atomic[0,1,2] are defined as non-inline namespaces, then reopened as
+ // inline namespaces, with the intention of bringing names into namespace std.
+ //
+ // We support this just well enough to get that case working; this is not
+ // sufficient to support reopening namespaces as inline in general.
+ if (*IsInline && II && II->getName().startswith("__atomic") &&
+ S.getSourceManager().isInSystemHeader(Loc)) {
+ // Mark all prior declarations of the namespace as inline.
+ for (NamespaceDecl *NS = PrevNS->getMostRecentDecl(); NS;
+ NS = NS->getPreviousDecl())
+ NS->setInline(*IsInline);
+ // Patch up the lookup table for the containing namespace. This isn't really
+ // correct, but it's good enough for this particular case.
+ for (DeclContext::decl_iterator I = PrevNS->decls_begin(),
+ E = PrevNS->decls_end(); I != E; ++I)
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*I))
+ PrevNS->getParent()->makeDeclVisibleInContext(ND);
+ return;
+ }
+
+ if (PrevNS->isInline())
+ // The user probably just forgot the 'inline', so suggest that it
+ // be added back.
+ S.Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
+ << FixItHint::CreateInsertion(KeywordLoc, "inline ");
+ else
+ S.Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
+ S.Diag(PrevNS->getLocation(), diag::note_previous_definition);
+ *IsInline = PrevNS->isInline();
+}
/// ActOnStartNamespaceDef - This is called at the start of a namespace
/// definition.
@@ -5357,21 +5564,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
if (PrevNS) {
// This is an extended namespace definition.
- if (IsInline != PrevNS->isInline()) {
- // inline-ness must match
- if (PrevNS->isInline()) {
- // The user probably just forgot the 'inline', so suggest that it
- // be added back.
- Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
- << FixItHint::CreateInsertion(NamespaceLoc, "inline ");
- } else {
- Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
- }
- Diag(PrevNS->getLocation(), diag::note_previous_definition);
-
- IsInline = PrevNS->isInline();
- }
+ if (IsInline != PrevNS->isInline())
+ DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II,
+ &IsInline, PrevNS);
} else if (PrevDecl) {
// This is an invalid name redefinition.
Diag(Loc, diag::err_redefinition_different_kind)
@@ -5402,15 +5597,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PrevNS = ND->getAnonymousNamespace();
}
- if (PrevNS && IsInline != PrevNS->isInline()) {
- // inline-ness must match
- Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
- Diag(PrevNS->getLocation(), diag::note_previous_definition);
-
- // Recover by ignoring the new namespace's inline status.
- IsInline = PrevNS->isInline();
- }
+ if (PrevNS && IsInline != PrevNS->isInline())
+ DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II,
+ &IsInline, PrevNS);
}
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
@@ -5460,15 +5649,15 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
if (!PrevNS) {
UsingDirectiveDecl* UD
- = UsingDirectiveDecl::Create(Context, CurContext,
+ = UsingDirectiveDecl::Create(Context, Parent,
/* 'using' */ LBrace,
/* 'namespace' */ SourceLocation(),
/* qualifier */ NestedNameSpecifierLoc(),
/* identifier */ SourceLocation(),
Namespc,
- /* Ancestor */ CurContext);
+ /* Ancestor */ Parent);
UD->setImplicit();
- CurContext->addDecl(UD);
+ Parent->addDecl(UD);
}
}
@@ -5697,7 +5886,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
if (DeclContext *DC = S.computeDeclContext(SS, false))
S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
<< Ident << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
S.Diag(IdentLoc, diag::err_using_directive_suggest)
<< Ident << CorrectedQuotedStr
@@ -6562,10 +6752,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (TemplateParamLists.size() != 1) {
Diag(UsingLoc, diag::err_alias_template_extra_headers)
- << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(),
- TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc());
+ << SourceRange(TemplateParamLists[1]->getTemplateLoc(),
+ TemplateParamLists[TemplateParamLists.size()-1]->getRAngleLoc());
}
- TemplateParameterList *TemplateParams = TemplateParamLists.get()[0];
+ TemplateParameterList *TemplateParams = TemplateParamLists[0];
// Only consider previous declarations in the same scope.
FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
@@ -6696,28 +6886,6 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
return AliasDecl;
}
-namespace {
- /// \brief Scoped object used to handle the state changes required in Sema
- /// to implicitly define the body of a C++ member function;
- class ImplicitlyDefinedFunctionScope {
- Sema &S;
- Sema::ContextRAII SavedContext;
-
- public:
- ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method)
- : S(S), SavedContext(S, Method)
- {
- S.PushFunctionScope();
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
- }
-
- ~ImplicitlyDefinedFunctionScope() {
- S.PopExpressionEvaluationContext();
- S.PopFunctionScopeInfo();
- }
- };
-}
-
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
CXXMethodDecl *MD) {
@@ -6861,7 +7029,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
+ SynthesizedFunctionScope Scope(*this, Constructor);
DiagnosticErrorTrap Trap(Diags);
if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
@@ -7173,7 +7341,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
if (Destructor->isInvalidDecl())
return;
- ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
+ SynthesizedFunctionScope Scope(*this, Destructor);
DiagnosticErrorTrap Trap(Diags);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
@@ -7412,7 +7580,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
= new (S.Context) BinaryOperator(IterationVarRefRVal,
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
- VK_RValue, OK_Ordinary, Loc);
+ VK_RValue, OK_Ordinary, Loc, false);
// Create the pre-increment of the iteration variable.
Expr *Increment
@@ -7654,7 +7822,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+ SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
DiagnosticErrorTrap Trap(Diags);
// C++0x [class.copy]p30:
@@ -7666,7 +7834,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// which they were declared in the class definition.
// The statements that form the synthesized function body.
- ASTOwningVector<Stmt*> Statements(*this);
+ SmallVector<Stmt*, 8> Statements;
// The parameter for the "other" object, which we are copying from.
ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
@@ -7846,8 +8014,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- CollectableMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
}
}
@@ -7866,12 +8034,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- BuiltinMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
}
- ASTOwningVector<Expr*> CallArgs(*this);
+ 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));
@@ -7879,12 +8047,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (NeedsCollectableMemCpy)
Call = ActOnCallExpr(/*Scope=*/0,
CollectableMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
else
Call = ActOnCallExpr(/*Scope=*/0,
BuiltinMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
@@ -7934,7 +8102,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
StmtResult Body;
{
CompoundScopeRAII CompoundScope(*this);
- Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ Body = ActOnCompoundStmt(Loc, Loc, Statements,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
@@ -8040,7 +8208,7 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
// reference types, are supposed to return false here, but that appears
// to be a standard defect.
CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
- if (!ClassDecl || !ClassDecl->getDefinition())
+ if (!ClassDecl || !ClassDecl->getDefinition() || ClassDecl->isInvalidDecl())
return true;
if (Type.isTriviallyCopyableType(S.Context))
@@ -8195,7 +8363,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MoveAssignOperator->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator);
+ SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
DiagnosticErrorTrap Trap(Diags);
// C++0x [class.copy]p28:
@@ -8207,7 +8375,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// definition.
// The statements that form the synthesized function body.
- ASTOwningVector<Stmt*> Statements(*this);
+ SmallVector<Stmt*, 8> Statements;
// The parameter for the "other" object, which we are move from.
ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
@@ -8395,8 +8563,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- CollectableMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
}
}
@@ -8415,12 +8583,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- BuiltinMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
}
- ASTOwningVector<Expr*> CallArgs(*this);
+ 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));
@@ -8428,12 +8596,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
if (NeedsCollectableMemCpy)
Call = ActOnCallExpr(/*Scope=*/0,
CollectableMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
else
Call = ActOnCallExpr(/*Scope=*/0,
BuiltinMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
@@ -8483,7 +8651,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
StmtResult Body;
{
CompoundScopeRAII CompoundScope(*this);
- Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ Body = ActOnCompoundStmt(Loc, Loc, Statements,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
@@ -8691,7 +8859,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
- ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
+ SynthesizedFunctionScope Scope(*this, CopyConstructor);
DiagnosticErrorTrap Trap(Diags);
if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
@@ -8703,7 +8871,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
CopyConstructor->getLocation(),
- MultiStmtArg(*this, 0, 0),
+ MultiStmtArg(),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
CopyConstructor->setImplicitlyDefined(true);
@@ -8874,7 +9042,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor");
- ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor);
+ SynthesizedFunctionScope Scope(*this, MoveConstructor);
DiagnosticErrorTrap Trap(Diags);
if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) ||
@@ -8886,7 +9054,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
Sema::CompoundScopeRAII CompoundScope(*this);
MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(),
MoveConstructor->getLocation(),
- MultiStmtArg(*this, 0, 0),
+ MultiStmtArg(),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
MoveConstructor->setImplicitlyDefined(true);
@@ -8926,7 +9094,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
Conv->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, Conv);
+ SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
// Return the address of the __invoke function.
@@ -8959,7 +9127,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
{
Conv->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, Conv);
+ SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
// Copy-initialize the lambda object as needed to capture it.
@@ -9014,12 +9182,12 @@ static bool hasOneRealArgument(MultiExprArg Args) {
return false;
default:
- if (!Args.get()[1]->isDefaultArgument())
+ if (!Args[1]->isDefaultArgument())
return false;
// fall through
case 1:
- return !Args.get()[0]->isDefaultArgument();
+ return !Args[0]->isDefaultArgument();
}
return false;
@@ -9047,12 +9215,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// directly into the target of the omitted copy/move
if (ConstructKind == CXXConstructExpr::CK_Complete &&
Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) {
- Expr *SubExpr = ((Expr **)ExprArgs.get())[0];
+ Expr *SubExpr = ExprArgs[0];
Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs), HadMultipleCandidates,
+ Elidable, ExprArgs, HadMultipleCandidates,
RequiresZeroInit, ConstructKind, ParenRange);
}
@@ -9066,12 +9234,9 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
- unsigned NumExprs = ExprArgs.size();
- Expr **Exprs = (Expr **)ExprArgs.release();
-
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
- Constructor, Elidable, Exprs, NumExprs,
+ Constructor, Elidable, ExprArgs,
HadMultipleCandidates, /*FIXME*/false,
RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
@@ -9085,7 +9250,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
// FIXME: Provide the correct paren SourceRange when available.
ExprResult TempResult =
BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor,
- move(Exprs), HadMultipleCandidates, false,
+ Exprs, HadMultipleCandidates, false,
CXXConstructExpr::CK_Complete, SourceRange());
if (TempResult.isInvalid())
return true;
@@ -9135,11 +9300,11 @@ bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
- ASTOwningVector<Expr*> &ConvertedArgs,
+ SmallVectorImpl<Expr*> &ConvertedArgs,
bool AllowExplicit) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
unsigned NumArgs = ArgsPtr.size();
- Expr **Args = (Expr **)ArgsPtr.get();
+ Expr **Args = ArgsPtr.data();
const FunctionProtoType *Proto
= Constructor->getType()->getAs<FunctionProtoType>();
@@ -9268,7 +9433,7 @@ CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
}
static bool
-CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
// C++ [basic.stc.dynamic.deallocation]p1:
// A program is ill-formed if deallocation functions are declared in a
// namespace scope other than global scope or declared static in global
@@ -9825,7 +9990,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
/// \brief Perform semantic analysis of the given friend type declaration.
///
/// \returns A friend declaration that.
-FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo) {
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
@@ -9864,7 +10029,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
diag::warn_cxx98_compat_nonclass_type_friend :
diag::ext_nonclass_type_friend)
<< T
- << SourceRange(FriendLoc, TypeRange.getEnd());
+ << TypeRange;
}
} else if (T->getAs<EnumType>()) {
Diag(FriendLoc,
@@ -9872,18 +10037,22 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
diag::warn_cxx98_compat_enum_friend :
diag::ext_enum_friend)
<< T
- << SourceRange(FriendLoc, TypeRange.getEnd());
+ << TypeRange;
}
- // C++0x [class.friend]p3:
+ // 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;
+
// If the type specifier in a friend declaration designates a (possibly
- // cv-qualified) class type, that class is declared as a friend; otherwise,
+ // cv-qualified) class type, that class is declared as a friend; otherwise,
// the friend declaration is ignored.
-
- // FIXME: C++0x has some syntactic restrictions on friend type declarations
- // in [class.friend]p3 that we do not implement.
-
- return FriendDecl::Create(Context, CurContext, Loc, TSInfo, FriendLoc);
+ return FriendDecl::Create(Context, CurContext, LocStart, TSInfo, FriendLoc);
}
/// Handle a friend tag declaration where the scope specifier was
@@ -9901,7 +10070,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
- TempParamLists.get(),
+ TempParamLists.data(),
TempParamLists.size(),
/*friend*/ true,
isExplicitSpecialization,
@@ -9916,7 +10085,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TemplateParams, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
TempParamLists.size() - 1,
- (TemplateParameterList**) TempParamLists.release()).take();
+ TempParamLists.data()).take();
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
@@ -9929,7 +10098,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
bool isAllExplicitSpecializations = true;
for (unsigned I = TempParamLists.size(); I-- > 0; ) {
- if (TempParamLists.get()[I]->size()) {
+ if (TempParamLists[I]->size()) {
isAllExplicitSpecializations = false;
break;
}
@@ -10076,7 +10245,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (unsigned NumTempParamLists = TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
NumTempParamLists,
- TempParams.release(),
+ TempParams.data(),
TSI,
DS.getFriendSpecLoc());
else
@@ -10318,7 +10487,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
bool AddToScope = true;
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
- move(TemplateParams), AddToScope);
+ TemplateParams, AddToScope);
if (!ND) return 0;
assert(ND->getDeclContext() == DC);
@@ -10435,10 +10604,10 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// If this definition appears within the record, do the checking when
// the record is complete.
const FunctionDecl *Primary = MD;
- if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
// Find the uninstantiated declaration that actually had the '= default'
// on it.
- MD->getTemplateInstantiationPattern()->isDefined(Primary);
+ Pattern->isDefined(Primary);
if (Primary == Primary->getCanonicalDecl())
return;
@@ -10963,14 +11132,16 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
if (Ctor->isInvalidDecl())
return;
- const FunctionDecl *FNTarget = 0;
- CXXConstructorDecl *Target;
-
- // We ignore the result here since if we don't have a body, Target will be
- // null below.
- (void)Ctor->getTargetConstructor()->hasBody(FNTarget);
- Target
-= const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget));
+ CXXConstructorDecl *Target = Ctor->getTargetConstructor();
+
+ // Target may not be determinable yet, for instance if this is a dependent
+ // call in an uninstantiated template.
+ if (Target) {
+ const FunctionDecl *FNTarget = 0;
+ (void)Target->hasBody(FNTarget);
+ Target = const_cast<CXXConstructorDecl*>(
+ cast_or_null<CXXConstructorDecl>(FNTarget));
+ }
CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(),
// Avoid dereferencing a null pointer here.
@@ -10994,17 +11165,18 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
diag::warn_delegating_ctor_cycle)
<< Ctor;
- // Don't add a note for a function delegating directo to itself.
+ // Don't add a note for a function delegating directly to itself.
if (TCanonical != Canonical)
S.Diag(Target->getLocation(), diag::note_it_delegates_to);
CXXConstructorDecl *C = Target;
while (C->getCanonicalDecl() != Canonical) {
+ const FunctionDecl *FNTarget = 0;
(void)C->getTargetConstructor()->hasBody(FNTarget);
assert(FNTarget && "Ctor cycle through bodiless function");
- C
- = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget));
+ C = const_cast<CXXConstructorDecl*>(
+ cast<CXXConstructorDecl>(FNTarget));
S.Diag(C->getLocation(), diag::note_which_delegates_to);
}
}
@@ -11027,9 +11199,8 @@ void Sema::CheckDelegatingCtorCycles() {
for (DelegatingCtorDeclsType::iterator
I = DelegatingCtorDecls.begin(ExternalSource),
E = DelegatingCtorDecls.end();
- I != E; ++I) {
- DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
- }
+ I != E; ++I)
+ DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
(*CI)->setInvalidDecl();
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 9da4d69382ef..c4e91e85015f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -282,6 +282,25 @@ void Sema::AddAnyMethodToGlobalPool(Decl *D) {
AddFactoryMethodToGlobalPool(MDecl, true);
}
+/// HasExplicitOwnershipAttr - returns true when pointer to ObjC pointer
+/// has explicit ownership attribute; false otherwise.
+static bool
+HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) {
+ QualType T = Param->getType();
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ T = PT->getPointeeType();
+ } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ T = RT->getPointeeType();
+ } else {
+ return true;
+ }
+
+ // If we have a lifetime qualifier, but it's local, we must have
+ // inferred it. So, it is implicit.
+ return !T.getLocalQualifiers().hasObjCLifetime();
+}
+
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
@@ -313,6 +332,12 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
RequireCompleteType(Param->getLocation(), Param->getType(),
diag::err_typecheck_decl_incomplete_type))
Param->setInvalidDecl();
+ if (!Param->isInvalidDecl() &&
+ getLangOpts().ObjCAutoRefCount &&
+ !HasExplicitOwnershipAttr(*this, Param))
+ Diag(Param->getLocation(), diag::warn_arc_strong_pointer_objc_pointer) <<
+ Param->getType();
+
if ((*PI)->getIdentifier())
PushOnScopeChains(*PI, FnBodyScope);
}
@@ -345,8 +370,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Warn on deprecated methods under -Wdeprecated-implementations,
// and prepare for warning on missing super calls.
if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) {
- if (ObjCMethodDecl *IMD =
- IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod()))
+ ObjCMethodDecl *IMD =
+ IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod());
+
+ if (IMD)
DiagnoseObjCImplementedDeprecations(*this,
dyn_cast<NamedDecl>(IMD),
MDecl->getLocation(), 0);
@@ -356,13 +383,23 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
// Only do this if the current class actually has a superclass.
if (IC->getSuperClass()) {
- getCurFunction()->ObjCShouldCallSuperDealloc =
- !(Context.getLangOpts().ObjCAutoRefCount ||
- Context.getLangOpts().getGC() == LangOptions::GCOnly) &&
- MDecl->getMethodFamily() == OMF_dealloc;
- getCurFunction()->ObjCShouldCallSuperFinalize =
- Context.getLangOpts().getGC() != LangOptions::NonGC &&
- MDecl->getMethodFamily() == OMF_finalize;
+ ObjCMethodFamily Family = MDecl->getMethodFamily();
+ if (Family == OMF_dealloc) {
+ if (!(getLangOpts().ObjCAutoRefCount ||
+ getLangOpts().getGC() == LangOptions::GCOnly))
+ getCurFunction()->ObjCShouldCallSuper = true;
+
+ } else if (Family == OMF_finalize) {
+ if (Context.getLangOpts().getGC() != LangOptions::NonGC)
+ getCurFunction()->ObjCShouldCallSuper = true;
+
+ } else {
+ const ObjCMethodDecl *SuperMethod =
+ IC->getSuperClass()->lookupMethod(MDecl->getSelector(),
+ MDecl->isInstanceMethod());
+ getCurFunction()->ObjCShouldCallSuper =
+ (SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
+ }
}
}
}
@@ -510,7 +547,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Check then save referenced protocols.
if (NumProtoRefs) {
- IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ IDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
IDecl->setEndOfDefinitionLoc(EndProtoLoc);
}
@@ -652,7 +689,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
- PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ PDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
}
@@ -819,11 +856,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
CurContext->addDecl(CDecl);
if (NumProtoRefs) {
- CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
// Protocols in the class extension belong to the class.
if (CDecl->IsClassExtension())
- IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
+ IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl*const*)ProtoRefs,
NumProtoRefs, Context);
}
@@ -1545,9 +1582,9 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
E = PDecl->instmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
- !method->isSynthesized() && !InsMap.count(method->getSelector()) &&
- (!Super ||
- !Super->lookupInstanceMethod(method->getSelector()))) {
+ !method->isPropertyAccessor() &&
+ !InsMap.count(method->getSelector()) &&
+ (!Super || !Super->lookupInstanceMethod(method->getSelector()))) {
// If a method is not implemented in the category implementation but
// has been declared in its primary class, superclass,
// or in one of their protocols, no need to issue the warning.
@@ -1560,7 +1597,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector(),
true /*shallowCategoryLookup*/))
- if (C || MethodInClass->isSynthesized())
+ if (C || MethodInClass->isPropertyAccessor())
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
@@ -1621,7 +1658,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (InsMapSeen.count((*I)->getSelector()))
continue;
InsMapSeen.insert((*I)->getSelector());
- if (!(*I)->isSynthesized() &&
+ if (!(*I)->isPropertyAccessor() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
@@ -1638,7 +1675,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
isa<ObjCProtocolDecl>(CDecl));
- else if (!MethodDecl->isSynthesized())
+ else if (!MethodDecl->isPropertyAccessor())
WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
isa<ObjCProtocolDecl>(CDecl));
}
@@ -1672,14 +1709,26 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
}
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
- // Also methods in class extensions need be looked at next.
- for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
- MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false,
- WarnCategoryMethodImpl);
+ // 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())
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
+ const_cast<ObjCCategoryDecl *>(CDeclChain),
+ IncompleteImpl, false,
+ WarnCategoryMethodImpl);
+ else
+ // Also methods in class extensions need be looked at next.
+ for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
+ ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
+ const_cast<ObjCCategoryDecl *>(ClsExtDecl),
+ IncompleteImpl, false,
+ WarnCategoryMethodImpl);
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -2339,11 +2388,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) {
if (ObjCMethodDecl *GetterMethod =
CExtDecl->getInstanceMethod(Property->getGetterName()))
- GetterMethod->setSynthesized(true);
+ GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
if (ObjCMethodDecl *SetterMethod =
CExtDecl->getInstanceMethod(Property->getSetterName()))
- SetterMethod->setSynthesized(true);
+ SetterMethod->setPropertyAccessor(true);
}
}
}
@@ -2435,26 +2484,49 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
}
static inline
+unsigned countAlignAttr(const AttrVec &A) {
+ unsigned count=0;
+ for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i)
+ if ((*i)->getKind() == attr::Aligned)
+ ++count;
+ return count;
+}
+
+static inline
bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
const AttrVec &A) {
// If method is only declared in implementation (private method),
// No need to issue any diagnostics on method definition with attributes.
if (!IMD)
return false;
-
+
// method declared in interface has no attribute.
- // But implementation has attributes. This is invalid
+ // But implementation has attributes. This is invalid.
+ // Except when implementation has 'Align' attribute which is
+ // immaterial to method declared in interface.
if (!IMD->hasAttrs())
- return true;
+ return (A.size() > countAlignAttr(A));
const AttrVec &D = IMD->getAttrs();
- if (D.size() != A.size())
- return true;
+ unsigned countAlignOnImpl = countAlignAttr(A);
+ if (!countAlignOnImpl && (A.size() != D.size()))
+ return true;
+ else if (countAlignOnImpl) {
+ unsigned countAlignOnDecl = countAlignAttr(D);
+ if (countAlignOnDecl && (A.size() != D.size()))
+ return true;
+ else if (!countAlignOnDecl &&
+ ((A.size()-countAlignOnImpl) != D.size()))
+ return true;
+ }
+
// attributes on method declaration and definition must match exactly.
// Note that we have at most a couple of attributes on methods, so this
// n*n search is good enough.
for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) {
+ if ((*i)->getKind() == attr::Aligned)
+ continue;
bool match = false;
for (AttrVec::const_iterator i1 = D.begin(), e1 = D.end(); i1 != e1; ++i1) {
if ((*i)->getKind() == (*i1)->getKind()) {
@@ -2465,6 +2537,7 @@ bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
if (!match)
return true;
}
+
return false;
}
@@ -2525,7 +2598,7 @@ public:
// with this selector before.
Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector);
if (it == S.MethodPool.end()) {
- if (!S.ExternalSource) return;
+ if (!S.getExternalSource()) return;
S.ReadMethodPool(selector);
it = S.MethodPool.find(selector);
@@ -2767,7 +2840,7 @@ Decl *Sema::ActOnMethodDeclaration(
ResultTInfo,
CurContext,
MethodType == tok::minus, isVariadic,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/false, /*isDefined=*/false,
MethodDeclKind == tok::objc_optional
? ObjCMethodDecl::Optional
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index e6266fb0863a..e1f4888d632f 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -120,6 +120,24 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
+/// Determine whether a function has an implicitly-generated exception
+/// specification.
+static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
+ if (!isa<CXXDestructorDecl>(Decl) &&
+ Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return false;
+
+ // If the user didn't declare the function, its exception specification must
+ // be implicit.
+ if (!Decl->getTypeSourceInfo())
+ return true;
+
+ const FunctionProtoType *Ty =
+ Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
+ return !Ty->hasExceptionSpec();
+}
+
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
@@ -129,25 +147,35 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
- if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
- PDiag(diag::note_previous_declaration),
- Old->getType()->getAs<FunctionProtoType>(),
- Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(),
- New->getLocation(),
- &MissingExceptionSpecification,
- &MissingEmptyExceptionSpecification,
- /*AllowNoexceptAllMatchWithNoSpec=*/true,
- IsOperatorNew))
+ // Check the types as written: they must match before any exception
+ // specification adjustment is applied.
+ if (!CheckEquivalentExceptionSpec(
+ PDiag(DiagID), PDiag(diag::note_previous_declaration),
+ Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
+ &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
+ /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
+ // C++11 [except.spec]p4 [DR1492]:
+ // 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 &&
+ hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
+ Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
+ << hasImplicitExceptionSpec(Old);
+ if (!Old->getLocation().isInvalid())
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
return false;
+ }
// The failure was something other than an empty exception
// specification; return an error.
if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
return true;
- const FunctionProtoType *NewProto
- = New->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *NewProto =
+ New->getType()->getAs<FunctionProtoType>();
// The new function declaration is only missing an empty exception
// specification "throw()". If the throw() specification came from a
@@ -172,8 +200,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
}
if (MissingExceptionSpecification && NewProto) {
- const FunctionProtoType *OldProto
- = Old->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *OldProto =
+ Old->getType()->getAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
@@ -290,14 +318,17 @@ bool Sema::CheckEquivalentExceptionSpec(
unsigned DiagID = diag::err_mismatched_exception_spec;
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
- return CheckEquivalentExceptionSpec(
- PDiag(DiagID),
+ return CheckEquivalentExceptionSpec(PDiag(DiagID),
PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
}
/// CheckEquivalentExceptionSpec - Check if the two types have compatible
/// exception specifications. See C++ [except.spec]p3.
+///
+/// \return \c false if the exception specifications match, \c true if there is
+/// a problem. If \c true is returned, either a diagnostic has already been
+/// produced or \c *MissingExceptionSpecification is set to \c true.
bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
const PartialDiagnostic & NoteID,
const FunctionProtoType *Old,
@@ -1029,6 +1060,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::PseudoObjectExprClass:
case Expr::SubstNonTypeTemplateParmExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::FunctionParmPackExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3875ba171366..bf4abfcb7460 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -66,6 +66,15 @@ bool Sema::CanUseDecl(NamedDecl *D) {
return true;
}
+static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
+ // Warn if this is used but marked unused.
+ if (D->hasAttr<UnusedAttr>()) {
+ const Decl *DC = cast<Decl>(S.getCurObjCLexicalContext());
+ if (!DC->hasAttr<UnusedAttr>())
+ S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ }
+}
+
static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass) {
@@ -78,6 +87,17 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
Result = TheEnumDecl->getAvailability(&Message);
}
+
+ const ObjCPropertyDecl *ObjCPDecl = 0;
+ if (Result == AR_Deprecated || Result == AR_Unavailable) {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
+ AvailabilityResult PDeclResult = PD->getAvailability(0);
+ if (PDeclResult == Result)
+ ObjCPDecl = PD;
+ }
+ }
+ }
switch (Result) {
case AR_Available:
@@ -85,23 +105,30 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
break;
case AR_Deprecated:
- S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass);
+ S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass, ObjCPDecl);
break;
case AR_Unavailable:
if (S.getCurContextAvailability() != AR_Unavailable) {
if (Message.empty()) {
- if (!UnknownObjCClass)
+ if (!UnknownObjCClass) {
S.Diag(Loc, diag::err_unavailable) << D->getDeclName();
+ if (ObjCPDecl)
+ S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute)
+ << ObjCPDecl->getDeclName() << 1;
+ }
else
S.Diag(Loc, diag::warn_unavailable_fwdclass_message)
<< D->getDeclName();
}
- else
+ else
S.Diag(Loc, diag::err_unavailable_message)
<< D->getDeclName() << Message;
- S.Diag(D->getLocation(), diag::note_unavailable_here)
- << isa<FunctionDecl>(D) << false;
+ S.Diag(D->getLocation(), diag::note_unavailable_here)
+ << isa<FunctionDecl>(D) << false;
+ if (ObjCPDecl)
+ S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute)
+ << ObjCPDecl->getDeclName() << 1;
}
break;
}
@@ -250,9 +277,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
}
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
- // Warn if this is used but marked unused.
- if (D->hasAttr<UnusedAttr>())
- Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ DiagnoseUnusedOfDecl(*this, D, Loc);
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
@@ -502,7 +527,7 @@ ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
Res = DefaultLvalueConversion(Res.take());
if (Res.isInvalid())
return ExprError();
- return move(Res);
+ return Res;
}
@@ -1098,8 +1123,8 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
unsigned NumAssocs = ArgTypes.size();
assert(NumAssocs == ArgExprs.size());
- ParsedType *ParsedTypes = ArgTypes.release();
- Expr **Exprs = ArgExprs.release();
+ ParsedType *ParsedTypes = ArgTypes.data();
+ Expr **Exprs = ArgExprs.data();
TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
for (unsigned i = 0; i < NumAssocs; ++i) {
@@ -1185,8 +1210,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
if (IsResultDependent)
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
- Types, Exprs, NumAssocs, DefaultLoc,
- RParenLoc, ContainsUnexpandedParameterPack));
+ llvm::makeArrayRef(Types, NumAssocs),
+ llvm::makeArrayRef(Exprs, NumAssocs),
+ DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack));
SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
@@ -1240,8 +1266,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
- Types, Exprs, NumAssocs, DefaultLoc,
- RParenLoc, ContainsUnexpandedParameterPack,
+ llvm::makeArrayRef(Types, NumAssocs),
+ llvm::makeArrayRef(Exprs, NumAssocs),
+ DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack,
ResultIndex));
}
@@ -1402,6 +1429,15 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
MarkDeclRefReferenced(E);
+ if (getLangOpts().ObjCARCWeak && isa<VarDecl>(D) &&
+ Ty.getObjCLifetime() == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ E->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(E);
+ }
+
// Just in case we're building an illegal pointer-to-member.
FieldDecl *FD = dyn_cast<FieldDecl>(D);
if (FD && FD->isBitField())
@@ -1428,11 +1464,9 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- Id.TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(Id.TemplateId->getTemplateArgs(),
Id.TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr, Buffer);
- TemplateArgsPtr.release();
TemplateName TName = Id.TemplateId->Template.get();
SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc;
@@ -1606,7 +1640,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
if (ND)
Diag(ND->getLocation(), diag::note_previous_decl)
<< CorrectedQuotedStr;
@@ -1797,7 +1832,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// lookup fails and no expression will be built to reference it.
if (!E.isInvalid() && !E.get())
return ExprError();
- return move(E);
+ return E;
}
}
}
@@ -1860,9 +1895,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
/// this path.
ExprResult
Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo) {
- DeclContext *DC;
- if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext())
+ const DeclarationNameInfo &NameInfo,
+ bool IsAddressOfOperand) {
+ DeclContext *DC = computeDeclContext(SS, false);
+ if (!DC)
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
NameInfo, /*TemplateArgs=*/0);
@@ -1875,13 +1911,26 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
if (R.isAmbiguous())
return ExprError();
+ if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/0);
+
if (R.empty()) {
Diag(NameInfo.getLoc(), diag::err_no_member)
<< NameInfo.getName() << DC << SS.getRange();
return ExprError();
}
- return BuildDeclarationNameExpr(SS, R, /*ADL*/ false);
+ // Defend against this resolving to an implicit member access. We usually
+ // won't get here if this might be a legitimate a class member (we end up in
+ // BuildMemberReferenceExpr instead), but this can be valid if we're forming
+ // a pointer-to-member or in an unevaluated context in C++11.
+ if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand)
+ return BuildPossibleImplicitMemberExpr(SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ R, /*TemplateArgs=*/0);
+
+ return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
}
/// LookupInObjCMethod - The parser has read a name in, and Sema has
@@ -1965,9 +2014,25 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCMethodFamily MF = CurMethod->getMethodFamily();
if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize)
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
- return Owned(new (Context)
- ObjCIvarRefExpr(IV, IV->getType(), Loc,
- SelfExpr.take(), true, true));
+
+ ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ Loc,
+ SelfExpr.take(),
+ true, true);
+
+ if (getLangOpts().ObjCAutoRefCount) {
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ if (CurContext->isClosure())
+ Diag(Loc, diag::warn_implicitly_retains_self)
+ << FixItHint::CreateInsertion(Loc, "self->");
+ }
+
+ return Owned(Result);
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -2416,6 +2481,14 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
case Decl::Function: {
+ if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
+ if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+ type = Context.BuiltinFnTy;
+ valueKind = VK_RValue;
+ break;
+ }
+ }
+
const FunctionType *fty = type->castAs<FunctionType>();
// If we're referring to a function with an __unknown_anytype
@@ -2615,19 +2688,20 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
return ActOnIntegerConstant(Tok.getLocation(), Val-'0');
}
- SmallString<512> IntegerBuffer;
- // Add padding so that NumericLiteralParser can overread by one character.
- IntegerBuffer.resize(Tok.getLength()+1);
- const char *ThisTokBegin = &IntegerBuffer[0];
+ SmallString<128> SpellingBuffer;
+ // NumericLiteralParser wants to overread by one character. Add padding to
+ // the buffer in case the token is copied to the buffer. If getSpelling()
+ // returns a StringRef to the memory buffer, it should have a null char at
+ // the EOF, so it is also safe.
+ SpellingBuffer.resize(Tok.getLength() + 1);
// Get the spelling of the token, which eliminates trigraphs, etc.
bool Invalid = false;
- unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid);
+ StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid);
if (Invalid)
return ExprError();
- NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
- Tok.getLocation(), PP);
+ NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), PP);
if (Literal.hadError)
return ExprError();
@@ -2693,7 +2767,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Context.CharTy, llvm::APInt(32, Length + 1),
ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
- Context, StringRef(ThisTokBegin, Length), StringLiteral::Ascii,
+ Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
/*Pascal*/false, StrTy, &TokLoc, 1);
return BuildLiteralOperatorCall(R, OpNameInfo,
llvm::makeArrayRef(&Lit, 1), TokLoc);
@@ -2709,7 +2783,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
bool CharIsUnsigned = Context.CharTy->isUnsignedIntegerType();
llvm::APSInt Value(CharBits, CharIsUnsigned);
for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
- Value = ThisTokBegin[I];
+ Value = TokSpelling[I];
TemplateArgument Arg(Context, Value, Context.CharTy);
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
@@ -2747,11 +2821,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else {
QualType Ty;
- // long long is a C99 feature.
- if (!getLangOpts().C99 && Literal.isLongLong)
- Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!getLangOpts().C99 && Literal.isLongLong) {
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ Diag(Tok.getLocation(), diag::ext_c99_longlong);
+ }
// Get the value in the widest-possible width.
unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
@@ -3140,7 +3218,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
Expr *ArgEx = (Expr *)TyOrEx;
ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind);
- return move(Result);
+ return Result;
}
static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
@@ -3167,7 +3245,7 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
ExprResult PR = S.CheckPlaceholderExpr(V.get());
if (PR.isInvalid()) return QualType();
if (PR.get() != V.get()) {
- V = move(PR);
+ V = PR;
return CheckRealImagOperand(S, V, Loc, IsReal);
}
@@ -3442,8 +3520,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Expr *ResultE = Result.takeAs<Expr>();
InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1);
- Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &ResultE, 1));
+ Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
if (Result.isInvalid())
return ExprError();
@@ -3776,28 +3853,25 @@ ExprResult
Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig) {
- unsigned NumArgs = ArgExprs.size();
-
// Since this might be a postfix expression, get rid of ParenListExprs.
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn);
if (Result.isInvalid()) return ExprError();
Fn = Result.take();
- Expr **Args = ArgExprs.release();
-
if (getLangOpts().CPlusPlus) {
// If this is a pseudo-destructor expression, build the call immediately.
if (isa<CXXPseudoDestructorExpr>(Fn)) {
- if (NumArgs > 0) {
+ if (!ArgExprs.empty()) {
// Pseudo-destructor calls should not have any arguments.
Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
<< FixItHint::CreateRemoval(
- SourceRange(Args[0]->getLocStart(),
- Args[NumArgs-1]->getLocEnd()));
+ SourceRange(ArgExprs[0]->getLocStart(),
+ ArgExprs.back()->getLocEnd()));
}
- return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
- VK_RValue, RParenLoc));
+ return Owned(new (Context) CallExpr(Context, Fn, MultiExprArg(),
+ Context.VoidTy, VK_RValue,
+ RParenLoc));
}
// Determine whether this is a dependent call inside a C++ template,
@@ -3807,17 +3881,16 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
bool Dependent = false;
if (Fn->isTypeDependent())
Dependent = true;
- else if (Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Args, NumArgs)))
+ else if (Expr::hasAnyTypeDependentArguments(ArgExprs))
Dependent = true;
if (Dependent) {
if (ExecConfig) {
return Owned(new (Context) CUDAKernelCallExpr(
- Context, Fn, cast<CallExpr>(ExecConfig), Args, NumArgs,
+ Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs,
Context.DependentTy, VK_RValue, RParenLoc));
} else {
- return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs,
+ return Owned(new (Context) CallExpr(Context, Fn, ArgExprs,
Context.DependentTy, VK_RValue,
RParenLoc));
}
@@ -3825,8 +3898,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
// Determine whether this is a call to an object (C++ [over.call.object]).
if (Fn->getType()->isRecordType())
- return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
- RParenLoc));
+ return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc,
+ ArgExprs.data(),
+ ArgExprs.size(), RParenLoc));
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
@@ -3835,8 +3909,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
}
if (Fn->getType() == Context.BoundMemberTy) {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- RParenLoc);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc);
}
}
@@ -3849,11 +3923,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
OverloadExpr *ovl = find.Expression;
if (isa<UnresolvedLookupExpr>(ovl)) {
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl);
- return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc, ExecConfig);
} else {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- RParenLoc);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc);
}
}
}
@@ -3877,8 +3951,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
else if (isa<MemberExpr>(NakedFn))
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
- return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc,
- ExecConfig, IsExecConfig);
+ return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc, ExecConfig,
+ IsExecConfig);
}
ExprResult
@@ -3932,9 +4007,19 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
SourceLocation RParenLoc,
Expr *Config, bool IsExecConfig) {
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+ unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
// Promote the function operand.
- ExprResult Result = UsualUnaryConversions(Fn);
+ // We special-case function promotion here because we only allow promoting
+ // builtin functions to function pointers in the callee of a call.
+ ExprResult Result;
+ if (BuiltinID &&
+ Fn->getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)) {
+ Result = ImpCastExprToType(Fn, Context.getPointerType(FDecl->getType()),
+ CK_BuiltinFnToFnPtr).take();
+ } else {
+ Result = UsualUnaryConversions(Fn);
+ }
if (Result.isInvalid())
return ExprError();
Fn = Result.take();
@@ -3945,19 +4030,17 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (Config)
TheCall = new (Context) CUDAKernelCallExpr(Context, Fn,
cast<CallExpr>(Config),
- Args, NumArgs,
+ llvm::makeArrayRef(Args,NumArgs),
Context.BoolTy,
VK_RValue,
RParenLoc);
else
TheCall = new (Context) CallExpr(Context, Fn,
- Args, NumArgs,
+ llvm::makeArrayRef(Args, NumArgs),
Context.BoolTy,
VK_RValue,
RParenLoc);
- unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
-
// Bail out early if calling a builtin with custom typechecking.
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
@@ -4143,9 +4226,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
SourceRange(LParenLoc, RParenLoc),
/*InitList=*/true);
InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &LiteralExpr, 1),
- &literalType);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, LiteralExpr,
+ &literalType);
if (Result.isInvalid())
return ExprError();
LiteralExpr = Result.get();
@@ -4167,28 +4249,25 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ExprResult
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
- unsigned NumInit = InitArgList.size();
- Expr **InitList = InitArgList.release();
-
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
- for (unsigned I = 0; I != NumInit; ++I) {
- if (InitList[I]->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(InitList[I]);
+ for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
+ if (InitArgList[I]->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(InitArgList[I]);
// Ignore failures; dropping the entire initializer list because
// of one failure would be terrible for indexing/etc.
if (result.isInvalid()) continue;
- InitList[I] = result.take();
+ InitArgList[I] = result.take();
}
}
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
- InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList,
- NumInit, RBraceLoc);
+ InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
+ RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
return Owned(E);
}
@@ -4575,8 +4654,7 @@ 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[0],
- initExprs.size(), RParenLoc);
+ initExprs, RParenLoc);
initE->setType(Ty);
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
}
@@ -4603,10 +4681,8 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ExprResult Sema::ActOnParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val) {
- unsigned nexprs = Val.size();
- Expr **exprs = reinterpret_cast<Expr**>(Val.release());
- assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
- Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ assert(Val.data() != 0 && "ActOnParenOrParenListExpr() missing expr list");
+ Expr *expr = new (Context) ParenListExpr(Context, L, Val, R);
return Owned(expr);
}
@@ -4884,11 +4960,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult LHSResult = CheckPlaceholderExpr(LHS.get());
if (!LHSResult.isUsable()) return QualType();
- LHS = move(LHSResult);
+ LHS = LHSResult;
ExprResult RHSResult = CheckPlaceholderExpr(RHS.get());
if (!RHSResult.isUsable()) return QualType();
- RHS = move(RHSResult);
+ RHS = RHSResult;
// C++ is sufficiently different to merit its own checker.
if (getLangOpts().CPlusPlus)
@@ -5247,7 +5323,7 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
<< BinaryOperator::getOpcodeStr(CondOpcode);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_conditional_silence)
+ Self.PDiag(diag::note_precedence_silence)
<< BinaryOperator::getOpcodeStr(CondOpcode),
SourceRange(Condition->getLocStart(), Condition->getLocEnd()));
@@ -5811,8 +5887,7 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C,
// of the transparent union.
Expr *E = EResult.take();
InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
- &E, 1,
- SourceLocation());
+ E, SourceLocation());
Initializer->setType(UnionType);
Initializer->setInitializedFieldInUnion(Field);
@@ -5910,7 +5985,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
!CheckObjCARCUnavailableWeakConversion(LHSType,
RHS.get()->getType()))
result = IncompatibleObjCWeakRef;
- RHS = move(Res);
+ RHS = Res;
return result;
}
@@ -6708,7 +6783,7 @@ static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc,
}
static bool isObjCObjectLiteral(ExprResult &E) {
- switch (E.get()->getStmtClass()) {
+ switch (E.get()->IgnoreParenImpCasts()->getStmtClass()) {
case Stmt::ObjCArrayLiteralClass:
case Stmt::ObjCDictionaryLiteralClass:
case Stmt::ObjCStringLiteralClass:
@@ -6800,6 +6875,7 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
LK_String
} LiteralKind;
+ Literal = Literal->IgnoreParenImpCasts();
switch (Literal->getStmtClass()) {
case Stmt::ObjCStringLiteralClass:
// "string literal"
@@ -7202,7 +7278,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
(LHSType->isIntegerType() && RHSType->isAnyPointerType())) {
unsigned DiagID = 0;
bool isError = false;
- if ((LHSIsNull && LHSType->isIntegerType()) ||
+ if (LangOpts.DebuggerSupport) {
+ // Under a debugger, allow the comparison of pointers to integers,
+ // since users tend to want to compare addresses.
+ } else if ((LHSIsNull && LHSType->isIntegerType()) ||
(RHSIsNull && RHSType->isIntegerType())) {
if (IsRelational && !getLangOpts().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
@@ -7419,12 +7498,12 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
if (LHSRes.isInvalid())
return InvalidOperands(Loc, LHS, RHS);
- LHS = move(LHSRes);
+ LHS = LHSRes;
ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
if (RHSRes.isInvalid())
return InvalidOperands(Loc, LHS, RHS);
- RHS = move(RHSRes);
+ RHS = RHSRes;
// C++ [expr.log.and]p2
// C++ [expr.log.or]p2
@@ -7683,10 +7762,31 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
}
if (ConvTy == Compatible) {
- if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
- checkRetainCycles(LHSExpr, RHS.get());
- else if (getLangOpts().ObjCAutoRefCount)
+ if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Warn about retain cycles where a block captures the LHS, but
+ // not if the LHS is a simple variable into which the block is
+ // being stored...unless that variable can be captured by reference!
+ const Expr *InnerLHS = LHSExpr->IgnoreParenCasts();
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InnerLHS);
+ if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>())
+ checkRetainCycles(LHSExpr, RHS.get());
+
+ // It is safe to assign a weak reference into a strong variable.
+ // Although this code can still have problems:
+ // id x = self.weakProp;
+ // id y = self.weakProp;
+ // we do not warn to warn spuriously when 'x' and 'y' are on separate
+ // paths through the function. This should be revisited if
+ // -Wrepeated-use-of-weak is made flow-sensitive.
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ RHS.get()->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(RHS.get());
+
+ } else if (getLangOpts().ObjCAutoRefCount) {
checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get());
+ }
}
} else {
// Compound assignment "x += y"
@@ -7972,8 +8072,16 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
- S.Diag(OpLoc, diag::err_unqualified_pointer_member_function)
- << op->getSourceRange();
+ if (MD->getParent()->getName().empty())
+ S.Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+ << op->getSourceRange();
+ else {
+ SmallString<32> Str;
+ StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str);
+ S.Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+ << op->getSourceRange()
+ << FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual);
+ }
}
return S.Context.getMemberPointerType(op->getType(),
@@ -8216,8 +8324,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(LHSExpr->getType());
InitializationSequence InitSeq(*this, Entity, Kind, &RHSExpr, 1);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(&RHSExpr, 1));
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr);
if (Init.isInvalid())
return Init;
RHSExpr = Init.take();
@@ -8340,7 +8447,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (CompResultTy.isNull())
return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
- ResultTy, VK, OK, OpLoc));
+ ResultTy, VK, OK, OpLoc,
+ FPFeatures.fp_contract));
if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
@@ -8348,7 +8456,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
}
return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, CompLHSTy,
- CompResultTy, OpLoc));
+ CompResultTy, OpLoc,
+ FPFeatures.fp_contract));
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -8383,8 +8492,8 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(),
OpLoc)
: SourceRange(OpLoc, RHSExpr->getLocEnd());
- std::string OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
- : BinOp::getOpcodeStr(RHSopc);
+ StringRef OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
+ : BinOp::getOpcodeStr(RHSopc);
SourceRange ParensRange = isLeftComp ?
SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(),
RHSExpr->getLocEnd())
@@ -8394,7 +8503,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
<< DiagRange << BinOp::getOpcodeStr(Opc) << OpStr;
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr,
+ Self.PDiag(diag::note_precedence_silence) << OpStr,
(isLeftComp ? LHSExpr : RHSExpr)->getSourceRange());
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc),
@@ -8411,7 +8520,8 @@ EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc,
Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or)
<< Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence),
+ Self.PDiag(diag::note_precedence_silence)
+ << Bop->getOpcodeStr(),
Bop->getSourceRange());
}
@@ -8425,7 +8535,8 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or)
<< Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::note_logical_and_in_logical_or_silence),
+ Self.PDiag(diag::note_precedence_silence)
+ << Bop->getOpcodeStr(),
Bop->getSourceRange());
}
@@ -8489,6 +8600,20 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
}
}
+static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc,
+ Expr *SubExpr, StringRef Shift) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(SubExpr)) {
+ if (Bop->getOpcode() == BO_Add || Bop->getOpcode() == BO_Sub) {
+ StringRef Op = Bop->getOpcodeStr();
+ S.Diag(Bop->getOperatorLoc(), diag::warn_addition_in_bitshift)
+ << Bop->getSourceRange() << OpLoc << Shift << Op;
+ SuggestParentheses(S, Bop->getOperatorLoc(),
+ S.PDiag(diag::note_precedence_silence) << Op,
+ Bop->getSourceRange());
+ }
+ }
+}
+
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
/// precedence.
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
@@ -8510,6 +8635,13 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr);
DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr);
}
+
+ if ((Opc == BO_Shl && LHSExpr->getType()->isIntegralType(Self.getASTContext()))
+ || Opc == BO_Shr) {
+ StringRef Shift = BinaryOperator::getOpcodeStr(Opc);
+ DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift);
+ DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift);
+ }
}
// Binary Operators. 'Tok' is the token for the operator.
@@ -8647,6 +8779,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
break;
case UO_Deref: {
Input = DefaultFunctionArrayLvalueConversion(Input.take());
+ if (Input.isInvalid()) return ExprError();
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break;
}
@@ -9147,8 +9280,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
}
return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc,
- TInfo, Comps.data(), Comps.size(),
- Exprs.data(), Exprs.size(), RParenLoc));
+ TInfo, Comps, Exprs, RParenLoc));
}
ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
@@ -9526,6 +9658,16 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
if (Result.isInvalid())
return ExprError();
E = Result.take();
+ } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) {
+ // If va_list is a record type and we are compiling in C++ mode,
+ // check the argument using reference binding.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context,
+ Context.getLValueReferenceType(VaListType), false);
+ ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E);
+ if (Init.isInvalid())
+ return ExprError();
+ E = Init.takeAs<Expr>();
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
@@ -10094,6 +10236,14 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
+void
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ ReuseLambdaContextDecl_t,
+ bool IsDecltype) {
+ Decl *LambdaContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+ PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype);
+}
+
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
@@ -10191,15 +10341,44 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
Func->setReferenced();
- // Don't mark this function as used multiple times, unless it's a constexpr
- // function which we need to instantiate.
- if (Func->isUsed(false) &&
- !(Func->isConstexpr() && !Func->getBody() &&
- Func->isImplicitlyInstantiable()))
- return;
-
- if (!IsPotentiallyEvaluatedContext(*this))
- return;
+ // C++11 [basic.def.odr]p3:
+ // A function whose name appears as a potentially-evaluated expression is
+ // odr-used if it is the unique lookup result or the selected member of a
+ // set of overloaded functions [...].
+ //
+ // We (incorrectly) mark overload resolution as an unevaluated context, so we
+ // can just check that here. Skip the rest of this function if we've already
+ // marked the function as used.
+ if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) {
+ // C++11 [temp.inst]p3:
+ // Unless a function template specialization has been explicitly
+ // instantiated or explicitly specialized, the function template
+ // specialization is implicitly instantiated when the specialization is
+ // referenced in a context that requires a function definition to exist.
+ //
+ // We consider constexpr function templates to be referenced in a context
+ // that requires a definition to exist whenever they are referenced.
+ //
+ // FIXME: This instantiates constexpr functions too frequently. If this is
+ // really an unevaluated context (and we're not just in the definition of a
+ // function template or overload resolution or other cases which we
+ // incorrectly consider to be unevaluated contexts), and we're not in a
+ // subexpression which we actually need to evaluate (for instance, a
+ // template argument, array bound or an expression in a braced-init-list),
+ // we are not permitted to instantiate this constexpr function definition.
+ //
+ // FIXME: This also implicitly defines special members too frequently. They
+ // are only supposed to be implicitly defined if they are odr-used, but they
+ // are not odr-used from constant expressions in unevaluated contexts.
+ // However, they cannot be referenced if they are deleted, and they are
+ // deleted whenever the implicit definition of the special member would
+ // fail.
+ if (!Func->isConstexpr() || Func->getBody())
+ return;
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
+ if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided()))
+ return;
+ }
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
@@ -10469,8 +10648,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1);
ExprResult Result(true);
if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1))
- Result = Init.Perform(S, Entities.back(), InitKind,
- MultiExprArg(S, &Ref, 1));
+ Result = Init.Perform(S, Entities.back(), InitKind, Ref);
// If this initialization requires any cleanups (e.g., due to a
// default argument to a copy constructor), note that for the
@@ -10886,20 +11064,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
- // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
- // an object that satisfies the requirements for appearing in a
- // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
+ // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
+ // the requirements for appearing in a constant expression (5.19) and, if
+ // it is an object, the lvalue-to-rvalue conversion (4.1)
// is immediately applied." We check the first part here, and
// Sema::UpdateMarkingForLValueToRValue deals with the second part.
// Note that we use the C++11 definition everywhere because nothing in
- // C++03 depends on whether we get the C++03 version correct. This does not
- // apply to references, since they are not objects.
+ // C++03 depends on whether we get the C++03 version correct. The second
+ // part does not apply to references, since they are not objects.
const VarDecl *DefVD;
- if (E && !isa<ParmVarDecl>(Var) && !Var->getType()->isReferenceType() &&
+ if (E && !isa<ParmVarDecl>(Var) &&
Var->isUsableInConstantExpressions(SemaRef.Context) &&
- Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
- SemaRef.MaybeODRUseExprs.insert(E);
- else
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) {
+ if (!Var->getType()->isReferenceType())
+ SemaRef.MaybeODRUseExprs.insert(E);
+ } else
MarkVarDeclODRUsed(SemaRef, Var, Loc);
}
@@ -11205,7 +11384,9 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
IsOrAssign = Op->getOperator() == OO_PipeEqual;
Loc = Op->getOperatorLoc();
- } else {
+ } else if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ return DiagnoseAssignmentAsCondition(POE->getSyntacticForm());
+ else {
// Not an assignment.
return;
}
@@ -11759,6 +11940,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::PseudoObject:
return checkPseudoObjectRValue(E);
+ case BuiltinType::BuiltinFn:
+ Diag(E->getLocStart(), diag::err_builtin_fn_use);
+ return ExprError();
+
// Everything else should be impossible.
#define BUILTIN_TYPE(Id, SingletonId) \
case BuiltinType::Id:
@@ -11783,6 +11968,18 @@ ExprResult
Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
assert((Kind == tok::kw___objc_yes || Kind == tok::kw___objc_no) &&
"Unknown Objective-C Boolean value!");
+ QualType BoolT = Context.ObjCBuiltinBoolTy;
+ if (!Context.getBOOLDecl()) {
+ LookupResult Result(*this, &Context.Idents.get("BOOL"), OpLoc,
+ Sema::LookupOrdinaryName);
+ if (LookupName(Result, getCurScope()) && Result.isSingleResult()) {
+ NamedDecl *ND = Result.getFoundDecl();
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
+ Context.setBOOLDecl(TD);
+ }
+ }
+ if (Context.getBOOLDecl())
+ BoolT = Context.getBOOLType();
return Owned(new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes,
- Context.ObjCBuiltinBoolTy, OpLoc));
+ BoolT, OpLoc));
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 27402599a401..0919bc5b6fa4 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -410,33 +410,13 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc);
}
-/// Retrieve the UuidAttr associated with QT.
-static UuidAttr *GetUuidAttrOfType(QualType QT) {
- // Optionally remove one level of pointer, reference or array indirection.
- const Type *Ty = QT.getTypePtr();;
- if (QT->isPointerType() || QT->isReferenceType())
- Ty = QT->getPointeeType().getTypePtr();
- else if (QT->isArrayType())
- Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
-
- // Loop all record redeclaration looking for an uuid attribute.
- CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
- if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
- return Uuid;
- }
-
- return 0;
-}
-
/// \brief Build a Microsoft __uuidof expression with a type operand.
ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
if (!Operand->getType()->isDependentType()) {
- if (!GetUuidAttrOfType(Operand->getType()))
+ if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType()))
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
}
@@ -452,7 +432,7 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
Expr *E,
SourceLocation RParenLoc) {
if (!E->getType()->isDependentType()) {
- if (!GetUuidAttrOfType(E->getType()) &&
+ if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType()) &&
!E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
}
@@ -808,21 +788,18 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
MultiExprArg exprs,
SourceLocation RParenLoc) {
QualType Ty = TInfo->getType();
- unsigned NumExprs = exprs.size();
- Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
- if (Ty->isDependentType() ||
- CallExpr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Exprs, NumExprs))) {
- exprs.release();
-
+ if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(exprs)) {
return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo,
LParenLoc,
- Exprs, NumExprs,
+ exprs,
RParenLoc));
}
+ unsigned NumExprs = exprs.size();
+ Expr **Exprs = exprs.data();
+
bool ListInitialization = LParenLoc.isInvalid();
assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0])))
&& "List initialization must have initializer list as expression.");
@@ -835,7 +812,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// corresponding cast expression.
if (NumExprs == 1 && !ListInitialization) {
Expr *Arg = Exprs[0];
- exprs.release();
return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
}
@@ -865,7 +841,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
: InitializationKind::CreateValue(TyBeginLoc,
LParenLoc, RParenLoc);
InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs));
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, exprs);
if (!Result.isInvalid() && ListInitialization &&
isa<InitListExpr>(Result.get())) {
@@ -881,7 +857,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
}
// FIXME: Improve AST representation?
- return move(Result);
+ return Result;
}
/// doesUsualArrayDeleteWantSize - Answers whether the usual
@@ -1011,9 +987,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
DirectInitRange = List->getSourceRange();
- return BuildCXXNew(StartLoc, UseGlobal,
+ return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ PlacementArgs,
PlacementRParen,
TypeIdParens,
AllocType,
@@ -1044,7 +1020,7 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
}
ExprResult
-Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
+Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
@@ -1056,6 +1032,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
Expr *Initializer,
bool TypeMayContainAuto) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
+ SourceLocation StartLoc = Range.getBegin();
CXXNewExpr::InitializationStyle initStyle;
if (DirectInitRange.isValid()) {
@@ -1279,21 +1256,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- // ARC: warn about ABI issues.
- if (getLangOpts().ObjCAutoRefCount) {
- QualType BaseAllocType = Context.getBaseElementType(AllocType);
- if (BaseAllocType.hasStrongOrWeakObjCLifetime())
- Diag(StartLoc, diag::warn_err_new_delete_object_array)
- << 0 << BaseAllocType;
- }
-
// Note that we do *not* convert the argument in any way. It can
// be signed, larger than size_t, whatever.
}
FunctionDecl *OperatorNew = 0;
FunctionDecl *OperatorDelete = 0;
- Expr **PlaceArgs = (Expr**)PlacementArgs.get();
+ Expr **PlaceArgs = PlacementArgs.data();
unsigned NumPlaceArgs = PlacementArgs.size();
if (!AllocType->isDependentType() &&
@@ -1432,15 +1401,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- PlacementArgs.release();
-
return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
OperatorDelete,
UsualArrayDeleteWantsSize,
- PlaceArgs, NumPlaceArgs, TypeIdParens,
+ llvm::makeArrayRef(PlaceArgs, NumPlaceArgs),
+ TypeIdParens,
ArraySize, initStyle, Initializer,
ResultType, AllocTypeInfo,
- StartLoc, DirectInitRange));
+ Range, DirectInitRange));
}
/// \brief Checks that a type is suitable as the allocated type
@@ -1638,7 +1606,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
= dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
// Perform template argument deduction to try to match the
// expected function type.
- TemplateDeductionInfo Info(Context, StartLoc);
+ TemplateDeductionInfo Info(StartLoc);
if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info))
continue;
} else
@@ -2100,7 +2068,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
ObjectPtrConversions.front()->getConversionType(),
AA_Converting);
if (Res.isUsable()) {
- Ex = move(Res);
+ Ex = Res;
Type = Ex.get()->getType();
}
}
@@ -2211,13 +2179,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
}
- } else if (getLangOpts().ObjCAutoRefCount &&
- PointeeElem->isObjCLifetimeType() &&
- (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
- PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
- ArrayForm) {
- Diag(StartLoc, diag::warn_err_new_delete_object_array)
- << 1 << PointeeElem;
}
if (!OperatorDelete) {
@@ -2287,7 +2248,7 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
return ExprError();
}
- return move(Condition);
+ return Condition;
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
@@ -2354,11 +2315,9 @@ static ExprResult BuildCXXCastArgument(Sema &S,
default: llvm_unreachable("Unhandled cast kind!");
case CK_ConstructorConversion: {
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method);
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
- if (S.CompleteConstructorCall(Constructor,
- MultiExprArg(&From, 1),
- CastLoc, ConstructorArgs))
+ if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs))
return ExprError();
S.CheckConstructorAccess(CastLoc, Constructor,
@@ -2367,7 +2326,7 @@ static ExprResult BuildCXXCastArgument(Sema &S,
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
@@ -2511,15 +2470,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
if (SCS.Second == ICK_Derived_To_Base) {
- ASTOwningVector<Expr*> ConstructorArgs(*this);
+ SmallVector<Expr*, 8> ConstructorArgs;
if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor),
- MultiExprArg(*this, &From, 1),
- /*FIXME:ConstructLoc*/SourceLocation(),
+ From, /*FIXME:ConstructLoc*/SourceLocation(),
ConstructorArgs))
return ExprError();
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
/*HadMultipleCandidates*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
@@ -2527,8 +2485,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
- MultiExprArg(*this, &From, 1),
- /*HadMultipleCandidates*/ false,
+ From, /*HadMultipleCandidates*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -2602,8 +2559,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
- From = ImpCastExprToType(From, ToType, CK_IntegralCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ if (ToType->isBooleanType()) {
+ assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
+ SCS.Second == ICK_Integral_Promotion &&
+ "only enums with fixed underlying type can promote to bool");
+ From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ } else {
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ }
break;
case ICK_Floating_Promotion:
@@ -2943,6 +2908,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
case UTT_IsEmpty:
case UTT_IsPolymorphic:
case UTT_IsAbstract:
+ case UTT_IsInterfaceClass:
// Fall-through
// These traits require a complete type.
@@ -3007,7 +2973,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsUnion:
return T->isUnionType();
case UTT_IsClass:
- return T->isClassType() || T->isStructureType();
+ return T->isClassType() || T->isStructureType() || T->isInterfaceType();
case UTT_IsFunction:
return T->isFunctionType();
@@ -3073,6 +3039,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return RD->isAbstract();
return false;
+ case UTT_IsInterfaceClass:
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->isInterface();
+ return false;
case UTT_IsFinal:
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return RD->hasAttr<FinalAttr>();
@@ -3417,9 +3387,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (Init.Failed())
return false;
- ExprResult Result = Init.Perform(S, To, InitKind,
- MultiExprArg(ArgExprs.data(),
- ArgExprs.size()));
+ ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs);
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
@@ -3577,7 +3545,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
if (Init.Failed())
return false;
- ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
+ ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
}
@@ -3774,7 +3742,7 @@ ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen);
- return move(Result);
+ return Result;
}
static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) {
@@ -4056,14 +4024,14 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
Best->Conversions[0], Sema::AA_Converting);
if (LHSRes.isInvalid())
break;
- LHS = move(LHSRes);
+ LHS = LHSRes;
ExprResult RHSRes =
Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], Sema::AA_Converting);
if (RHSRes.isInvalid())
break;
- RHS = move(RHSRes);
+ RHS = RHSRes;
if (Best->Function)
Self.MarkFunctionReferenced(QuestionLoc, Best->Function);
return false;
@@ -4104,7 +4072,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
SourceLocation());
Expr *Arg = E.take();
InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1);
- ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&Arg, 1));
+ ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg);
if (Result.isInvalid())
return true;
@@ -4129,7 +4097,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult CondRes = CheckCXXBooleanCondition(Cond.take());
if (CondRes.isInvalid())
return QualType();
- Cond = move(CondRes);
+ Cond = CondRes;
}
// Assume r-value.
@@ -4160,6 +4128,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult &NonVoid = LVoid ? RHS : LHS;
if (NonVoid.get()->getType()->isRecordType() &&
NonVoid.get()->isGLValue()) {
+ if (RequireNonAbstractType(QuestionLoc, NonVoid.get()->getType(),
+ diag::err_allocation_of_abstract_type))
+ return QualType();
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(NonVoid.get()->getType());
NonVoid = PerformCopyInitialization(Entity, SourceLocation(), NonVoid);
@@ -4302,7 +4273,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) {
if (LTy->isRecordType()) {
// The operands have class type. Make a temporary copy.
+ if (RequireNonAbstractType(QuestionLoc, LTy,
+ diag::err_allocation_of_abstract_type))
+ return QualType();
InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
+
ExprResult LHSCopy = PerformCopyInitialization(Entity,
SourceLocation(),
LHS);
@@ -4566,14 +4541,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// Convert E1 to Composite1
ExprResult E1Result
- = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E1,1));
+ = E1ToC1.Perform(*this, Entity1, Kind, E1);
if (E1Result.isInvalid())
return QualType();
E1 = E1Result.takeAs<Expr>();
// Convert E2 to Composite1
ExprResult E2Result
- = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E2,1));
+ = E2ToC1.Perform(*this, Entity1, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.takeAs<Expr>();
@@ -4591,14 +4566,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// Convert E1 to Composite2
ExprResult E1Result
- = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1));
+ = E1ToC2.Perform(*this, Entity2, Kind, E1);
if (E1Result.isInvalid())
return QualType();
E1 = E1Result.takeAs<Expr>();
// Convert E2 to Composite2
ExprResult E2Result
- = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1));
+ = E2ToC2.Perform(*this, Entity2, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.takeAs<Expr>();
@@ -4839,7 +4814,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
BO_Comma, BO->getType(),
BO->getValueKind(),
BO->getObjectKind(),
- BO->getOperatorLoc()));
+ BO->getOperatorLoc(),
+ BO->isFPContractable()));
}
}
@@ -4991,7 +4967,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
// type C (or of pointer to a class type C), the unqualified-id is looked
// up in the scope of class C. [...]
ObjectType = ParsedType::make(BaseType);
- return move(Base);
+ return Base;
}
ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
@@ -5056,7 +5032,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
return ExprError();
- if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
+ if (!ObjectType->isDependentType() && !ObjectType->isScalarType() &&
+ !ObjectType->isVectorType()) {
if (getLangOpts().MicrosoftMode && ObjectType->isVoidType())
Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange();
else
@@ -5203,8 +5180,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
} else {
// Resolve the template-id to a type.
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
@@ -5253,8 +5229,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
} else {
// Resolve the template-id to a type.
TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
@@ -5353,7 +5328,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
- new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK,
+ new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK,
Exp.get()->getLocEnd());
return CE;
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 8f445e28648d..a7fd47183a16 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -13,6 +13,7 @@
#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"
@@ -353,7 +354,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
// Now look up the TypeDefDecl from the vector type. Without this,
// diagostics look bad. We want extended vector types to appear built-in.
for (Sema::ExtVectorDeclsType::iterator
- I = S.ExtVectorDecls.begin(S.ExternalSource),
+ I = S.ExtVectorDecls.begin(S.getExternalSource()),
E = S.ExtVectorDecls.end();
I != E; ++I) {
if ((*I)->getUnderlyingType() == VT)
@@ -605,7 +606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
R.addDecl(ND);
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
}
@@ -656,7 +658,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
}
if (Result.get())
- return move(Result);
+ return Result;
// LookupMemberExpr can modify Base, and thus change BaseType
BaseType = Base->getType();
@@ -1021,7 +1023,7 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
// Do the substitution as long as the redefinition type isn't just a
// possibly-qualified pointer to builtin-id or builtin-Class again.
opty = redef->getAs<ObjCObjectPointerType>();
- if (opty && !opty->getObjectType()->getInterface() != 0)
+ if (opty && !opty->getObjectType()->getInterface())
return false;
base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
@@ -1272,9 +1274,23 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (warn)
Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr.take(),
- IsArrow));
+
+ ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc,
+ BaseExpr.take(),
+ IsArrow);
+
+ if (getLangOpts().ObjCAutoRefCount) {
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ MemberLoc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ }
+
+ return Owned(Result);
}
// Objective-C property access.
@@ -1550,7 +1566,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
Id.getKind() == UnqualifiedId::IK_DestructorName)
return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
- return move(Result);
+ return Result;
}
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl, HasTrailingLParen};
@@ -1560,7 +1576,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
false, &ExtraArgs);
}
- return move(Result);
+ return Result;
}
static ExprResult
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 0aabf8b634d1..e43b6bff5586 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -229,7 +229,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberPointer, ResultTInfo,
S.NSNumberDecl,
/*isInstance=*/false, /*isVariadic=*/false,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required,
@@ -345,7 +345,7 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
SourceLocation());
InitializationSequence Seq(S, Entity, Kind, &Element, 1);
if (!Seq.Failed())
- return Seq.Perform(S, Entity, Kind, MultiExprArg(S, &Element, 1));
+ return Seq.Perform(S, Entity, Kind, Element);
}
Expr *OrigElement = Element;
@@ -477,7 +477,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
stringWithUTF8String, NSStringPointer,
ResultTInfo, NSStringDecl,
/*isInstance=*/false, /*isVariadic=*/false,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required,
@@ -646,7 +646,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
ResultTInfo,
Context.getTranslationUnitDecl(),
false /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -708,7 +708,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
// Check that each of the elements provided is valid in a collection literal,
// performing conversions as necessary.
- Expr **ElementsBuffer = Elements.get();
+ Expr **ElementsBuffer = Elements.data();
for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
ElementsBuffer[I],
@@ -724,10 +724,8 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context.getObjCInterfaceType(NSArrayDecl));
return MaybeBindToTemporary(
- ObjCArrayLiteral::Create(Context,
- llvm::makeArrayRef(Elements.get(),
- Elements.size()),
- Ty, ArrayWithObjectsMethod, SR));
+ ObjCArrayLiteral::Create(Context, Elements, Ty,
+ ArrayWithObjectsMethod, SR));
}
ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
@@ -766,7 +764,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
0 /*TypeSourceInfo */,
Context.getTranslationUnitDecl(),
false /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -1125,7 +1123,9 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) {
bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Expr **Args, unsigned NumArgs,
- Selector Sel, ObjCMethodDecl *Method,
+ Selector Sel,
+ ArrayRef<SourceLocation> SelectorLocs,
+ ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
QualType &ReturnType, ExprValueKind &VK) {
@@ -1149,7 +1149,8 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
: diag::warn_inst_method_not_found;
if (!getLangOpts().DebuggerSupport)
Diag(lbrac, DiagID)
- << Sel << isClassMessage << SourceRange(lbrac, rbrac);
+ << Sel << isClassMessage << SourceRange(SelectorLocs.front(),
+ SelectorLocs.back());
// In debuggers, we want to use __unknown_anytype for these
// results so that clients can cast them.
@@ -1304,8 +1305,8 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
Expr *RExpr = Receiver->IgnoreParenImpCasts();
SourceLocation Loc = RExpr->getLocStart();
QualType T = RExpr->getType();
- ObjCPropertyDecl *PDecl = 0;
- ObjCMethodDecl *GDecl = 0;
+ const ObjCPropertyDecl *PDecl = 0;
+ const ObjCMethodDecl *GDecl = 0;
if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) {
RExpr = POE->getSyntacticForm();
if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) {
@@ -1327,34 +1328,29 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
// See if receiver is a method which envokes a synthesized getter
// backing a 'weak' property.
ObjCMethodDecl *Method = ME->getMethodDecl();
- if (Method && Method->isSynthesized()) {
- Selector Sel = Method->getSelector();
- if (Sel.getNumArgs() == 0) {
- const DeclContext *Container = Method->getDeclContext();
- PDecl =
- S.LookupPropertyDecl(cast<ObjCContainerDecl>(Container),
- Sel.getIdentifierInfoForSlot(0));
- }
+ if (Method && Method->getSelector().getNumArgs() == 0) {
+ PDecl = Method->findPropertyDecl();
if (PDecl)
T = PDecl->getType();
}
}
- if (T.getObjCLifetime() == Qualifiers::OCL_Weak) {
- S.Diag(Loc, diag::warn_receiver_is_weak)
- << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2));
- if (PDecl)
- S.Diag(PDecl->getLocation(), diag::note_property_declare);
- else if (GDecl)
- S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl;
- return;
+ if (T.getObjCLifetime() != Qualifiers::OCL_Weak) {
+ if (!PDecl)
+ return;
+ if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak))
+ return;
}
-
- if (PDecl &&
- (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) {
- S.Diag(Loc, diag::warn_receiver_is_weak) << 1;
+
+ S.Diag(Loc, diag::warn_receiver_is_weak)
+ << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2));
+
+ if (PDecl)
S.Diag(PDecl->getLocation(), diag::note_property_declare);
- }
+ else if (GDecl)
+ S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl;
+
+ S.Diag(Loc, diag::note_arc_assign_to_strong);
}
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
@@ -1776,19 +1772,17 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
// We are in a method whose class has a superclass, so 'super'
// is acting as a keyword.
- if (Method->isInstanceMethod()) {
- if (Sel.getMethodFamily() == OMF_dealloc)
- getCurFunction()->ObjCShouldCallSuperDealloc = false;
- if (Sel.getMethodFamily() == OMF_finalize)
- getCurFunction()->ObjCShouldCallSuperFinalize = false;
+ if (Method->getSelector() == Sel)
+ getCurFunction()->ObjCShouldCallSuper = false;
+ if (Method->isInstanceMethod()) {
// Since we are in an instance method, this is an instance
// message to the superclass instance.
QualType SuperTy = Context.getObjCInterfaceType(Super);
SuperTy = Context.getObjCObjectPointerType(SuperTy);
return BuildInstanceMessage(0, SuperTy, SuperLoc,
Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
// Since we are in a class method, this is a class message to
@@ -1796,7 +1790,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
return BuildClassMessage(/*ReceiverTypeInfo=*/0,
Context.getObjCInterfaceType(Super),
SuperLoc, Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
@@ -1911,7 +1905,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// If the receiver type is dependent, we can't type-check anything
// at this point. Build a dependent expression.
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return Owned(ObjCMessageExpr::Create(Context, ReceiverType,
VK_RValue, LBracLoc, ReceiverTypeInfo,
@@ -1965,8 +1959,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
ExprValueKind VK = VK_RValue;
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
- if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true,
+ Expr **Args = ArgsIn.data();
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, SelectorLocs,
+ Method, true,
SuperLoc.isValid(), LBracLoc, RBracLoc,
ReturnType, VK))
return ExprError();
@@ -2016,7 +2011,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
@@ -2095,7 +2090,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// If the receiver is type-dependent, we can't type-check anything
// at this point. Build a dependent expression.
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
VK_RValue, LBracLoc, Receiver, Sel,
@@ -2282,7 +2277,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
LBracLoc,
SelectorLocs,
RBracLoc,
- move(ArgsIn));
+ ArgsIn);
} else {
// Reject other random receiver types (e.g. structs).
Diag(Loc, diag::err_bad_receiver_type)
@@ -2295,12 +2290,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Check the message arguments.
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ Expr **Args = ArgsIn.data();
QualType ReturnType;
ExprValueKind VK = VK_RValue;
bool ClassMessage = (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType());
- if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method,
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel,
+ SelectorLocs, Method,
ClassMessage, SuperLoc.isValid(),
LBracLoc, RBracLoc, ReturnType, VK))
return ExprError();
@@ -2428,6 +2424,24 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// In ARC, check for message sends which are likely to introduce
// retain cycles.
checkRetainCycles(Result);
+
+ if (!isImplicit && Method) {
+ if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) {
+ bool IsWeak =
+ Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak;
+ if (!IsWeak && Sel.isUnarySelector())
+ IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak;
+
+ if (IsWeak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ LBracLoc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(Result, Prop);
+
+ }
+ }
+ }
}
return MaybeBindToTemporary(Result);
@@ -2448,7 +2462,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
return BuildInstanceMessage(Receiver, Receiver->getType(),
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
enum ARCConversionTypeClass {
@@ -3079,8 +3093,8 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(),
gse->getControllingExpr(),
- subTypes.data(), subExprs.data(),
- n, gse->getDefaultLoc(),
+ subTypes, subExprs,
+ gse->getDefaultLoc(),
gse->getRParenLoc(),
gse->containsUnexpandedParameterPack(),
gse->getResultIndex());
@@ -3101,8 +3115,8 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
canExprType->isObjCObjectPointerType()) {
if (const ObjCObjectPointerType *ObjT =
canExprType->getAs<ObjCObjectPointerType>())
- if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable())
- return false;
+ if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl())
+ return !ObjI->isArcWeakrefUnavailable();
}
return true;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 62ab1e645089..3596bbfc725a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1316,6 +1316,8 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
if (structDecl->isInvalidDecl()) {
+ // Assume it was supposed to consume a single initializer.
+ ++Index;
hadError = true;
return;
}
@@ -1503,11 +1505,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
/// corresponds to FieldName.
static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
IdentifierInfo *FieldName) {
+ if (!FieldName)
+ return 0;
+
assert(AnonField->isAnonymousStructOrUnion());
Decl *NextDecl = AnonField->getNextDeclInContext();
while (IndirectFieldDecl *IF =
dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) {
- if (FieldName && FieldName == IF->getAnonField()->getIdentifier())
+ if (FieldName == IF->getAnonField()->getIdentifier())
return IF;
NextDecl = NextDecl->getNextDeclInContext();
}
@@ -1521,8 +1526,8 @@ static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
for (unsigned I = 0; I < NumIndexExprs; ++I)
IndexExprs[I] = DIE->getSubExpr(I + 1);
return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(),
- DIE->size(), IndexExprs.data(),
- NumIndexExprs, DIE->getEqualOrColonLoc(),
+ DIE->size(), IndexExprs,
+ DIE->getEqualOrColonLoc(),
DIE->usesGNUSyntax(), DIE->getInit());
}
@@ -1562,7 +1567,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
///
/// @param DesigIdx The index of the current designator.
///
-/// @param DeclType The type of the "current object" (C99 6.7.8p17),
+/// @param CurrentObjectType The type of the "current object" (C99 6.7.8p17),
/// into which the designation in @p DIE should refer.
///
/// @param NextField If non-NULL and the first designator in @p DIE is
@@ -2068,7 +2073,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
- InitRange.getBegin(), 0, 0,
+ InitRange.getBegin(), MultiExprArg(),
InitRange.getEnd());
QualType ResultType = CurrentObjectType;
@@ -2261,8 +2266,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
DesignatedInitExpr *DIE
= DesignatedInitExpr::Create(Context,
Designators.data(), Designators.size(),
- InitExpressions.data(), InitExpressions.size(),
- Loc, GNUSyntax, Init.takeAs<Expr>());
+ InitExpressions, Loc, GNUSyntax,
+ Init.takeAs<Expr>());
if (!getLangOpts().C99)
Diag(DIE->getLocStart(), diag::ext_designated_init)
@@ -2814,14 +2819,6 @@ static void TryConstructorInitialization(Sema &S,
assert((!InitListSyntax || (NumArgs == 1 && isa<InitListExpr>(Args[0]))) &&
"InitListSyntax must come with a single initializer list argument.");
- // Check constructor arguments for self reference.
- if (DeclaratorDecl *DD = Entity.getDecl())
- // Parameters arguments are occassionially constructed with itself,
- // for instance, in recursive functions. Skip them.
- if (!isa<ParmVarDecl>(DD))
- for (unsigned i = 0; i < NumArgs; ++i)
- S.CheckSelfReference(DD, Args[i]);
-
// The type we're constructing needs to be complete.
if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
Sequence.setIncompleteTypeFailure(DestType);
@@ -3614,8 +3611,8 @@ static void TryValueInitialization(Sema &S,
// user-provided or deleted default constructor, then the object is
// zero-initialized and, if T has a non-trivial default constructor,
// default-initialized;
- // FIXME: The 'non-union' here is a defect (not yet assigned an issue
- // number). Update the quotation when the defect is resolved.
+ // The 'non-union' here was removed by DR1502. The 'non-trivial default
+ // constructor' part was removed by DR1507.
if (NeedZeroInitialization)
Sequence.AddZeroInitializationStep(Entity.getType());
@@ -3703,8 +3700,14 @@ static void TryUserDefinedConversion(Sema &S,
// Try to complete the type we're converting to.
if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl);
+ DeclContext::lookup_iterator ConOrig, ConEndOrig;
+ llvm::tie(ConOrig, ConEndOrig) = 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);
+ for (SmallVector<NamedDecl*, 8>::iterator
+ Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -4413,7 +4416,7 @@ static ExprResult CopyObject(Sema &S,
if (const RecordType *Record = T->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
- return move(CurInit);
+ return CurInit;
// C++0x [class.copy]p32:
// When certain criteria are met, an implementation is allowed to
@@ -4435,7 +4438,7 @@ static ExprResult CopyObject(Sema &S,
// Make sure that the type we are copying is complete.
if (S.RequireCompleteType(Loc, T, diag::err_temp_copy_incomplete))
- return move(CurInit);
+ return CurInit;
// Perform overload resolution using the class's copy/move constructors.
// Only consider constructors and constructor templates. Per
@@ -4460,7 +4463,7 @@ static ExprResult CopyObject(Sema &S,
CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
if (!IsExtraneousCopy || S.isSFINAEContext())
return ExprError();
- return move(CurInit);
+ return CurInit;
case OR_Ambiguous:
S.Diag(Loc, diag::err_temp_copy_ambiguous)
@@ -4478,7 +4481,7 @@ static ExprResult CopyObject(Sema &S,
}
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
CurInit.release(); // Ownership transferred into MultiExprArg, below.
S.CheckConstructorAccess(Loc, Constructor, Entity,
@@ -4521,7 +4524,7 @@ static ExprResult CopyObject(Sema &S,
// Actually perform the constructor call.
CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
@@ -4530,7 +4533,7 @@ static ExprResult CopyObject(Sema &S,
// If we're supposed to bind temporaries, do so.
if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
- return move(CurInit);
+ return CurInit;
}
/// \brief Check whether elidable copy construction for binding a reference to
@@ -4619,7 +4622,7 @@ PerformConstructorInitialization(Sema &S,
bool HadMultipleCandidates = Step.Function.HadMultipleCandidates;
// Build a call to the selected constructor.
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
? Kind.getEqualLoc()
: Kind.getLocation();
@@ -4648,7 +4651,7 @@ PerformConstructorInitialization(Sema &S,
// Determine the arguments required to actually perform the constructor
// call.
- if (S.CompleteConstructorCall(Constructor, move(Args),
+ if (S.CompleteConstructorCall(Constructor, Args,
Loc, ConstructorArgs,
AllowExplicitConv))
return ExprError();
@@ -4660,8 +4663,6 @@ PerformConstructorInitialization(Sema &S,
(Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value)))) {
// An explicitly-constructed temporary, e.g., X(1, 2).
- unsigned NumExprs = ConstructorArgs.size();
- Expr **Exprs = (Expr **)ConstructorArgs.take();
S.MarkFunctionReferenced(Loc, Constructor);
S.DiagnoseUseOfDecl(Constructor, Loc);
@@ -4675,8 +4676,7 @@ PerformConstructorInitialization(Sema &S,
CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
Constructor,
TSInfo,
- Exprs,
- NumExprs,
+ ConstructorArgs,
ParenRange,
HadMultipleCandidates,
ConstructorInitRequiresZeroInit));
@@ -4702,7 +4702,7 @@ PerformConstructorInitialization(Sema &S,
if (Entity.allowsNRVO())
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor, /*Elidable=*/true,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
ConstructorInitRequiresZeroInit,
ConstructKind,
@@ -4710,7 +4710,7 @@ PerformConstructorInitialization(Sema &S,
else
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
ConstructorInitRequiresZeroInit,
ConstructKind,
@@ -4727,7 +4727,7 @@ PerformConstructorInitialization(Sema &S,
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
- return move(CurInit);
+ return CurInit;
}
/// Determine whether the specified InitializedEntity definitely has a lifetime
@@ -4775,7 +4775,7 @@ InitializationSequence::Perform(Sema &S,
QualType *ResultType) {
if (Failed()) {
unsigned NumArgs = Args.size();
- Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs);
+ Diagnose(S, Entity, Kind, Args.data(), NumArgs);
return ExprError();
}
@@ -4795,7 +4795,7 @@ InitializationSequence::Perform(Sema &S,
// introduced and such). So, we fall back to making the array
// type a dependently-sized array type with no specified
// bound.
- if (isa<InitListExpr>((Expr *)Args.get()[0])) {
+ if (isa<InitListExpr>((Expr *)Args[0])) {
SourceRange Brackets;
// Scavange the location of the brackets from the entity, if we can.
@@ -4823,12 +4823,12 @@ InitializationSequence::Perform(Sema &S,
// Rebuild the ParenListExpr.
SourceRange ParenRange = Kind.getParenRange();
return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(),
- move(Args));
+ Args);
}
assert(Kind.getKind() == InitializationKind::IK_Copy ||
Kind.isExplicitCast() ||
Kind.getKind() == InitializationKind::IK_DirectList);
- return ExprResult(Args.release()[0]);
+ return ExprResult(Args[0]);
}
// No steps means no initialization.
@@ -4836,22 +4836,22 @@ InitializationSequence::Perform(Sema &S,
return S.Owned((Expr *)0);
if (S.getLangOpts().CPlusPlus0x && Entity.getType()->isReferenceType() &&
- Args.size() == 1 && isa<InitListExpr>(Args.get()[0]) &&
+ Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
Entity.getKind() != InitializedEntity::EK_Parameter) {
// Produce a C++98 compatibility warning if we are initializing a reference
// from an initializer list. For parameters, we produce a better warning
// elsewhere.
- Expr *Init = Args.get()[0];
+ Expr *Init = Args[0];
S.Diag(Init->getLocStart(), diag::warn_cxx98_compat_reference_list_init)
<< Init->getSourceRange();
}
// Diagnose cases where we initialize a pointer to an array temporary, and the
// pointer obviously outlives the temporary.
- if (Args.size() == 1 && Args.get()[0]->getType()->isArrayType() &&
+ if (Args.size() == 1 && Args[0]->getType()->isArrayType() &&
Entity.getType()->isPointerType() &&
InitializedEntityOutlivesFullExpression(Entity)) {
- Expr *Init = Args.get()[0];
+ Expr *Init = Args[0];
Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);
if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)
S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)
@@ -4897,7 +4897,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ProduceObjCObject:
case SK_StdInitializerList: {
assert(Args.size() == 1);
- CurInit = Args.get()[0];
+ CurInit = Args[0];
if (!CurInit.get()) return ExprError();
break;
}
@@ -4924,7 +4924,7 @@ InitializationSequence::Perform(Sema &S,
// initializer to reflect that choice.
S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl);
S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation());
- CurInit = S.FixOverloadedFunctionReference(move(CurInit),
+ CurInit = S.FixOverloadedFunctionReference(CurInit,
Step->Function.FoundDecl,
Step->Function.Function);
break;
@@ -5016,7 +5016,7 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_ExtraneousCopyToTemporary:
- CurInit = CopyObject(S, Step->Type, Entity, move(CurInit),
+ CurInit = CopyObject(S, Step->Type, Entity, CurInit,
/*IsExtraneousCopy=*/true);
break;
@@ -5031,7 +5031,7 @@ InitializationSequence::Perform(Sema &S,
bool CreatedObject = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = CurInit.get()->getLocStart();
CurInit.release(); // Ownership transferred into MultiExprArg, below.
@@ -5045,7 +5045,7 @@ InitializationSequence::Perform(Sema &S,
// Build an expression that constructs a temporary.
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
@@ -5079,7 +5079,7 @@ InitializationSequence::Perform(Sema &S,
FoundFn, Conversion);
if(CurInitExprRes.isInvalid())
return ExprError();
- CurInit = move(CurInitExprRes);
+ CurInit = CurInitExprRes;
// Build the actual call to the conversion function.
CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
@@ -5115,7 +5115,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
if (RequiresCopy)
CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
- move(CurInit), /*IsExtraneousCopy=*/false);
+ CurInit, /*IsExtraneousCopy=*/false);
break;
}
@@ -5144,7 +5144,7 @@ InitializationSequence::Perform(Sema &S,
getAssignmentAction(Entity), CCK);
if (CurInitExprRes.isInvalid())
return ExprError();
- CurInit = move(CurInitExprRes);
+ CurInit = CurInitExprRes;
break;
}
@@ -5195,13 +5195,13 @@ InitializationSequence::Perform(Sema &S,
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
assert(Args.size() == 1 && "expected a single argument for list init");
- InitListExpr *InitList = cast<InitListExpr>(Args.get()[0]);
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
S.Diag(InitList->getExprLoc(), diag::warn_cxx98_compat_ctor_list_init)
<< InitList->getSourceRange();
MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
- Kind, move(Arg), *Step,
+ Kind, Arg, *Step,
ConstructorInitRequiresZeroInit);
break;
}
@@ -5214,7 +5214,7 @@ InitializationSequence::Perform(Sema &S,
Expr *E = CurInit.take();
InitListExpr *Syntactic = Step->WrappingSyntacticList;
InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
- Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc());
+ Syntactic->getLBraceLoc(), E, Syntactic->getRBraceLoc());
ILE->setSyntacticForm(Syntactic);
ILE->setType(E->getType());
ILE->setValueKind(E->getValueKind());
@@ -5234,7 +5234,7 @@ InitializationSequence::Perform(Sema &S,
bool UseTemporary = Entity.getType()->isReferenceType();
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
: Entity,
- Kind, move(Args), *Step,
+ Kind, Args, *Step,
ConstructorInitRequiresZeroInit);
break;
}
@@ -5268,15 +5268,15 @@ InitializationSequence::Perform(Sema &S,
case SK_CAssignment: {
QualType SourceType = CurInit.get()->getType();
- ExprResult Result = move(CurInit);
+ ExprResult Result = CurInit;
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(Step->Type, Result);
if (Result.isInvalid())
return ExprError();
- CurInit = move(Result);
+ CurInit = Result;
// If this is a call, allow conversion to a transparent union.
- ExprResult CurInitExprRes = move(CurInit);
+ ExprResult CurInitExprRes = CurInit;
if (ConvTy != Sema::Compatible &&
Entity.getKind() == InitializedEntity::EK_Parameter &&
S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes)
@@ -5284,7 +5284,7 @@ InitializationSequence::Perform(Sema &S,
ConvTy = Sema::Compatible;
if (CurInitExprRes.isInvalid())
return ExprError();
- CurInit = move(CurInitExprRes);
+ CurInit = CurInitExprRes;
bool Complained;
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
@@ -5398,7 +5398,7 @@ InitializationSequence::Perform(Sema &S,
}
InitListExpr *Semantic = new (S.Context)
InitListExpr(S.Context, ILE->getLBraceLoc(),
- Converted.data(), NumInits, ILE->getRBraceLoc());
+ Converted, ILE->getRBraceLoc());
Semantic->setSyntacticForm(ILE);
Semantic->setType(Dest);
Semantic->setInitializesStdInitializerList();
@@ -5415,7 +5415,7 @@ InitializationSequence::Perform(Sema &S,
cast<FieldDecl>(Entity.getDecl()),
CurInit.get());
- return move(CurInit);
+ return CurInit;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 6414c6fbac97..15cd2a73e7f7 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -22,13 +22,14 @@ using namespace clang;
using namespace sema;
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
+ TypeSourceInfo *Info,
bool KnownDependent) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
// Start constructing the lambda class.
- CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC,
+ CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info,
IntroducerRange.getBegin(),
KnownDependent);
DC->addDecl(Class);
@@ -369,15 +370,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (!TmplScope->decl_empty())
KnownDependent = true;
- CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent);
-
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
bool ExplicitResultType = true;
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
- llvm::ArrayRef<ParmVarDecl *> Params;
+ llvm::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
@@ -410,17 +409,25 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType
= MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
!= Context.DependentTy;
-
- TypeLoc TL = MethodTyInfo->getTypeLoc();
- FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
- Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(),
- Proto.getNumArgs());
+
+ if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+ cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
+ // Empty arg list, don't push any params.
+ checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param));
+ } else {
+ Params.reserve(FTI.NumArgs);
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+ Params.push_back(cast<ParmVarDecl>(FTI.ArgInfo[i].Param));
+ }
// Check for unexpanded parameter packs in the method type.
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
}
-
+
+ CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
+ KnownDependent);
+
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
@@ -528,6 +535,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
+ // Ignore invalid decls; they'll just confuse the code later.
+ if (Var->isInvalidDecl())
+ continue;
+
if (!Var->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index dad196b410c4..f6987e7bfbe0 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -707,7 +707,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// result), perform template argument deduction and place the
// specialization into the result set. We do this to avoid forcing all
// callers to perform special deduction for conversion functions.
- TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc());
+ TemplateDeductionInfo Info(R.getNameLoc());
FunctionDecl *Specialization = 0;
const FunctionProtoType *ConvProto
@@ -1725,15 +1725,17 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
namespace {
struct AssociatedLookup {
- AssociatedLookup(Sema &S,
+ AssociatedLookup(Sema &S, SourceLocation InstantiationLoc,
Sema::AssociatedNamespaceSet &Namespaces,
Sema::AssociatedClassSet &Classes)
- : S(S), Namespaces(Namespaces), Classes(Classes) {
+ : S(S), Namespaces(Namespaces), Classes(Classes),
+ InstantiationLoc(InstantiationLoc) {
}
Sema &S;
Sema::AssociatedNamespaceSet &Namespaces;
Sema::AssociatedClassSet &Classes;
+ SourceLocation InstantiationLoc;
};
}
@@ -1796,6 +1798,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
+ case TemplateArgument::NullPtr:
// [Note: non-type template arguments do not contribute to the set of
// associated namespaces. ]
break;
@@ -1864,8 +1867,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// Only recurse into base classes for complete types.
if (!Class->hasDefinition()) {
- // FIXME: we might need to instantiate templates here
- return;
+ QualType type = Result.S.Context.getTypeDeclType(Class);
+ if (Result.S.RequireCompleteType(Result.InstantiationLoc, type,
+ /*no diagnostic*/ 0))
+ return;
}
// Add direct and indirect base classes along with their associated
@@ -2069,13 +2074,15 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
/// namespaces searched by argument-dependent lookup
/// (C++ [basic.lookup.argdep]) for a given set of arguments.
void
-Sema::FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args,
+Sema::FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
+ llvm::ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses) {
AssociatedNamespaces.clear();
AssociatedClasses.clear();
- AssociatedLookup Result(*this, AssociatedNamespaces, AssociatedClasses);
+ AssociatedLookup Result(*this, InstantiationLoc,
+ AssociatedNamespaces, AssociatedClasses);
// C++ [basic.lookup.koenig]p2:
// For each argument type T in the function call, there is a set
@@ -2642,17 +2649,14 @@ void ADLResult::insert(NamedDecl *New) {
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
SourceLocation Loc,
llvm::ArrayRef<Expr *> Args,
- ADLResult &Result,
- bool StdNamespaceIsAssociated) {
+ ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedClassSet AssociatedClasses;
- FindAssociatedClassesAndNamespaces(Args,
+ FindAssociatedClassesAndNamespaces(Loc, Args,
AssociatedNamespaces,
AssociatedClasses);
- if (StdNamespaceIsAssociated && StdNamespace)
- AssociatedNamespaces.insert(getStdNamespace());
QualType T1, T2;
if (Operator) {
@@ -2661,13 +2665,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
T2 = Args[1]->getType();
}
- // Try to complete all associated classes, in case they contain a
- // declaration of a friend function.
- for (AssociatedClassSet::iterator C = AssociatedClasses.begin(),
- CEnd = AssociatedClasses.end();
- C != CEnd; ++C)
- RequireCompleteType(Loc, Context.getRecordType(*C), 0);
-
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
@@ -4056,7 +4053,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (IsUnqualifiedLookup)
UnqualifiedTyposCorrected[Typo] = Result;
- return Result;
+ TypoCorrection TC = Result;
+ TC.setCorrectionRange(SS, TypoName);
+ return TC;
}
else if (BestResults.size() > 1
// Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
@@ -4076,7 +4075,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (IsUnqualifiedLookup)
UnqualifiedTyposCorrected[Typo] = BestResults["super"].front();
- return BestResults["super"].front();
+ TypoCorrection TC = BestResults["super"].front();
+ TC.setCorrectionRange(SS, TypoName);
+ return TC;
}
// If this was an unqualified lookup and we believe the callback object did
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 27deab226f91..8d708607f6eb 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -22,6 +22,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
@@ -43,7 +44,7 @@ static Qualifiers::ObjCLifetime getImpliedARCOwnership(
if (attrs & (ObjCPropertyDecl::OBJC_PR_retain |
ObjCPropertyDecl::OBJC_PR_strong |
ObjCPropertyDecl::OBJC_PR_copy)) {
- return type->getObjCARCImplicitLifetime();
+ return Qualifiers::OCL_Strong;
} else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) {
return Qualifiers::OCL_Weak;
} else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) {
@@ -102,6 +103,15 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
<< propertyLifetime;
}
+static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
+ if ((S.getLangOpts().getGC() != LangOptions::NonGC &&
+ T.isObjCGCWeak()) ||
+ (S.getLangOpts().ObjCAutoRefCount &&
+ T.getObjCLifetime() == Qualifiers::OCL_Weak))
+ return ObjCDeclSpec::DQ_PR_weak;
+ return 0;
+}
+
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
SourceLocation LParenLoc,
FieldDeclarator &FD,
@@ -114,12 +124,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
unsigned Attributes = ODS.getPropertyAttributes();
TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
QualType T = TSI->getType();
- if ((getLangOpts().getGC() != LangOptions::NonGC &&
- T.isObjCGCWeak()) ||
- (getLangOpts().ObjCAutoRefCount &&
- T.getObjCLifetime() == Qualifiers::OCL_Weak))
- Attributes |= ObjCDeclSpec::DQ_PR_weak;
-
+ Attributes |= deduceWeakPropertyFromType(*this, T);
+
bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
// default is readwrite!
!(Attributes & ObjCDeclSpec::DQ_PR_readonly));
@@ -236,6 +242,15 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
}
+static unsigned getOwnershipRule(unsigned attr) {
+ return attr & (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_weak |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+}
+
Decl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
@@ -335,6 +350,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc,
diag::err_type_mismatch_continuation_class) << PDecl->getType();
Diag(PIDecl->getLocation(), diag::note_property_declare);
+ return 0;
}
}
@@ -342,13 +358,11 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// with continuation class's readwrite property attribute!
unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
- unsigned retainCopyNonatomic =
- (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_nonatomic);
- if ((Attributes & retainCopyNonatomic) !=
- (PIkind & retainCopyNonatomic)) {
+ PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType());
+ unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
+ unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
+ if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
+ (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
@@ -397,6 +411,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc, diag)
<< CCPrimary->getDeclName();
Diag(PIDecl->getLocation(), diag::note_property_declare);
+ return 0;
}
*isOverridingProperty = true;
// Make sure setter decl is synthesized, and added to primary class's list.
@@ -405,7 +420,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl());
if (ASTMutationListener *L = Context.getASTMutationListener())
L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl);
- return 0;
+ return PDecl;
}
ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
@@ -543,6 +558,23 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
ivarLifetime == Qualifiers::OCL_Autoreleasing)
return;
+ // If the ivar is private, and it's implicitly __unsafe_unretained
+ // becaues of its type, then pretend it was actually implicitly
+ // __strong. This is only sound because we're processing the
+ // property implementation before parsing any method bodies.
+ if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
+ propertyLifetime == Qualifiers::OCL_Strong &&
+ ivar->getAccessControl() == ObjCIvarDecl::Private) {
+ SplitQualType split = ivarType.split();
+ if (split.Quals.hasObjCLifetime()) {
+ assert(ivarType->isObjCARCImplicitlyUnretainedType());
+ split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);
+ ivarType = S.Context.getQualifiedType(split);
+ ivar->setType(ivarType);
+ return;
+ }
+ }
+
switch (propertyLifetime) {
case Qualifiers::OCL_Strong:
S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
@@ -632,7 +664,13 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl,
// property.
if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
if (!classExtPropertyAttr ||
- (classExtPropertyAttr & ObjCDeclSpec::DQ_PR_readwrite))
+ (classExtPropertyAttr &
+ (ObjCDeclSpec::DQ_PR_readwrite|
+ ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong)))
continue;
warn = true;
break;
@@ -857,13 +895,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (lifetime == Qualifiers::OCL_Weak) {
bool err = false;
if (const ObjCObjectPointerType *ObjT =
- PropertyIvarType->getAs<ObjCObjectPointerType>())
- if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) {
+ PropertyIvarType->getAs<ObjCObjectPointerType>()) {
+ const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
+ if (ObjI && ObjI->isArcWeakrefUnavailable()) {
Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property);
Diag(property->getLocation(), diag::note_property_declare);
err = true;
}
- if (!err && !getLangOpts().ObjCRuntimeHasWeak) {
+ }
+ if (!err && !getLangOpts().ObjCARCWeak) {
Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime);
Diag(property->getLocation(), diag::note_property_declare);
}
@@ -891,7 +931,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Ivar->setInvalidDecl();
ClassImpDecl->addDecl(Ivar);
IDecl->makeDeclVisibleInContext(Ivar);
- property->setPropertyIvarDecl(Ivar);
if (getLangOpts().ObjCRuntime.isFragile())
Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl)
@@ -907,14 +946,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
<< Ivar << Ivar->getName();
// Note! I deliberately want it to fall thru so more errors are caught.
}
+ property->setPropertyIvarDecl(Ivar);
+
QualType IvarType = Context.getCanonicalType(Ivar->getType());
// Check that type of property and its ivar are type compatible.
if (!Context.hasSameType(PropertyIvarType, IvarType)) {
- compat = false;
if (isa<ObjCObjectPointerType>(PropertyIvarType)
&& isa<ObjCObjectPointerType>(IvarType))
- compat =
+ compat =
Context.canAssignObjCInterfaces(
PropertyIvarType->getAs<ObjCObjectPointerType>(),
IvarType->getAs<ObjCObjectPointerType>());
@@ -988,19 +1028,21 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// For Objective-C++, need to synthesize the AST for the IVAR object to be
// returned by the getter as it must conform to C++'s copy-return rules.
// FIXME. Eventually we want to do this for Objective-C as well.
+ SynthesizedFunctionScope Scope(*this, getterMethod);
ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
- VK_RValue, SourceLocation());
+ VK_RValue, PropertyDiagLoc);
+ MarkDeclRefReferenced(SelfExpr);
Expr *IvarRefExpr =
- new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
SelfExpr, true, true);
ExprResult Res =
PerformCopyInitialization(InitializedEntity::InitializeResult(
- SourceLocation(),
+ PropertyDiagLoc,
getterMethod->getResultType(),
/*NRVO=*/false),
- SourceLocation(),
+ PropertyDiagLoc,
Owned(IvarRefExpr));
if (!Res.isInvalid()) {
Expr *ResExpr = Res.takeAs<Expr>();
@@ -1021,19 +1063,22 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well.
+ SynthesizedFunctionScope Scope(*this, setterMethod);
ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
- VK_RValue, SourceLocation());
+ VK_RValue, PropertyDiagLoc);
+ MarkDeclRefReferenced(SelfExpr);
Expr *lhs =
- new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
QualType T = Param->getType().getNonReferenceType();
- Expr *rhs = new (Context) DeclRefExpr(Param, false, T,
- VK_LValue, SourceLocation());
- ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
+ DeclRefExpr *rhs = new (Context) DeclRefExpr(Param, false, T,
+ VK_LValue, PropertyDiagLoc);
+ MarkDeclRefReferenced(rhs);
+ ExprResult Res = BuildBinOp(S, PropertyDiagLoc,
BO_Assign, lhs, rhs);
if (property->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_atomic) {
@@ -1043,7 +1088,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
if (!FuncDecl->isTrivial())
if (property->getType()->isReferenceType()) {
- Diag(PropertyLoc,
+ Diag(PropertyDiagLoc,
diag::err_atomic_property_nontrivial_assign_op)
<< property->getType();
Diag(FuncDecl->getLocStart(),
@@ -1395,8 +1440,8 @@ 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.
void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap) {
+ ObjCContainerDecl::PropertyMap &PropMap,
+ ObjCContainerDecl::PropertyMap &SuperPropMap) {
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
E = IDecl->prop_end(); P != E; ++P) {
@@ -1442,118 +1487,38 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
-/// CollectClassPropertyImplementations - This routine collects list of
-/// properties to be implemented in the class. This includes, class's
-/// and its conforming protocols' properties.
-static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- PropMap[Prop->getIdentifier()] = Prop;
- }
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); PI != E; ++PI)
- CollectClassPropertyImplementations((*PI), PropMap);
- }
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (!PropMap.count(Prop->getIdentifier()))
- PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- CollectClassPropertyImplementations((*PI), PropMap);
- }
-}
-
/// CollectSuperClassPropertyImplementations - This routine collects list of
/// properties to be implemented in super class(s) and also coming from their
/// conforming protocols.
static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ ObjCInterfaceDecl::PropertyMap &PropMap) {
if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
while (SDecl) {
- CollectClassPropertyImplementations(SDecl, PropMap);
+ SDecl->collectPropertiesToImplement(PropMap);
SDecl = SDecl->getSuperClass();
}
}
}
-/// LookupPropertyDecl - Looks up a property in the current class and all
-/// its protocols.
-ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
- IdentifierInfo *II) {
- if (const ObjCInterfaceDecl *IDecl =
- dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- else if (const ObjCProtocolDecl *PDecl =
- dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- return 0;
-}
-
-static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop,
- ASTContext &Ctx) {
- SmallString<128> ivarName;
- {
- llvm::raw_svector_ostream os(ivarName);
- os << '_' << Prop->getIdentifier()->getName();
- }
- return &Ctx.Idents.get(ivarName.str());
-}
-
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl) {
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
- CollectClassPropertyImplementations(IDecl, PropMap);
+ ObjCInterfaceDecl::PropertyMap PropMap;
+ IDecl->collectPropertiesToImplement(PropMap);
if (PropMap.empty())
return;
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
+ ObjCInterfaceDecl::PropertyMap SuperPropMap;
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ for (ObjCInterfaceDecl::PropertyMap::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
ObjCPropertyDecl *Prop = P->second;
// If property to be implemented in the super class, ignore.
if (SuperPropMap[Prop->getIdentifier()])
continue;
- // Is there a matching propery synthesize/dynamic?
+ // Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
@@ -1583,7 +1548,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
true,
/* property = */ Prop->getIdentifier(),
- /* ivar = */ getDefaultSynthIvarName(Prop, Context),
+ /* ivar = */ Prop->getDefaultSynthIvarName(Context),
Prop->getLocation()));
if (PIDecl) {
Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
@@ -1606,11 +1571,11 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const SelectorSet &InsMap) {
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
+ ObjCContainerDecl::PropertyMap SuperPropMap;
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ ObjCContainerDecl::PropertyMap PropMap;
CollectImmediateProperties(CDecl, PropMap, SuperPropMap);
if (PropMap.empty())
return;
@@ -1621,7 +1586,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
EI = IMPDecl->propimpl_end(); I != EI; ++I)
PropImplMap.insert(I->getPropertyDecl());
- for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ for (ObjCContainerDecl::PropertyMap::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
ObjCPropertyDecl *Prop = P->second;
// Is there a matching propery synthesize/dynamic?
@@ -1847,7 +1812,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
property->getType(), 0, CD, /*isInstance=*/true,
- /*isVariadic=*/false, /*isSynthesized=*/true,
+ /*isVariadic=*/false, /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
@@ -1867,7 +1832,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
- GetterMethod->setSynthesized(true);
+ GetterMethod->setPropertyAccessor(true);
property->setGetterMethodDecl(GetterMethod);
// Skip setter if property is read-only.
@@ -1885,7 +1850,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCMethodDecl::Create(Context, Loc, Loc,
property->getSetterName(), Context.VoidTy, 0,
CD, /*isInstance=*/true, /*isVariadic=*/false,
- /*isSynthesized=*/true,
+ /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
(property->getPropertyImplementation() ==
@@ -1916,7 +1881,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
} else
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
- SetterMethod->setSynthesized(true);
+ SetterMethod->setPropertyAccessor(true);
property->setSetterMethodDecl(SetterMethod);
}
// Add any synthesized methods to the global pool. This allows us to
@@ -2121,7 +2086,9 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
// issue any warning.
if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
;
- else {
+ else if (propertyInPrimaryClass) {
+ // Don't issue warning on property with no life time in class
+ // extension as it is inherited from property in primary class.
// Skip this warning in gc-only mode.
if (getLangOpts().getGC() != LangOptions::GCOnly)
Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 9382f7dddc6c..911187857fe1 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -49,7 +49,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates,
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
return ExprError();
- return move(E);
+ return E;
}
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
@@ -555,6 +555,7 @@ static MakeDeductionFailureInfo(ASTContext &Context,
Result.Data = 0;
switch (TDK) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
@@ -597,6 +598,7 @@ static MakeDeductionFailureInfo(ASTContext &Context,
void OverloadCandidate::DeductionFailureInfo::Destroy() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_Incomplete:
case Sema::TDK_TooManyArguments:
@@ -637,6 +639,7 @@ TemplateParameter
OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
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:
@@ -664,6 +667,7 @@ 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:
@@ -688,6 +692,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_Incomplete:
case Sema::TDK_TooManyArguments:
@@ -713,6 +718,7 @@ const TemplateArgument *
OverloadCandidate::DeductionFailureInfo::getSecondArg() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_Incomplete:
case Sema::TDK_TooManyArguments:
@@ -734,13 +740,17 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
return 0;
}
-void OverloadCandidateSet::clear() {
+void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
i->Conversions[ii].~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
+}
+
+void OverloadCandidateSet::clear() {
+ destroyCandidates();
NumInlineSequences = 0;
Candidates.clear();
Functions.clear();
@@ -1668,7 +1678,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
return To->getKind() == BuiltinType::UInt;
}
- // C++0x [conv.prom]p3:
+ // C++11 [conv.prom]p3:
// A prvalue of an unscoped enumeration type whose underlying type is not
// fixed (7.2) can be converted to an rvalue a prvalue of the first of the
// following types that can represent all the values of the enumeration
@@ -1680,12 +1690,26 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// with lowest integer conversion rank (4.13) greater than the rank of long
// long in which all the values of the enumeration can be represented. If
// there are two such extended types, the signed one is chosen.
+ // C++11 [conv.prom]p4:
+ // A prvalue of an unscoped enumeration type whose underlying type is fixed
+ // can be converted to a prvalue of its underlying type. Moreover, if
+ // integral promotion can be applied to its underlying type, a prvalue of an
+ // unscoped enumeration type whose underlying type is fixed can also be
+ // converted to a prvalue of the promoted underlying type.
if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
// C++0x 7.2p9: Note that this implicit enum to int conversion is not
// provided for a scoped enumeration.
if (FromEnumType->getDecl()->isScoped())
return false;
+ // We can perform an integral promotion to the underlying type of the enum,
+ // even if that's not the promoted type.
+ if (FromEnumType->getDecl()->isFixed()) {
+ QualType Underlying = FromEnumType->getDecl()->getIntegerType();
+ return Context.hasSameUnqualifiedType(Underlying, ToType) ||
+ IsIntegralPromotion(From, Underlying, ToType);
+ }
+
// We have already pre-calculated the promotion type, so this is trivial.
if (ToType->isIntegerType() &&
!RequireCompleteType(From->getLocStart(), FromType, 0))
@@ -2899,8 +2923,6 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
case OR_Success: {
// Record the standard conversion we used and the conversion function.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
- S.MarkFunctionReferenced(From->getLocStart(), Constructor);
-
QualType ThisType = Constructor->getThisType(S.Context);
// Initializer lists don't have conversions as such.
User.Before.setAsIdentityConversion();
@@ -3081,8 +3103,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Record the standard conversion we used and the conversion function.
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
- S.MarkFunctionReferenced(From->getLocStart(), Constructor);
-
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
// constructor (12.3.1), the initial standard conversion
@@ -3111,8 +3131,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
- S.MarkFunctionReferenced(From->getLocStart(), Conversion);
-
// C++ [over.ics.user]p1:
//
// [...] If the user-defined conversion is specified by a
@@ -4025,8 +4043,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (!Best->FinalConversion.DirectBinding)
return false;
- if (Best->Function)
- S.MarkFunctionReferenced(DeclLoc, Best->Function);
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
@@ -5531,7 +5547,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
+ TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
@@ -5581,7 +5597,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
+ TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
@@ -5703,7 +5719,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
// allocator).
QualType CallResultType = ConversionType.getNonLValueExprType(Context);
- CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK,
+ CallExpr Call(Context, &ConversionFn, MultiExprArg(), CallResultType, VK,
From->getLocStart());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, &Call, ToType,
@@ -5765,7 +5781,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
- TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
+ TemplateDeductionInfo Info(CandidateSet.getLocation());
CXXConversionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
@@ -6770,17 +6786,16 @@ public:
// bool operator==(T, T);
// bool operator!=(T, T);
void addRelationalPointerOrEnumeralOverloads() {
- // C++ [over.built]p1:
- // If there is a user-written candidate with the same name and parameter
- // types as a built-in candidate operator function, the built-in operator
- // function is hidden and is not included in the set of candidate
- // functions.
+ // C++ [over.match.oper]p3:
+ // [...]the built-in candidates include all of the candidate operator
+ // functions defined in 13.6 that, compared to the given operator, [...]
+ // do not have the same parameter-type-list as any non-template non-member
+ // candidate.
//
- // The text is actually in a note, but if we don't implement it then we end
- // up with ambiguities when the user provides an overloaded operator for
- // an enumeration type. Note that only enumeration types have this problem,
- // so we track which enumeration types we've seen operators for. Also, the
- // only other overloaded operator with enumeration argumenst, operator=,
+ // Note that in practice, this only affects enumeration types because there
+ // aren't any built-in candidates of record type, and a user-defined operator
+ // must have an operand of record or enumeration type. Also, the only other
+ // overloaded operator with enumeration arguments, operator=,
// cannot be overloaded for enumeration types, so this is the only place
// where we must suppress candidates like this.
llvm::DenseSet<std::pair<CanQualType, CanQualType> >
@@ -6795,6 +6810,9 @@ public:
if (!C->Viable || !C->Function || C->Function->getNumParams() != 2)
continue;
+ if (C->Function->isFunctionTemplateSpecialization())
+ continue;
+
QualType FirstParamType =
C->Function->getParamDecl(0)->getType().getUnqualifiedType();
QualType SecondParamType =
@@ -7652,8 +7670,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
llvm::ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
- bool PartialOverloading,
- bool StdNamespaceIsAssociated) {
+ bool PartialOverloading) {
ADLResult Fns;
// FIXME: This approach for uniquing ADL results (and removing
@@ -7664,8 +7681,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Loc, Args, Fns,
- StdNamespaceIsAssociated);
+ ArgumentDependentLookup(Name, Operator, Loc, Args, Fns);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -7976,10 +7992,20 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
const PartialDiagnostic &PDiag) const {
S.Diag(CaretLoc, PDiag)
<< Ambiguous.getFromType() << Ambiguous.getToType();
- for (AmbiguousConversionSequence::const_iterator
- I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) {
+ // FIXME: The note limiting machinery is borrowed from
+ // OverloadCandidateSet::NoteCandidates; there's an opportunity for
+ // refactoring here.
+ const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
+ unsigned CandsShown = 0;
+ AmbiguousConversionSequence::const_iterator I, E;
+ for (I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) {
+ if (CandsShown >= 4 && ShowOverloads == Ovl_Best)
+ break;
+ ++CandsShown;
S.NoteOverloadCandidate(*I);
}
+ if (I != E)
+ S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I);
}
namespace {
@@ -8515,7 +8541,7 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
}
void NoteBuiltinOperatorCandidate(Sema &S,
- const char *Opc,
+ StringRef Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
@@ -8561,6 +8587,7 @@ RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) {
case Sema::TDK_Success:
llvm_unreachable("TDK_success while diagnosing bad deduction");
+ case Sema::TDK_Invalid:
case Sema::TDK_Incomplete:
return 1;
@@ -8783,7 +8810,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
void OverloadCandidateSet::NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
llvm::ArrayRef<Expr *> Args,
- const char *Opc,
+ StringRef Opc,
SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
// be prohibitive, so we make a set of pointers and sort those.
@@ -8807,8 +8834,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
bool ReportedAmbiguousConversions = false;
SmallVectorImpl<OverloadCandidate*>::iterator I, E;
- const DiagnosticsEngine::OverloadsShown ShowOverloads =
- S.Diags.getShowOverloads();
+ const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
unsigned CandsShown = 0;
for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
OverloadCandidate *Cand = *I;
@@ -8816,7 +8842,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
// Set an arbitrary limit on the number of candidate functions we'll spam
// the user with. FIXME: This limit should depend on details of the
// candidate list.
- if (CandsShown >= 4 && ShowOverloads == DiagnosticsEngine::Ovl_Best) {
+ if (CandsShown >= 4 && ShowOverloads == Ovl_Best) {
break;
}
++CandsShown;
@@ -8979,7 +9005,7 @@ private:
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
+ TemplateDeductionInfo Info(OvlExpr->getNameLoc());
if (Sema::TemplateDeductionResult Result
= S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
@@ -9201,7 +9227,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
- MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn);
if (Complain)
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
}
@@ -9257,7 +9282,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context, ovl->getNameLoc());
+ TemplateDeductionInfo Info(ovl->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
@@ -9457,8 +9482,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
ULE->getExprLoc(),
Args, ExplicitTemplateArgs,
- CandidateSet, PartialOverloading,
- ULE->isStdAssociatedNamespace());
+ CandidateSet, PartialOverloading);
}
/// Attempt to recover from an ill-formed use of a non-dependent name in a
@@ -9509,7 +9533,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
// declaring the function there instead.
Sema::AssociatedNamespaceSet AssociatedNamespaces;
Sema::AssociatedClassSet AssociatedClasses;
- SemaRef.FindAssociatedClassesAndNamespaces(Args,
+ SemaRef.FindAssociatedClassesAndNamespaces(FnLoc, Args,
AssociatedNamespaces,
AssociatedClasses);
// Never suggest declaring a function within namespace 'std'.
@@ -9632,6 +9656,20 @@ class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
return false;
}
};
+
+class BuildRecoveryCallExprRAII {
+ Sema &SemaRef;
+public:
+ BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) {
+ assert(SemaRef.IsBuildingRecoveryCallExpr == false);
+ SemaRef.IsBuildingRecoveryCallExpr = true;
+ }
+
+ ~BuildRecoveryCallExprRAII() {
+ SemaRef.IsBuildingRecoveryCallExpr = false;
+ }
+};
+
}
/// Attempts to recover from a call where no functions were found.
@@ -9644,6 +9682,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
llvm::MutableArrayRef<Expr *> Args,
SourceLocation RParenLoc,
bool EmptyLookup, bool AllowTypoCorrection) {
+ // Do not try to recover if it is already building a recovery call.
+ // This stops infinite loops for template instantiations like
+ //
+ // template <typename T> auto foo(T t) -> decltype(foo(t)) {}
+ // template <typename T> auto foo(T t) -> decltype(foo(&t)) {}
+ //
+ if (SemaRef.IsBuildingRecoveryCallExpr)
+ return ExprError();
+ BuildRecoveryCallExprRAII RCE(SemaRef);
CXXScopeSpec SS;
SS.Adopt(ULE->getQualifierLoc());
@@ -9695,20 +9742,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
RParenLoc);
}
-/// ResolveOverloadedCallFn - Given the call expression that calls Fn
-/// (which eventually refers to the declaration Func) and the call
-/// arguments Args/NumArgs, attempt to resolve the function call down
-/// to a specific function. If overload resolution succeeds, returns
-/// the function declaration produced by overload
-/// resolution. Otherwise, emits diagnostics, deletes all of the
-/// arguments and Fn, and returns NULL.
-ExprResult
-Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
- SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc,
- Expr *ExecConfig,
- bool AllowTypoCorrection) {
+/// \brief Constructs and populates an OverloadedCandidateSet from
+/// the given function.
+/// \returns true when an the ExprResult output parameter has been set.
+bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ OverloadCandidateSet *CandidateSet,
+ ExprResult *Result) {
#ifndef NDEBUG
if (ULE->requiresADL()) {
// To do ADL, we must have found an unqualified name.
@@ -9724,62 +9766,79 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// We don't perform ADL in C.
assert(getLangOpts().CPlusPlus && "ADL enabled in C");
- } else
- assert(!ULE->isStdAssociatedNamespace() &&
- "std is associated namespace but not doing ADL");
+ }
#endif
UnbridgedCastsSet UnbridgedCasts;
- if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
- return ExprError();
-
- OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) {
+ *Result = ExprError();
+ return true;
+ }
// Add the functions denoted by the callee to the set of candidate
// functions, including those from argument-dependent lookup.
AddOverloadedCallCandidates(ULE, llvm::makeArrayRef(Args, NumArgs),
- CandidateSet);
+ *CandidateSet);
// If we found nothing, try to recover.
// BuildRecoveryCallExpr diagnoses the error itself, so we just bail
// out if it fails.
- if (CandidateSet.empty()) {
+ if (CandidateSet->empty()) {
// In Microsoft mode, if we are inside a template class member function then
// create a type dependent CallExpr. The goal is to postpone name lookup
// to instantiation time to be able to search into type dependent base
// classes.
if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
(isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) {
- CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs,
- Context.DependentTy, VK_RValue,
- RParenLoc);
+ CallExpr *CE = new (Context) CallExpr(Context, Fn,
+ llvm::makeArrayRef(Args, NumArgs),
+ Context.DependentTy, VK_RValue,
+ RParenLoc);
CE->setTypeDependent(true);
- return Owned(CE);
+ *Result = Owned(CE);
+ return true;
}
- return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
- llvm::MutableArrayRef<Expr *>(Args, NumArgs),
- RParenLoc, /*EmptyLookup=*/true,
- AllowTypoCorrection);
+ return false;
}
UnbridgedCasts.restore();
+ return false;
+}
- OverloadCandidateSet::iterator Best;
- switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
+/// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns
+/// the completed call expression. If overload resolution fails, emits
+/// diagnostics and returns ExprError()
+static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ Expr *ExecConfig,
+ OverloadCandidateSet *CandidateSet,
+ OverloadCandidateSet::iterator *Best,
+ OverloadingResult OverloadResult,
+ bool AllowTypoCorrection) {
+ if (CandidateSet->empty())
+ return BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
+ llvm::MutableArrayRef<Expr *>(Args, NumArgs),
+ RParenLoc, /*EmptyLookup=*/true,
+ AllowTypoCorrection);
+
+ switch (OverloadResult) {
case OR_Success: {
- FunctionDecl *FDecl = Best->Function;
- MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
- CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
- DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
- Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
- return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc,
- ExecConfig);
+ 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);
+ return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
+ RParenLoc, ExecConfig);
}
case OR_No_Viable_Function: {
// Try to recover by looking for viable functions which the user might
// have meant to call.
- ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
+ ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
llvm::MutableArrayRef<Expr *>(Args, NumArgs),
RParenLoc,
/*EmptyLookup=*/false,
@@ -9787,44 +9846,73 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
if (!Recovery.isInvalid())
return Recovery;
- Diag(Fn->getLocStart(),
+ SemaRef.Diag(Fn->getLocStart(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
}
case OR_Ambiguous:
- Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call)
+ SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
- case OR_Deleted:
- {
- Diag(Fn->getLocStart(), diag::err_ovl_deleted_call)
- << Best->Function->isDeleted()
- << ULE->getName()
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ case OR_Deleted: {
+ SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_deleted_call)
+ << (*Best)->Function->isDeleted()
+ << ULE->getName()
+ << SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function)
+ << Fn->getSourceRange();
+ CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
- // We emitted an error for the unvailable/deleted function call but keep
- // the call in the AST.
- FunctionDecl *FDecl = Best->Function;
- Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
- return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
- }
+ // We emitted an error for the unvailable/deleted function call but keep
+ // the call in the AST.
+ FunctionDecl *FDecl = (*Best)->Function;
+ Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
+ return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
+ RParenLoc, ExecConfig);
+ }
}
// Overload resolution failed.
return ExprError();
}
+/// BuildOverloadedCallExpr - Given the call expression that calls Fn
+/// (which eventually refers to the declaration Func) and the call
+/// arguments Args/NumArgs, attempt to resolve the function call down
+/// to a specific function. If overload resolution succeeds, returns
+/// the call expression produced by overload resolution.
+/// Otherwise, emits diagnostics and returns ExprError.
+ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ Expr *ExecConfig,
+ bool AllowTypoCorrection) {
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ ExprResult result;
+
+ if (buildOverloadedCallSet(S, Fn, ULE, Args, NumArgs, LParenLoc,
+ &CandidateSet, &result))
+ return result;
+
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult OverloadResult =
+ CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best);
+
+ return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
+ RParenLoc, ExecConfig, &CandidateSet,
+ &Best, OverloadResult,
+ AllowTypoCorrection);
+}
+
static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
return Functions.size() > 1 ||
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
@@ -9889,10 +9977,10 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
- &Args[0], NumArgs,
+ llvm::makeArrayRef(Args, NumArgs),
Context.DependentTy,
VK_RValue,
- OpLoc));
+ OpLoc, false));
}
// Build an empty overload set.
@@ -9968,7 +10056,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Args[0] = Input;
CallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
- Args, NumArgs, ResultTy, VK, OpLoc);
+ llvm::makeArrayRef(Args, NumArgs),
+ ResultTy, VK, OpLoc, false);
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
FnDecl))
@@ -10069,7 +10158,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
Context.DependentTy,
VK_RValue, OK_Ordinary,
- OpLoc));
+ OpLoc,
+ FPFeatures.fp_contract));
return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc,
Context.DependentTy,
@@ -10077,7 +10167,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
OK_Ordinary,
Context.DependentTy,
Context.DependentTy,
- OpLoc));
+ OpLoc,
+ FPFeatures.fp_contract));
}
// FIXME: save results of ADL from here?
@@ -10089,11 +10180,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
- Args, 2,
- Context.DependentTy,
- VK_RValue,
- OpLoc));
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args,
+ Context.DependentTy, VK_RValue,
+ OpLoc, FPFeatures.fp_contract));
}
// Always do placeholder-like conversions on the RHS.
@@ -10208,7 +10297,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
- Args, 2, ResultTy, VK, OpLoc);
+ Args, ResultTy, VK, OpLoc,
+ FPFeatures.fp_contract);
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
FnDecl))
@@ -10270,7 +10360,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Result.isInvalid())
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
- return move(Result);
+ return Result;
}
case OR_Ambiguous:
@@ -10337,10 +10427,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Can't add any actual overloads yet
return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn,
- Args, 2,
+ Args,
Context.DependentTy,
VK_RValue,
- RLoc));
+ RLoc, false));
}
// Handle placeholders on both operands.
@@ -10416,8 +10506,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr.take(), Args, 2,
- ResultTy, VK, RLoc);
+ FnExpr.take(), Args,
+ ResultTy, VK, RLoc,
+ false);
if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall,
FnDecl))
@@ -10534,7 +10625,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
CXXMemberCallExpr *call
- = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs,
+ = new (Context) CXXMemberCallExpr(Context, MemExprE,
+ llvm::makeArrayRef(Args, NumArgs),
resultType, valueKind, RParenLoc);
if (CheckCallReturnType(proto->getResultType(),
@@ -10676,7 +10768,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
assert(Method && "Member call to something that isn't a method?");
CXXMemberCallExpr *TheCall =
- new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs,
+ new (Context) CXXMemberCallExpr(Context, MemExprE,
+ llvm::makeArrayRef(Args, NumArgs),
ResultType, VK, RParenLoc);
// Check for a valid return type.
@@ -10904,6 +10997,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// that calls this method, using Object for the implicit object
// parameter and passing along the remaining arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+
+ // An error diagnostic has already been printed when parsing the declaration.
+ if (Method->isInvalidDecl())
+ return ExprError();
+
const FunctionProtoType *Proto =
Method->getType()->getAs<FunctionProtoType>();
@@ -10942,8 +11040,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn.take(),
- MethodArgs, NumArgs + 1,
- ResultTy, VK, RParenLoc);
+ llvm::makeArrayRef(MethodArgs, NumArgs+1),
+ ResultTy, VK, RParenLoc, false);
delete [] MethodArgs;
if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall,
@@ -10966,7 +11064,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (ObjRes.isInvalid())
IsError = true;
else
- Object = move(ObjRes);
+ Object = ObjRes;
TheCall->setArg(0, Object.take());
// Check the argument types.
@@ -11116,7 +11214,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.take(),
- &Base, 1, ResultTy, VK, OpLoc);
+ Base, ResultTy, VK, OpLoc, false);
if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall,
Method))
@@ -11187,7 +11285,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
ResultTy = ResultTy.getNonLValueExprType(Context);
UserDefinedLiteral *UDL =
- new (Context) UserDefinedLiteral(Context, Fn.take(), ConvArgs, Args.size(),
+ new (Context) UserDefinedLiteral(Context, Fn.take(),
+ llvm::makeArrayRef(ConvArgs, Args.size()),
ResultTy, VK, LitEndLoc, UDSuffixLoc);
if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
@@ -11199,6 +11298,80 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
return MaybeBindToTemporary(UDL);
}
+/// Build a call to 'begin' or 'end' for a C++11 for-range statement. If the
+/// given LookupResult is non-empty, it is assumed to describe a member which
+/// will be invoked. Otherwise, the function will be found via argument
+/// dependent lookup.
+/// CallExpr is set to a valid expression and FRS_Success returned on success,
+/// otherwise CallExpr is set to ExprError() and some non-success value
+/// is returned.
+Sema::ForRangeStatus
+Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
+ SourceLocation RangeLoc, VarDecl *Decl,
+ BeginEndFunction BEF,
+ const DeclarationNameInfo &NameInfo,
+ LookupResult &MemberLookup,
+ OverloadCandidateSet *CandidateSet,
+ Expr *Range, ExprResult *CallExpr) {
+ CandidateSet->clear();
+ if (!MemberLookup.empty()) {
+ ExprResult MemberRef =
+ BuildMemberReferenceExpr(Range, Range->getType(), Loc,
+ /*IsPtr=*/false, CXXScopeSpec(),
+ /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/0,
+ MemberLookup,
+ /*TemplateArgs=*/0);
+ if (MemberRef.isInvalid()) {
+ *CallExpr = ExprError();
+ Diag(Range->getLocStart(), diag::note_in_for_range)
+ << RangeLoc << BEF << Range->getType();
+ return FRS_DiagnosticIssued;
+ }
+ *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), Loc, 0);
+ if (CallExpr->isInvalid()) {
+ *CallExpr = ExprError();
+ Diag(Range->getLocStart(), diag::note_in_for_range)
+ << RangeLoc << BEF << Range->getType();
+ return FRS_DiagnosticIssued;
+ }
+ } else {
+ UnresolvedSet<0> FoundNames;
+ UnresolvedLookupExpr *Fn =
+ UnresolvedLookupExpr::Create(Context, /*NamingClass=*/0,
+ NestedNameSpecifierLoc(), NameInfo,
+ /*NeedsADL=*/true, /*Overloaded=*/false,
+ FoundNames.begin(), FoundNames.end());
+
+ bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, &Range, 1, Loc,
+ CandidateSet, CallExpr);
+ if (CandidateSet->empty() || CandidateSetError) {
+ *CallExpr = ExprError();
+ return FRS_NoViableFunction;
+ }
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult OverloadResult =
+ CandidateSet->BestViableFunction(*this, Fn->getLocStart(), Best);
+
+ if (OverloadResult == OR_No_Viable_Function) {
+ *CallExpr = ExprError();
+ return FRS_NoViableFunction;
+ }
+ *CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, &Range, 1,
+ Loc, 0, CandidateSet, &Best,
+ OverloadResult,
+ /*AllowTypoCorrection=*/false);
+ if (CallExpr->isInvalid() || OverloadResult != OR_Success) {
+ *CallExpr = ExprError();
+ Diag(Range->getLocStart(), diag::note_in_for_range)
+ << RangeLoc << BEF << Range->getType();
+ return FRS_DiagnosticIssued;
+ }
+ }
+ return FRS_Success;
+}
+
+
/// FixOverloadedFunctionReference - E is an expression that refers to
/// a C++ overloaded function (possibly with some parentheses and
/// perhaps a '&' around it). We have resolved the overloaded function
@@ -11358,6 +11531,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
TemplateArgs,
type, valueKind, OK_Ordinary);
ME->setHadMultipleCandidates(true);
+ MarkMemberReferenced(ME);
return ME;
}
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 722ac19be533..a8d75b290f19 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -31,6 +31,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
@@ -91,9 +92,8 @@ namespace {
return new (S.Context) GenericSelectionExpr(S.Context,
gse->getGenericLoc(),
gse->getControllingExpr(),
- assocTypes.data(),
- assocs.data(),
- numAssocs,
+ assocTypes,
+ assocs,
gse->getDefaultLoc(),
gse->getRParenLoc(),
gse->containsUnexpandedParameterPack(),
@@ -187,7 +187,7 @@ namespace {
UnaryOperatorKind opcode,
Expr *op);
- ExprResult complete(Expr *syntacticForm);
+ virtual ExprResult complete(Expr *syntacticForm);
OpaqueValueExpr *capture(Expr *op);
OpaqueValueExpr *captureValueAsResult(Expr *op);
@@ -198,7 +198,14 @@ namespace {
}
/// Return true if assignments have a non-void result.
- virtual bool assignmentsHaveResult() { return true; }
+ bool CanCaptureValueOfType(QualType ty) {
+ assert(!ty->isIncompleteType());
+ assert(!ty->isDependentType());
+
+ if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl())
+ return ClassDecl->isTriviallyCopyable();
+ return true;
+ }
virtual Expr *rebuildAndCaptureObject(Expr *) = 0;
virtual ExprResult buildGet() = 0;
@@ -206,7 +213,7 @@ namespace {
bool captureSetValueAsResult) = 0;
};
- /// A PseudoOpBuilder for Objective-C @properties.
+ /// A PseudoOpBuilder for Objective-C \@properties.
class ObjCPropertyOpBuilder : public PseudoOpBuilder {
ObjCPropertyRefExpr *RefExpr;
ObjCPropertyRefExpr *SyntacticRefExpr;
@@ -239,6 +246,9 @@ namespace {
Expr *rebuildAndCaptureObject(Expr *syntacticBase);
ExprResult buildGet();
ExprResult buildSet(Expr *op, SourceLocation, bool);
+ ExprResult complete(Expr *SyntacticForm);
+
+ bool isWeakProperty() const;
};
/// A PseudoOpBuilder for Objective-C array/dictionary indexing.
@@ -292,7 +302,7 @@ OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) {
/// operation. This routine is safe against expressions which may
/// already be captured.
///
-/// \param Returns the captured expression, which will be the
+/// \returns the captured expression, which will be the
/// same as the input if the input was already captured
OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) {
assert(ResultIndex == PseudoObjectExpr::NoResult);
@@ -353,7 +363,7 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
opcode, capturedRHS->getType(),
capturedRHS->getValueKind(),
- OK_Ordinary, opcLoc);
+ OK_Ordinary, opcLoc, false);
} else {
ExprResult opLHS = buildGet();
if (opLHS.isInvalid()) return ExprError();
@@ -372,12 +382,12 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
OK_Ordinary,
opLHS.get()->getType(),
result.get()->getType(),
- opcLoc);
+ opcLoc, false);
}
// The result of the assignment, if not void, is the value set into
// the l-value.
- result = buildSet(result.take(), opcLoc, assignmentsHaveResult());
+ result = buildSet(result.take(), opcLoc, /*captureSetValueAsResult*/ true);
if (result.isInvalid()) return ExprError();
addSemanticExpr(result.take());
@@ -401,7 +411,7 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
QualType resultType = result.get()->getType();
// That's the postfix result.
- if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) {
+ if (UnaryOperator::isPostfix(opcode) && CanCaptureValueOfType(resultType)) {
result = capture(result.take());
setResultToLastSemantic();
}
@@ -420,8 +430,7 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
// Store that back into the result. The value stored is the result
// of a prefix operation.
- result = buildSet(result.take(), opcLoc,
- UnaryOperator::isPrefix(opcode) && assignmentsHaveResult());
+ result = buildSet(result.take(), opcLoc, UnaryOperator::isPrefix(opcode));
if (result.isInvalid()) return ExprError();
addSemanticExpr(result.take());
@@ -472,6 +481,23 @@ static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
return S.LookupMethodInObjectType(sel, IT, false);
}
+bool ObjCPropertyOpBuilder::isWeakProperty() const {
+ QualType T;
+ if (RefExpr->isExplicitProperty()) {
+ const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty();
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ return true;
+
+ T = Prop->getType();
+ } else if (Getter) {
+ T = Getter->getResultType();
+ } else {
+ return false;
+ }
+
+ return T.getObjCLifetime() == Qualifiers::OCL_Weak;
+}
+
bool ObjCPropertyOpBuilder::findGetter() {
if (Getter) return true;
@@ -532,7 +558,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
// Do a normal method lookup first.
if (ObjCMethodDecl *setter =
LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
- if (setter->isSynthesized() && warn)
+ if (setter->isPropertyAccessor() && warn)
if (const ObjCInterfaceDecl *IFace =
dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) {
const StringRef thisPropertyName(prop->getName());
@@ -617,7 +643,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
/// Store to an Objective-C property reference.
///
-/// \param bindSetValueAsResult - If true, capture the actual
+/// \param captureSetValueAsResult If true, capture the actual
/// value being set as the value of the property operation.
ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
@@ -676,7 +702,8 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ObjCMessageExpr *msgExpr =
cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
Expr *arg = msgExpr->getArg(0);
- msgExpr->setArg(0, captureValueAsResult(arg));
+ if (CanCaptureValueOfType(arg->getType()))
+ msgExpr->setArg(0, captureValueAsResult(arg));
}
return msg;
@@ -819,6 +846,19 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op);
}
+ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) {
+ if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) {
+ DiagnosticsEngine::Level Level =
+ S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ SyntacticForm->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr,
+ SyntacticRefExpr->isMessagingGetter());
+ }
+
+ return PseudoOpBuilder::complete(SyntacticForm);
+}
+
// ObjCSubscript build stuff.
//
@@ -1035,7 +1075,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
0 /*TypeSourceInfo */,
S.Context.getTranslationUnitDecl(),
true /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -1151,7 +1191,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
ResultTInfo,
S.Context.getTranslationUnitDecl(),
true /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -1255,7 +1295,7 @@ ExprResult ObjCSubscriptOpBuilder::buildGet() {
/// Store into the container the "op" object at "Index"'ed location
/// by building this messaging expression:
/// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index;
-/// \param bindSetValueAsResult - If true, capture the actual
+/// \param captureSetValueAsResult If true, capture the actual
/// value being set as the value of the property operation.
ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
@@ -1279,7 +1319,8 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ObjCMessageExpr *msgExpr =
cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
Expr *arg = msgExpr->getArg(0);
- msgExpr->setArg(0, captureValueAsResult(arg));
+ if (CanCaptureValueOfType(arg->getType()))
+ msgExpr->setArg(0, captureValueAsResult(arg));
}
return msg;
@@ -1333,7 +1374,7 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
// Do nothing if either argument is dependent.
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
- VK_RValue, OK_Ordinary, opcLoc);
+ VK_RValue, OK_Ordinary, opcLoc, false);
// Filter out non-overload placeholder types in the RHS.
if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1404,14 +1445,14 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
cop->getObjectKind(),
cop->getComputationLHSType(),
cop->getComputationResultType(),
- cop->getOperatorLoc());
+ cop->getOperatorLoc(), false);
} else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
bop->getType(), bop->getValueKind(),
bop->getObjectKind(),
- bop->getOperatorLoc());
+ bop->getOperatorLoc(), false);
} else {
assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 86884b787339..f55174e05cc1 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -28,27 +28,10 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.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/MCAsmLexer.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
using namespace clang;
using namespace sema;
@@ -177,6 +160,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
return;
+ // If this is a GNU statement expression expanded from a macro, it is probably
+ // unused because it is a function-like macro that can be used as either an
+ // expression or statement. Don't warn, because it is almost certainly a
+ // false positive.
+ if (isa<StmtExpr>(E) && Loc.isMacroID())
+ return;
+
// Okay, we have an unused result. Depending on what the base expression is,
// we might want to make a more specific diagnostic. Check for one of these
// cases now.
@@ -271,7 +261,7 @@ StmtResult
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg elts, bool isStmtExpr) {
unsigned NumElts = elts.size();
- Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
+ Stmt **Elts = elts.data();
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
@@ -381,8 +371,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
// Otherwise, things are good. Fill in the declaration and return it.
LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
TheDecl->setStmt(LS);
- if (!TheDecl->isGnuLocal())
+ if (!TheDecl->isGnuLocal()) {
+ TheDecl->setLocStart(IdentLoc);
TheDecl->setLocation(IdentLoc);
+ }
return Owned(LS);
}
@@ -1566,25 +1558,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
ForLoc, RParenLoc));
}
-namespace {
-
-enum BeginEndFunction {
- BEF_begin,
- BEF_end
-};
-
-/// Build a variable declaration for a for-range statement.
-static VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
- QualType Type, const char *Name) {
- DeclContext *DC = SemaRef.CurContext;
- 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);
- Decl->setImplicit();
- return Decl;
-}
-
/// Finish building a variable declaration for a for-range statement.
/// \return true if an error occurs.
static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
@@ -1617,12 +1590,14 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
return false;
}
+namespace {
+
/// Produce a note indicating which begin/end function was implicitly called
-/// by a C++0x for-range statement. This is often not obvious from the code,
+/// by a C++11 for-range statement. This is often not obvious from the code,
/// nor from the diagnostics produced when analysing the implicit expressions
/// required in a for-range statement.
void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
- BeginEndFunction BEF) {
+ Sema::BeginEndFunction BEF) {
CallExpr *CE = dyn_cast<CallExpr>(E);
if (!CE)
return;
@@ -1643,56 +1618,16 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
<< BEF << IsTemplate << Description << E->getType();
}
-/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the
-/// given LookupResult is non-empty, it is assumed to describe a member which
-/// will be invoked. Otherwise, the function will be found via argument
-/// dependent lookup.
-static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
- SourceLocation Loc,
- VarDecl *Decl,
- BeginEndFunction BEF,
- const DeclarationNameInfo &NameInfo,
- LookupResult &MemberLookup,
- Expr *Range) {
- ExprResult CallExpr;
- if (!MemberLookup.empty()) {
- ExprResult MemberRef =
- SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc,
- /*IsPtr=*/false, CXXScopeSpec(),
- /*TemplateKWLoc=*/SourceLocation(),
- /*FirstQualifierInScope=*/0,
- MemberLookup,
- /*TemplateArgs=*/0);
- if (MemberRef.isInvalid())
- return ExprError();
- CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(),
- Loc, 0);
- if (CallExpr.isInvalid())
- return ExprError();
- } else {
- UnresolvedSet<0> FoundNames;
- // C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace
- // std is an associated namespace.
- UnresolvedLookupExpr *Fn =
- UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0,
- NestedNameSpecifierLoc(), NameInfo,
- /*NeedsADL=*/true, /*Overloaded=*/false,
- FoundNames.begin(), FoundNames.end(),
- /*LookInStdNamespace=*/true);
- CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc,
- 0, /*AllowTypoCorrection=*/false);
- if (CallExpr.isInvalid()) {
- SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type)
- << Range->getType();
- return ExprError();
- }
- }
- if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc,
- diag::err_for_range_iter_deduction_failure)) {
- NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF);
- return ExprError();
- }
- return CallExpr;
+/// Build a variable declaration for a for-range statement.
+VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
+ QualType Type, const char *Name) {
+ DeclContext *DC = SemaRef.CurContext;
+ 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);
+ Decl->setImplicit();
+ return Decl;
}
}
@@ -1723,7 +1658,7 @@ static bool ObjCEnumerationCollection(Expr *Collection) {
StmtResult
Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
Stmt *First, SourceLocation ColonLoc, Expr *Range,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc, BuildForRangeKind Kind) {
if (!First || !Range)
return StmtError();
@@ -1761,15 +1696,137 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
/*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
- RParenLoc);
+ RParenLoc, Kind);
}
-/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement.
+/// \brief Create the initialization, compare, and increment steps for
+/// the range-based for loop expression.
+/// This function does not handle array-based for loops,
+/// which are created in Sema::BuildCXXForRangeStmt.
+///
+/// \returns a ForRangeStatus indicating success or what kind of error occurred.
+/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
+/// CandidateSet and BEF are set and some non-success value is returned on
+/// failure.
+static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
+ Expr *BeginRange, Expr *EndRange,
+ QualType RangeType,
+ VarDecl *BeginVar,
+ VarDecl *EndVar,
+ SourceLocation ColonLoc,
+ OverloadCandidateSet *CandidateSet,
+ ExprResult *BeginExpr,
+ ExprResult *EndExpr,
+ Sema::BeginEndFunction *BEF) {
+ DeclarationNameInfo BeginNameInfo(
+ &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
+ DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
+ ColonLoc);
+
+ LookupResult BeginMemberLookup(SemaRef, BeginNameInfo,
+ Sema::LookupMemberName);
+ LookupResult EndMemberLookup(SemaRef, EndNameInfo, Sema::LookupMemberName);
+
+ if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) {
+ // - if _RangeT is a class type, the unqualified-ids begin and end are
+ // looked up in the scope of class _RangeT as if by class member access
+ // lookup (3.4.5), and if either (or both) finds at least one
+ // declaration, begin-expr and end-expr are __range.begin() and
+ // __range.end(), respectively;
+ SemaRef.LookupQualifiedName(BeginMemberLookup, D);
+ SemaRef.LookupQualifiedName(EndMemberLookup, D);
+
+ if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
+ SourceLocation RangeLoc = BeginVar->getLocation();
+ *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin;
+
+ SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch)
+ << RangeLoc << BeginRange->getType() << *BEF;
+ return Sema::FRS_DiagnosticIssued;
+ }
+ } else {
+ // - otherwise, begin-expr and end-expr are begin(__range) and
+ // end(__range), respectively, where begin and end are looked up with
+ // argument-dependent lookup (3.4.2). For the purposes of this name
+ // lookup, namespace std is an associated namespace.
+
+ }
+
+ *BEF = Sema::BEF_begin;
+ Sema::ForRangeStatus RangeStatus =
+ SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar,
+ Sema::BEF_begin, BeginNameInfo,
+ BeginMemberLookup, CandidateSet,
+ BeginRange, BeginExpr);
+
+ if (RangeStatus != Sema::FRS_Success)
+ return RangeStatus;
+ if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
+ return Sema::FRS_DiagnosticIssued;
+ }
+
+ *BEF = Sema::BEF_end;
+ RangeStatus =
+ SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar,
+ Sema::BEF_end, EndNameInfo,
+ EndMemberLookup, CandidateSet,
+ EndRange, EndExpr);
+ if (RangeStatus != Sema::FRS_Success)
+ return RangeStatus;
+ if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF);
+ return Sema::FRS_DiagnosticIssued;
+ }
+ return Sema::FRS_Success;
+}
+
+/// Speculatively attempt to dereference an invalid range expression.
+/// If the attempt fails, this function will return a valid, null StmtResult
+/// and emit no diagnostics.
+static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
+ SourceLocation ForLoc,
+ Stmt *LoopVarDecl,
+ SourceLocation ColonLoc,
+ Expr *Range,
+ SourceLocation RangeLoc,
+ SourceLocation RParenLoc) {
+ // Determine whether we can rebuild the for-range statement with a
+ // dereferenced range expression.
+ ExprResult AdjustedRange;
+ {
+ Sema::SFINAETrap Trap(SemaRef);
+
+ AdjustedRange = SemaRef.BuildUnaryOp(S, RangeLoc, UO_Deref, Range);
+ if (AdjustedRange.isInvalid())
+ return StmtResult();
+
+ StmtResult SR =
+ SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc,
+ AdjustedRange.get(), RParenLoc,
+ Sema::BFRK_Check);
+ if (SR.isInvalid())
+ return StmtResult();
+ }
+
+ // The attempt to dereference worked well enough that it could produce a valid
+ // loop. Produce a fixit, and rebuild the loop with diagnostics enabled, in
+ // case there are any other (non-fatal) problems with it.
+ SemaRef.Diag(RangeLoc, diag::err_for_range_dereference)
+ << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*");
+ return SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc,
+ AdjustedRange.get(), RParenLoc,
+ Sema::BFRK_Rebuild);
+}
+
+/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
StmtResult
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
Expr *Inc, Stmt *LoopVarDecl,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc, BuildForRangeKind Kind) {
Scope *S = getCurScope();
DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
@@ -1855,50 +1912,43 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
return StmtError();
}
} else {
- DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"),
- ColonLoc);
- DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"),
- ColonLoc);
-
- LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName);
- LookupResult EndMemberLookup(*this, EndNameInfo, LookupMemberName);
-
- if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) {
- // - if _RangeT is a class type, the unqualified-ids begin and end are
- // looked up in the scope of class _RangeT as if by class member access
- // lookup (3.4.5), and if either (or both) finds at least one
- // declaration, begin-expr and end-expr are __range.begin() and
- // __range.end(), respectively;
- LookupQualifiedName(BeginMemberLookup, D);
- LookupQualifiedName(EndMemberLookup, D);
-
- if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
- Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch)
- << RangeType << BeginMemberLookup.empty();
- return StmtError();
- }
- } else {
- // - otherwise, begin-expr and end-expr are begin(__range) and
- // end(__range), respectively, where begin and end are looked up with
- // argument-dependent lookup (3.4.2). For the purposes of this name
- // lookup, namespace std is an associated namespace.
+ OverloadCandidateSet CandidateSet(RangeLoc);
+ Sema::BeginEndFunction BEFFailure;
+ ForRangeStatus RangeStatus =
+ BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
+ EndRangeRef.get(), RangeType,
+ BeginVar, EndVar, ColonLoc, &CandidateSet,
+ &BeginExpr, &EndExpr, &BEFFailure);
+
+ // If building the range failed, try dereferencing the range expression
+ // unless a diagnostic was issued or the end function is problematic.
+ if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
+ BEFFailure == BEF_begin) {
+ StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
+ LoopVarDecl, ColonLoc,
+ Range, RangeLoc,
+ RParenLoc);
+ if (SR.isInvalid() || SR.isUsable())
+ return SR;
}
- BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar,
- BEF_begin, BeginNameInfo,
- BeginMemberLookup,
- BeginRangeRef.get());
- if (BeginExpr.isInvalid())
- return StmtError();
-
- EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar,
- BEF_end, EndNameInfo,
- EndMemberLookup, EndRangeRef.get());
- if (EndExpr.isInvalid())
+ // Otherwise, emit diagnostics if we haven't already.
+ if (RangeStatus == FRS_NoViableFunction) {
+ 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));
+ }
+ // Return an error if no fix was discovered.
+ if (RangeStatus != FRS_Success)
return StmtError();
}
- // C++0x [decl.spec.auto]p6: BeginType and EndType must be the same.
+ assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
+ "invalid range expression in for loop");
+
+ // C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
@@ -1930,6 +1980,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get());
NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
if (NotEqExpr.isInvalid()) {
+ Diag(RangeLoc, diag::note_for_range_invalid_iterator)
+ << RangeLoc << 0 << BeginRangeRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
if (!Context.hasSameType(BeginType, EndType))
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
@@ -1945,6 +1997,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
if (IncrExpr.isInvalid()) {
+ Diag(RangeLoc, diag::note_for_range_invalid_iterator)
+ << RangeLoc << 2 << BeginRangeRef.get()->getType() ;
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
@@ -1957,12 +2011,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
+ Diag(RangeLoc, diag::note_for_range_invalid_iterator)
+ << RangeLoc << 1 << BeginRangeRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
- // Attach *__begin as initializer for VD.
- if (!LoopVar->isInvalidDecl()) {
+ // Attach *__begin as initializer for VD. Don't touch it if we're just
+ // trying to determine whether this would be a valid range.
+ if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false,
/*TypeMayContainAuto=*/true);
if (LoopVar->isInvalidDecl())
@@ -1973,6 +2030,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
RangeVar->setUsed();
}
+ // Don't bother to actually allocate the result if we're just trying to
+ // determine whether it would be valid.
+ if (Kind == BFRK_Check)
+ return StmtResult();
+
return Owned(new (Context) CXXForRangeStmt(RangeDS,
cast_or_null<DeclStmt>(BeginEndDecl.get()),
NotEqExpr.take(), IncrExpr.take(),
@@ -2485,600 +2547,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
return Owned(Result);
}
-/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
-/// ignore "noop" casts in places where an lvalue is required by an inline asm.
-/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
-/// provide a strong guidance to not use it.
-///
-/// This method checks to see if the argument is an acceptable l-value and
-/// returns false if it is a case we can handle.
-static bool CheckAsmLValue(const Expr *E, Sema &S) {
- // Type dependent expressions will be checked during instantiation.
- if (E->isTypeDependent())
- return false;
-
- if (E->isLValue())
- return false; // Cool, this is an lvalue.
-
- // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
- // are supposed to allow.
- const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
- if (E != E2 && E2->isLValue()) {
- if (!S.getLangOpts().HeinousExtensions)
- S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
- << E->getSourceRange();
- else
- S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
- << E->getSourceRange();
- // Accept, even if we emitted an error diagnostic.
- return false;
- }
-
- // None of the above, just randomly invalid non-lvalue.
- return true;
-}
-
-/// isOperandMentioned - Return true if the specified operand # is mentioned
-/// anywhere in the decomposed asm string.
-static bool isOperandMentioned(unsigned OpNo,
- ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
- for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
- const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
- if (!Piece.isOperand()) continue;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == OpNo)
- return true;
- }
- return false;
-}
-
-StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
- bool IsVolatile, unsigned NumOutputs,
- unsigned NumInputs, IdentifierInfo **Names,
- MultiExprArg constraints, MultiExprArg exprs,
- Expr *asmString, MultiExprArg clobbers,
- SourceLocation RParenLoc, bool MSAsm) {
- unsigned NumClobbers = clobbers.size();
- StringLiteral **Constraints =
- reinterpret_cast<StringLiteral**>(constraints.get());
- Expr **Exprs = exprs.get();
- StringLiteral *AsmString = cast<StringLiteral>(asmString);
- StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
-
- SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
-
- // The parser verifies that there is a string literal here.
- if (!AsmString->isAscii())
- return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
- << AsmString->getSourceRange());
-
- for (unsigned i = 0; i != NumOutputs; i++) {
- StringLiteral *Literal = Constraints[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
-
- StringRef OutputName;
- if (Names[i])
- OutputName = Names[i]->getName();
-
- TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
- if (!Context.getTargetInfo().validateOutputConstraint(Info))
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_invalid_output_constraint)
- << Info.getConstraintStr());
-
- // Check that the output exprs are valid lvalues.
- Expr *OutputExpr = Exprs[i];
- if (CheckAsmLValue(OutputExpr, *this)) {
- return StmtError(Diag(OutputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_output)
- << OutputExpr->getSourceRange());
- }
-
- OutputConstraintInfos.push_back(Info);
- }
-
- SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
-
- for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
- StringLiteral *Literal = Constraints[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
-
- StringRef InputName;
- if (Names[i])
- InputName = Names[i]->getName();
-
- TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
- if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
- NumOutputs, Info)) {
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_invalid_input_constraint)
- << Info.getConstraintStr());
- }
-
- Expr *InputExpr = Exprs[i];
-
- // Only allow void types for memory constraints.
- if (Info.allowsMemory() && !Info.allowsRegister()) {
- if (CheckAsmLValue(InputExpr, *this))
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_input)
- << Info.getConstraintStr()
- << InputExpr->getSourceRange());
- }
-
- if (Info.allowsRegister()) {
- if (InputExpr->getType()->isVoidType()) {
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_asm_invalid_type_in_input)
- << InputExpr->getType() << Info.getConstraintStr()
- << InputExpr->getSourceRange());
- }
- }
-
- ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
- if (Result.isInvalid())
- return StmtError();
-
- Exprs[i] = Result.take();
- InputConstraintInfos.push_back(Info);
- }
-
- // Check that the clobbers are valid.
- for (unsigned i = 0; i != NumClobbers; i++) {
- StringLiteral *Literal = Clobbers[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
-
- StringRef Clobber = Literal->getString();
-
- if (!Context.getTargetInfo().isValidClobber(Clobber))
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_unknown_register_name) << Clobber);
- }
-
- AsmStmt *NS =
- new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
- NumOutputs, NumInputs, Names, Constraints, Exprs,
- AsmString, NumClobbers, Clobbers, RParenLoc);
- // Validate the asm string, ensuring it makes sense given the operands we
- // have.
- SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
- unsigned DiagOffs;
- if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
- Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
- << AsmString->getSourceRange();
- return StmtError();
- }
-
- // Validate tied input operands for type mismatches.
- for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
- TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
-
- // If this is a tied constraint, verify that the output and input have
- // either exactly the same type, or that they are int/ptr operands with the
- // same size (int/long, int*/long, are ok etc).
- if (!Info.hasTiedOperand()) continue;
-
- unsigned TiedTo = Info.getTiedOperand();
- unsigned InputOpNo = i+NumOutputs;
- Expr *OutputExpr = Exprs[TiedTo];
- Expr *InputExpr = Exprs[InputOpNo];
-
- if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
- continue;
-
- QualType InTy = InputExpr->getType();
- QualType OutTy = OutputExpr->getType();
- if (Context.hasSameType(InTy, OutTy))
- continue; // All types can be tied to themselves.
-
- // Decide if the input and output are in the same domain (integer/ptr or
- // floating point.
- enum AsmDomain {
- AD_Int, AD_FP, AD_Other
- } InputDomain, OutputDomain;
-
- if (InTy->isIntegerType() || InTy->isPointerType())
- InputDomain = AD_Int;
- else if (InTy->isRealFloatingType())
- InputDomain = AD_FP;
- else
- InputDomain = AD_Other;
-
- if (OutTy->isIntegerType() || OutTy->isPointerType())
- OutputDomain = AD_Int;
- else if (OutTy->isRealFloatingType())
- OutputDomain = AD_FP;
- else
- OutputDomain = AD_Other;
-
- // They are ok if they are the same size and in the same domain. This
- // allows tying things like:
- // void* to int*
- // void* to int if they are the same size.
- // double to long double if they are the same size.
- //
- uint64_t OutSize = Context.getTypeSize(OutTy);
- uint64_t InSize = Context.getTypeSize(InTy);
- if (OutSize == InSize && InputDomain == OutputDomain &&
- InputDomain != AD_Other)
- continue;
-
- // If the smaller input/output operand is not mentioned in the asm string,
- // then we can promote the smaller one to a larger input and the asm string
- // won't notice.
- bool SmallerValueMentioned = false;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (isOperandMentioned(InputOpNo, Pieces)) {
- // This is a use in the asm string of the smaller operand. Since we
- // codegen this by promoting to a wider value, the asm will get printed
- // "wrong".
- SmallerValueMentioned |= InSize < OutSize;
- }
- if (isOperandMentioned(TiedTo, Pieces)) {
- // If this is a reference to the output, and if the output is the larger
- // value, then it's ok because we'll promote the input to the larger type.
- SmallerValueMentioned |= OutSize < InSize;
- }
-
- // If the smaller value wasn't mentioned in the asm string, and if the
- // output was a register, just extend the shorter one to the size of the
- // larger one.
- if (!SmallerValueMentioned && InputDomain != AD_Other &&
- OutputConstraintInfos[TiedTo].allowsRegister())
- continue;
-
- // Either both of the operands were mentioned or the smaller one was
- // mentioned. One more special case that we'll allow: if the tied input is
- // integer, unmentioned, and is a constant, then we'll allow truncating it
- // down to the size of the destination.
- if (InputDomain == AD_Int && OutputDomain == AD_Int &&
- !isOperandMentioned(InputOpNo, Pieces) &&
- InputExpr->isEvaluatable(Context)) {
- CastKind castKind =
- (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
- InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
- Exprs[InputOpNo] = InputExpr;
- NS->setInputExpr(i, InputExpr);
- continue;
- }
-
- Diag(InputExpr->getLocStart(),
- diag::err_asm_tying_incompatible_types)
- << InTy << OutTy << OutputExpr->getSourceRange()
- << InputExpr->getSourceRange();
- return StmtError();
- }
-
- return Owned(NS);
-}
-
-// isMSAsmKeyword - Return true if this is an MS-style inline asm keyword. These
-// require special handling.
-static bool isMSAsmKeyword(StringRef Name) {
- bool Ret = llvm::StringSwitch<bool>(Name)
- .Cases("EVEN", "ALIGN", true) // Alignment directives.
- .Cases("LENGTH", "SIZE", "TYPE", true) // Type and variable sizes.
- .Case("_emit", true) // _emit Pseudoinstruction.
- .Default(false);
- return Ret;
-}
-
-static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
- StringRef Asm;
- SmallString<512> TokenBuf;
- TokenBuf.resize(512);
- bool StringInvalid = false;
- Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
- assert (!StringInvalid && "Expected valid string!");
- return Asm;
-}
-
-static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple,
- SourceLocation AsmLoc,
- ArrayRef<Token> AsmToks,
- const TargetInfo &TI,
- std::vector<llvm::BitVector> &AsmRegs,
- std::vector<llvm::BitVector> &AsmNames,
- std::vector<std::string> &AsmStrings) {
- assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-
- // Assume simple asm stmt until we parse a non-register identifer (or we just
- // need to bail gracefully).
- IsSimple = true;
-
- SmallString<512> Asm;
- unsigned NumAsmStrings = 0;
- for (unsigned i = 0, e = AsmToks.size(); i != e; ++i) {
-
- // Determine if this should be considered a new asm.
- bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
- AsmToks[i].is(tok::kw_asm);
-
- // Emit the previous asm string.
- if (i && isNewAsm) {
- AsmStrings[NumAsmStrings++] = Asm.c_str();
- if (AsmToks[i].is(tok::kw_asm)) {
- ++i; // Skip __asm
- assert (i != e && "Expected another token.");
- }
- }
-
- // Start a new asm string with the opcode.
- if (isNewAsm) {
- AsmRegs[NumAsmStrings].resize(AsmToks.size());
- AsmNames[NumAsmStrings].resize(AsmToks.size());
-
- StringRef Piece = AsmToks[i].getIdentifierInfo()->getName();
- // MS-style inline asm keywords require special handling.
- if (isMSAsmKeyword(Piece))
- IsSimple = false;
-
- // TODO: Verify this is a valid opcode.
- Asm = Piece;
- continue;
- }
-
- if (i && AsmToks[i].hasLeadingSpace())
- Asm += ' ';
-
- // Check the operand(s).
- switch (AsmToks[i].getKind()) {
- default:
- IsSimple = false;
- Asm += getSpelling(SemaRef, AsmToks[i]);
- break;
- case tok::comma: Asm += ","; break;
- case tok::colon: Asm += ":"; break;
- case tok::l_square: Asm += "["; break;
- case tok::r_square: Asm += "]"; break;
- case tok::l_brace: Asm += "{"; break;
- case tok::r_brace: Asm += "}"; break;
- case tok::numeric_constant:
- Asm += getSpelling(SemaRef, AsmToks[i]);
- break;
- case tok::identifier: {
- IdentifierInfo *II = AsmToks[i].getIdentifierInfo();
- StringRef Name = II->getName();
-
- // Valid register?
- if (TI.isValidGCCRegisterName(Name)) {
- AsmRegs[NumAsmStrings].set(i);
- Asm += Name;
- break;
- }
-
- IsSimple = false;
-
- // MS-style inline asm keywords require special handling.
- if (isMSAsmKeyword(Name)) {
- IsSimple = false;
- Asm += Name;
- break;
- }
-
- // FIXME: Why are we missing this segment register?
- if (Name == "fs") {
- Asm += Name;
- break;
- }
-
- // Lookup the identifier.
- // TODO: Someone with more experience with clang should verify this the
- // proper way of doing a symbol lookup.
- DeclarationName DeclName(II);
- Scope *CurScope = SemaRef.getCurScope();
- LookupResult R(SemaRef, DeclName, AsmLoc, Sema::LookupOrdinaryName);
- if (!SemaRef.LookupName(R, CurScope, false/*AllowBuiltinCreation*/))
- break;
-
- assert (R.isSingleResult() && "Expected a single result?!");
- NamedDecl *Decl = R.getFoundDecl();
- switch (Decl->getKind()) {
- default:
- assert(0 && "Unknown decl kind.");
- break;
- case Decl::Var: {
- case Decl::ParmVar:
- AsmNames[NumAsmStrings].set(i);
-
- VarDecl *Var = cast<VarDecl>(Decl);
- QualType Ty = Var->getType();
- (void)Ty; // Avoid warning.
- // TODO: Patch identifier with valid operand. One potential idea is to
- // probe the backend with type information to guess the possible
- // operand.
- break;
- }
- }
- break;
- }
- }
- }
-
- // Emit the final (and possibly only) asm string.
- AsmStrings[NumAsmStrings] = Asm.c_str();
-}
-
-// Build the unmodified MSAsmString.
-static std::string buildMSAsmString(Sema &SemaRef,
- ArrayRef<Token> AsmToks,
- unsigned &NumAsmStrings) {
- assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
- NumAsmStrings = 0;
-
- SmallString<512> Asm;
- for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
- bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
- AsmToks[i].is(tok::kw_asm);
-
- if (isNewAsm) {
- ++NumAsmStrings;
- if (i)
- Asm += '\n';
- if (AsmToks[i].is(tok::kw_asm)) {
- i++; // Skip __asm
- assert (i != e && "Expected another token");
- }
- }
-
- if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
- Asm += ' ';
-
- Asm += getSpelling(SemaRef, AsmToks[i]);
- }
- return Asm.c_str();
-}
-
-StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
- SourceLocation LBraceLoc,
- ArrayRef<Token> AsmToks,
- SourceLocation EndLoc) {
- // MS-style inline assembly is not fully supported, so emit a warning.
- Diag(AsmLoc, diag::warn_unsupported_msasm);
- SmallVector<StringRef,4> Clobbers;
- std::set<std::string> ClobberRegs;
- SmallVector<IdentifierInfo*, 4> Inputs;
- SmallVector<IdentifierInfo*, 4> Outputs;
-
- // Empty asm statements don't need to instantiate the AsmParser, etc.
- if (AsmToks.empty()) {
- StringRef AsmString;
- MSAsmStmt *NS =
- new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
- /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
- AsmString, Clobbers, EndLoc);
- return Owned(NS);
- }
-
- unsigned NumAsmStrings;
- std::string AsmString = buildMSAsmString(*this, AsmToks, NumAsmStrings);
-
- bool IsSimple;
- std::vector<llvm::BitVector> Regs;
- std::vector<llvm::BitVector> Names;
- std::vector<std::string> PatchedAsmStrings;
-
- Regs.resize(NumAsmStrings);
- Names.resize(NumAsmStrings);
- PatchedAsmStrings.resize(NumAsmStrings);
-
- // Rewrite operands to appease the AsmParser.
- patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks,
- Context.getTargetInfo(), Regs, Names, PatchedAsmStrings);
-
- // patchMSAsmStrings doesn't correctly patch non-simple asm statements.
- if (!IsSimple) {
- MSAsmStmt *NS =
- new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
- /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
- AsmString, Clobbers, EndLoc);
- return Owned(NS);
- }
-
- // Initialize targets and assembly printers/parsers.
- llvm::InitializeAllTargetInfos();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmParsers();
-
- // Get the target specific parser.
- std::string Error;
- const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
- const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
-
- OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
- OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
- OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
- OwningPtr<llvm::MCSubtargetInfo>
- STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
-
- for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) {
- llvm::SourceMgr SrcMgr;
- llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
- llvm::MemoryBuffer *Buffer =
- llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<inline asm>");
-
- // Tell SrcMgr about this buffer, which is what the parser will pick up.
- SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
-
- OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
- OwningPtr<llvm::MCAsmParser>
- Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
- OwningPtr<llvm::MCTargetAsmParser>
- TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
- // Change to the Intel dialect.
- Parser->setAssemblerDialect(1);
- Parser->setTargetParser(*TargetParser.get());
-
- // Prime the lexer.
- Parser->Lex();
-
- // Parse the opcode.
- StringRef IDVal;
- Parser->ParseIdentifier(IDVal);
-
- // Canonicalize the opcode to lower case.
- SmallString<128> Opcode;
- for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
- Opcode.push_back(tolower(IDVal[i]));
-
- // Parse the operands.
- llvm::SMLoc IDLoc;
- SmallVector<llvm::MCParsedAsmOperand*, 8> Operands;
- bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc,
- Operands);
- assert (!HadError && "Unexpected error parsing instruction");
-
- // Match the MCInstr.
- SmallVector<llvm::MCInst, 2> Instrs;
- HadError = TargetParser->MatchInstruction(IDLoc, Operands, Instrs);
- assert (!HadError && "Unexpected error matching instruction");
- assert ((Instrs.size() == 1) && "Expected only a single instruction.");
-
- // Get the instruction descriptor.
- llvm::MCInst Inst = Instrs[0];
- const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
- const llvm::MCInstrDesc &Desc = MII->get(Inst.getOpcode());
- llvm::MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
-
- // Build the list of clobbers.
- for (unsigned i = 0, e = Desc.getNumDefs(); i != e; ++i) {
- const llvm::MCOperand &Op = Inst.getOperand(i);
- if (!Op.isReg())
- continue;
-
- std::string Reg;
- llvm::raw_string_ostream OS(Reg);
- IP->printRegName(OS, Op.getReg());
-
- StringRef Clobber(OS.str());
- if (!Context.getTargetInfo().isValidClobber(Clobber))
- return StmtError(Diag(AsmLoc, diag::err_asm_unknown_register_name) <<
- Clobber);
- ClobberRegs.insert(Reg);
- }
- }
- for (std::set<std::string>::iterator I = ClobberRegs.begin(),
- E = ClobberRegs.end(); I != E; ++I)
- Clobbers.push_back(*I);
-
- MSAsmStmt *NS =
- new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
- /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
- AsmString, Clobbers, EndLoc);
- return Owned(NS);
-}
-
StmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, Decl *Parm,
@@ -3104,7 +2572,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
getCurFunction()->setHasBranchProtectedScope();
unsigned NumCatchStmts = CatchStmts.size();
return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try,
- CatchStmts.release(),
+ CatchStmts.data(),
NumCatchStmts,
Finally));
}
@@ -3239,7 +2707,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
unsigned NumHandlers = RawHandlers.size();
assert(NumHandlers > 0 &&
"The parser shouldn't call this if there are no handlers.");
- Stmt **Handlers = RawHandlers.get();
+ Stmt **Handlers = RawHandlers.data();
SmallVector<TypeWithHandler, 8> TypesWithHandlers;
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
new file mode 100644
index 000000000000..7c2c766e4615
--- /dev/null
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -0,0 +1,661 @@
+//===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for inline asm statements.
+//
+//===----------------------------------------------------------------------===//
+
+#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 "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/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"
+using namespace clang;
+using namespace sema;
+
+/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
+/// ignore "noop" casts in places where an lvalue is required by an inline asm.
+/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
+/// provide a strong guidance to not use it.
+///
+/// This method checks to see if the argument is an acceptable l-value and
+/// returns false if it is a case we can handle.
+static bool CheckAsmLValue(const Expr *E, Sema &S) {
+ // Type dependent expressions will be checked during instantiation.
+ if (E->isTypeDependent())
+ return false;
+
+ if (E->isLValue())
+ return false; // Cool, this is an lvalue.
+
+ // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
+ // are supposed to allow.
+ const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
+ if (E != E2 && E2->isLValue()) {
+ if (!S.getLangOpts().HeinousExtensions)
+ S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ else
+ S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ // Accept, even if we emitted an error diagnostic.
+ return false;
+ }
+
+ // None of the above, just randomly invalid non-lvalue.
+ return true;
+}
+
+/// isOperandMentioned - Return true if the specified operand # is mentioned
+/// anywhere in the decomposed asm string.
+static bool isOperandMentioned(unsigned OpNo,
+ ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
+ for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
+ const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == OpNo)
+ return true;
+ }
+ return false;
+}
+
+StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+ bool IsVolatile, unsigned NumOutputs,
+ unsigned NumInputs, IdentifierInfo **Names,
+ MultiExprArg constraints, MultiExprArg exprs,
+ Expr *asmString, MultiExprArg clobbers,
+ SourceLocation RParenLoc) {
+ unsigned NumClobbers = clobbers.size();
+ StringLiteral **Constraints =
+ reinterpret_cast<StringLiteral**>(constraints.data());
+ Expr **Exprs = exprs.data();
+ StringLiteral *AsmString = cast<StringLiteral>(asmString);
+ StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data());
+
+ SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+
+ // The parser verifies that there is a string literal here.
+ if (!AsmString->isAscii())
+ return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
+ << AsmString->getSourceRange());
+
+ for (unsigned i = 0; i != NumOutputs; i++) {
+ StringLiteral *Literal = Constraints[i];
+ if (!Literal->isAscii())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ StringRef OutputName;
+ if (Names[i])
+ OutputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
+ if (!Context.getTargetInfo().validateOutputConstraint(Info))
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_invalid_output_constraint)
+ << Info.getConstraintStr());
+
+ // Check that the output exprs are valid lvalues.
+ Expr *OutputExpr = Exprs[i];
+ if (CheckAsmLValue(OutputExpr, *this)) {
+ return StmtError(Diag(OutputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_output)
+ << OutputExpr->getSourceRange());
+ }
+
+ OutputConstraintInfos.push_back(Info);
+ }
+
+ SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+
+ for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
+ StringLiteral *Literal = Constraints[i];
+ if (!Literal->isAscii())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ StringRef InputName;
+ if (Names[i])
+ InputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
+ if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
+ NumOutputs, Info)) {
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_invalid_input_constraint)
+ << Info.getConstraintStr());
+ }
+
+ Expr *InputExpr = Exprs[i];
+
+ // Only allow void types for memory constraints.
+ if (Info.allowsMemory() && !Info.allowsRegister()) {
+ if (CheckAsmLValue(InputExpr, *this))
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_input)
+ << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
+
+ if (Info.allowsRegister()) {
+ if (InputExpr->getType()->isVoidType()) {
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_type_in_input)
+ << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
+ }
+
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
+ if (Result.isInvalid())
+ return StmtError();
+
+ Exprs[i] = Result.take();
+ InputConstraintInfos.push_back(Info);
+ }
+
+ // Check that the clobbers are valid.
+ for (unsigned i = 0; i != NumClobbers; i++) {
+ StringLiteral *Literal = Clobbers[i];
+ if (!Literal->isAscii())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ StringRef Clobber = Literal->getString();
+
+ if (!Context.getTargetInfo().isValidClobber(Clobber))
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_unknown_register_name) << Clobber);
+ }
+
+ GCCAsmStmt *NS =
+ new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs, AsmString,
+ NumClobbers, Clobbers, RParenLoc);
+ // Validate the asm string, ensuring it makes sense given the operands we
+ // have.
+ SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
+ unsigned DiagOffs;
+ if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
+ Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
+ << AsmString->getSourceRange();
+ return StmtError();
+ }
+
+ // Validate constraints and modifiers.
+ for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
+ GCCAsmStmt::AsmStringPiece &Piece = Pieces[i];
+ if (!Piece.isOperand()) continue;
+
+ // Look for the correct constraint index.
+ unsigned Idx = 0;
+ unsigned ConstraintIdx = 0;
+ for (unsigned i = 0, e = NS->getNumOutputs(); i != e; ++i, ++ConstraintIdx) {
+ TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+
+ if (Info.isReadWrite()) {
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+ }
+ }
+
+ for (unsigned i = 0, e = NS->getNumInputs(); i != e; ++i, ++ConstraintIdx) {
+ TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+
+ if (Info.isReadWrite()) {
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+ }
+ }
+
+ // Now that we have the right indexes go ahead and check.
+ StringLiteral *Literal = Constraints[ConstraintIdx];
+ const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr();
+ if (Ty->isDependentType() || Ty->isIncompleteType())
+ continue;
+
+ unsigned Size = Context.getTypeSize(Ty);
+ if (!Context.getTargetInfo()
+ .validateConstraintModifier(Literal->getString(), Piece.getModifier(),
+ Size))
+ Diag(Exprs[ConstraintIdx]->getLocStart(),
+ diag::warn_asm_mismatched_size_modifier);
+ }
+
+ // Validate tied input operands for type mismatches.
+ for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
+ TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+
+ // If this is a tied constraint, verify that the output and input have
+ // either exactly the same type, or that they are int/ptr operands with the
+ // same size (int/long, int*/long, are ok etc).
+ if (!Info.hasTiedOperand()) continue;
+
+ unsigned TiedTo = Info.getTiedOperand();
+ unsigned InputOpNo = i+NumOutputs;
+ Expr *OutputExpr = Exprs[TiedTo];
+ Expr *InputExpr = Exprs[InputOpNo];
+
+ if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
+ continue;
+
+ QualType InTy = InputExpr->getType();
+ QualType OutTy = OutputExpr->getType();
+ if (Context.hasSameType(InTy, OutTy))
+ continue; // All types can be tied to themselves.
+
+ // Decide if the input and output are in the same domain (integer/ptr or
+ // floating point.
+ enum AsmDomain {
+ AD_Int, AD_FP, AD_Other
+ } InputDomain, OutputDomain;
+
+ if (InTy->isIntegerType() || InTy->isPointerType())
+ InputDomain = AD_Int;
+ else if (InTy->isRealFloatingType())
+ InputDomain = AD_FP;
+ else
+ InputDomain = AD_Other;
+
+ if (OutTy->isIntegerType() || OutTy->isPointerType())
+ OutputDomain = AD_Int;
+ else if (OutTy->isRealFloatingType())
+ OutputDomain = AD_FP;
+ else
+ OutputDomain = AD_Other;
+
+ // They are ok if they are the same size and in the same domain. This
+ // allows tying things like:
+ // void* to int*
+ // void* to int if they are the same size.
+ // double to long double if they are the same size.
+ //
+ uint64_t OutSize = Context.getTypeSize(OutTy);
+ uint64_t InSize = Context.getTypeSize(InTy);
+ if (OutSize == InSize && InputDomain == OutputDomain &&
+ InputDomain != AD_Other)
+ continue;
+
+ // If the smaller input/output operand is not mentioned in the asm string,
+ // then we can promote the smaller one to a larger input and the asm string
+ // won't notice.
+ bool SmallerValueMentioned = false;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (isOperandMentioned(InputOpNo, Pieces)) {
+ // This is a use in the asm string of the smaller operand. Since we
+ // codegen this by promoting to a wider value, the asm will get printed
+ // "wrong".
+ SmallerValueMentioned |= InSize < OutSize;
+ }
+ if (isOperandMentioned(TiedTo, Pieces)) {
+ // If this is a reference to the output, and if the output is the larger
+ // value, then it's ok because we'll promote the input to the larger type.
+ SmallerValueMentioned |= OutSize < InSize;
+ }
+
+ // If the smaller value wasn't mentioned in the asm string, and if the
+ // output was a register, just extend the shorter one to the size of the
+ // larger one.
+ if (!SmallerValueMentioned && InputDomain != AD_Other &&
+ OutputConstraintInfos[TiedTo].allowsRegister())
+ continue;
+
+ // Either both of the operands were mentioned or the smaller one was
+ // mentioned. One more special case that we'll allow: if the tied input is
+ // integer, unmentioned, and is a constant, then we'll allow truncating it
+ // down to the size of the destination.
+ if (InputDomain == AD_Int && OutputDomain == AD_Int &&
+ !isOperandMentioned(InputOpNo, Pieces) &&
+ InputExpr->isEvaluatable(Context)) {
+ CastKind castKind =
+ (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
+ InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
+ Exprs[InputOpNo] = InputExpr;
+ NS->setInputExpr(i, InputExpr);
+ continue;
+ }
+
+ Diag(InputExpr->getLocStart(),
+ diag::err_asm_tying_incompatible_types)
+ << InTy << OutTy << OutputExpr->getSourceRange()
+ << InputExpr->getSourceRange();
+ return StmtError();
+ }
+
+ return Owned(NS);
+}
+
+// getSpelling - Get the spelling of the AsmTok token.
+static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
+ StringRef Asm;
+ SmallString<512> TokenBuf;
+ TokenBuf.resize(512);
+ bool StringInvalid = false;
+ Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
+ assert (!StringInvalid && "Expected valid string!");
+ return Asm;
+}
+
+// Build the inline assembly string. Returns true on error.
+static bool buildMSAsmString(Sema &SemaRef,
+ SourceLocation AsmLoc,
+ ArrayRef<Token> AsmToks,
+ llvm::SmallVectorImpl<unsigned> &TokOffsets,
+ std::string &AsmString) {
+ assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+ SmallString<512> Asm;
+ for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+ bool isNewAsm = ((i == 0) ||
+ AsmToks[i].isAtStartOfLine() ||
+ AsmToks[i].is(tok::kw_asm));
+ if (isNewAsm) {
+ if (i != 0)
+ Asm += "\n\t";
+
+ if (AsmToks[i].is(tok::kw_asm)) {
+ i++; // Skip __asm
+ if (i == e) {
+ SemaRef.Diag(AsmLoc, diag::err_asm_empty);
+ return true;
+ }
+
+ }
+ }
+
+ if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
+ Asm += ' ';
+
+ StringRef Spelling = getSpelling(SemaRef, AsmToks[i]);
+ Asm += Spelling;
+ TokOffsets.push_back(Asm.size());
+ }
+ AsmString = Asm.str();
+ return false;
+}
+
+namespace {
+
+class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback {
+ Sema &SemaRef;
+ SourceLocation AsmLoc;
+ ArrayRef<Token> AsmToks;
+ ArrayRef<unsigned> TokOffsets;
+
+public:
+ MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc,
+ ArrayRef<Token> Toks,
+ ArrayRef<unsigned> Offsets)
+ : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { }
+ ~MCAsmParserSemaCallbackImpl() {}
+
+ void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, unsigned &Size){
+ SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc);
+ NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Size);
+ return static_cast<void *>(OpDecl);
+ }
+
+ bool LookupInlineAsmField(StringRef Base, StringRef Member,
+ unsigned &Offset) {
+ return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc);
+ }
+
+ static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D,
+ void *Context) {
+ ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D);
+ }
+ void MSAsmDiagHandler(const llvm::SMDiagnostic &D) {
+ // Compute an offset into the inline asm buffer.
+ // FIXME: This isn't right if .macro is involved (but hopefully, no
+ // real-world code does that).
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+ const llvm::MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+ unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+
+ // Figure out which token that offset points into.
+ const unsigned *OffsetPtr =
+ std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset);
+ unsigned TokIndex = OffsetPtr - TokOffsets.begin();
+
+ // If we come up with an answer which seems sane, use it; otherwise,
+ // just point at the __asm keyword.
+ // FIXME: Assert the answer is sane once we handle .macro correctly.
+ SourceLocation Loc = AsmLoc;
+ if (TokIndex < AsmToks.size()) {
+ const Token *Tok = &AsmToks[TokIndex];
+ Loc = Tok->getLocation();
+ Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength()));
+ }
+ SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+ }
+};
+
+}
+
+NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
+ unsigned &Size) {
+ Size = 0;
+ LookupResult Result(*this, &Context.Idents.get(Name), Loc,
+ Sema::LookupOrdinaryName);
+
+ if (!LookupName(Result, getCurScope())) {
+ // If we don't find anything, return null; the AsmParser will assume
+ // it is a label of some sort.
+ return 0;
+ }
+
+ if (!Result.isSingleResult()) {
+ // FIXME: Diagnose result.
+ 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;
+ }
+
+ // FIXME: Handle other kinds of results? (FieldDecl, etc.)
+ // FIXME: Diagnose if we find something we can't handle, like a typedef.
+ return 0;
+}
+
+bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
+ unsigned &Offset, SourceLocation AsmLoc) {
+ Offset = 0;
+ LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
+ LookupOrdinaryName);
+
+ if (!LookupName(BaseResult, getCurScope()))
+ return true;
+
+ if (!BaseResult.isSingleResult())
+ return true;
+
+ NamedDecl *FoundDecl = BaseResult.getFoundDecl();
+ const RecordType *RT = 0;
+ if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) {
+ RT = VD->getType()->getAs<RecordType>();
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl)) {
+ RT = TD->getUnderlyingType()->getAs<RecordType>();
+ }
+ if (!RT)
+ return true;
+
+ if (RequireCompleteType(AsmLoc, QualType(RT, 0), 0))
+ return true;
+
+ LookupResult FieldResult(*this, &Context.Idents.get(Member), SourceLocation(),
+ LookupMemberName);
+
+ if (!LookupQualifiedName(FieldResult, RT->getDecl()))
+ return true;
+
+ // FIXME: Handle IndirectFieldDecl?
+ FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
+ if (!FD)
+ return true;
+
+ const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl());
+ unsigned i = FD->getFieldIndex();
+ CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i));
+ Offset = (unsigned)Result.getQuantity();
+
+ return false;
+}
+
+StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
+ ArrayRef<Token> AsmToks,SourceLocation EndLoc) {
+ SmallVector<IdentifierInfo*, 4> Names;
+ SmallVector<StringRef, 4> ConstraintRefs;
+ SmallVector<Expr*, 4> Exprs;
+ SmallVector<StringRef, 4> ClobberRefs;
+
+ // Empty asm statements don't need to instantiate the AsmParser, etc.
+ if (AsmToks.empty()) {
+ StringRef EmptyAsmStr;
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
+ /*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0,
+ /*NumInputs*/ 0, Names, ConstraintRefs, Exprs,
+ EmptyAsmStr, ClobberRefs, EndLoc);
+ return Owned(NS);
+ }
+
+ std::string AsmString;
+ llvm::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 llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
+
+ OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
+ OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+ OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+ OwningPtr<llvm::MCSubtargetInfo>
+ STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+ llvm::SourceMgr SrcMgr;
+ llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+ llvm::MemoryBuffer *Buffer =
+ llvm::MemoryBuffer::getMemBuffer(AsmString, "<inline asm>");
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+
+ OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
+ OwningPtr<llvm::MCAsmParser>
+ Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
+ OwningPtr<llvm::MCTargetAsmParser>
+ TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
+
+ // Get the instruction descriptor.
+ const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
+ llvm::MCInstPrinter *IP =
+ TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
+
+ // Change to the Intel dialect.
+ Parser->setAssemblerDialect(1);
+ Parser->setTargetParser(*TargetParser.get());
+ Parser->setParsingInlineAsm(true);
+ TargetParser->setParsingInlineAsm(true);
+
+ MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets);
+ TargetParser->setSemaCallback(&MCAPSI);
+ SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback,
+ &MCAPSI);
+
+ unsigned NumOutputs;
+ unsigned NumInputs;
+ std::string AsmStringIR;
+ SmallVector<std::pair<void *, bool>, 4> OpDecls;
+ SmallVector<std::string, 4> Constraints;
+ SmallVector<std::string, 4> Clobbers;
+ if (Parser->ParseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
+ NumOutputs, NumInputs, OpDecls, Constraints,
+ Clobbers, MII, IP, MCAPSI))
+ return StmtError();
+
+ // Build the vector of clobber StringRefs.
+ unsigned NumClobbers = Clobbers.size();
+ ClobberRefs.resize(NumClobbers);
+ for (unsigned i = 0; i != NumClobbers; ++i)
+ ClobberRefs[i] = StringRef(Clobbers[i]);
+
+ // Recast the void pointers and build the vector of constraint StringRefs.
+ unsigned NumExprs = NumOutputs + NumInputs;
+ Names.resize(NumExprs);
+ ConstraintRefs.resize(NumExprs);
+ Exprs.resize(NumExprs);
+ for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+ NamedDecl *OpDecl = static_cast<NamedDecl *>(OpDecls[i].first);
+ if (!OpDecl)
+ return StmtError();
+
+ DeclarationNameInfo NameInfo(OpDecl->getDeclName(), AsmLoc);
+ ExprResult OpExpr = BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo,
+ OpDecl);
+ if (OpExpr.isInvalid())
+ return StmtError();
+
+ // Need offset of variable.
+ if (OpDecls[i].second)
+ OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf,
+ OpExpr.take());
+
+ Names[i] = OpDecl->getIdentifier();
+ ConstraintRefs[i] = StringRef(Constraints[i]);
+ Exprs[i] = OpExpr.take();
+ }
+
+ bool IsSimple = NumExprs > 0;
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
+ /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
+ Names, ConstraintRefs, Exprs, AsmStringIR,
+ ClobberRefs, EndLoc);
+ return Owned(NS);
+}
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 3c15b7a8afad..b268b4502c4f 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -48,11 +48,16 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
switch (A.getKind()) {
+ case AttributeList::UnknownAttribute:
+ S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
+ diag::warn_unhandled_ms_attribute_ignored :
+ diag::warn_unknown_attribute_ignored) << A.getName();
+ return 0;
case AttributeList::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
default:
- // if we're here, then we parsed an attribute, but didn't recognize it as a
- // statement attribute => it is declaration attribute
+ // 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();
return 0;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 4dbf3e45b387..f56b05406d07 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -333,7 +333,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
<< Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_no_template_suggest)
<< Name << CorrectedQuotedStr
@@ -1104,6 +1105,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
+ if (PrevClassTemplate)
+ mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
+
AddPushedVisibilityAttribute(NewClass);
if (TUK != TUK_Friend)
@@ -1138,8 +1142,6 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
NewTemplate->setInvalidDecl();
NewClass->setInvalidDecl();
}
- if (PrevClassTemplate)
- mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
ActOnDocumentableDecl(NewTemplate);
@@ -1204,11 +1206,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
/// of a template template parameter, recursively.
static bool DiagnoseUnexpandedParameterPacks(Sema &S,
TemplateTemplateParmDecl *TTP) {
+ // A template template parameter which is a parameter pack is also a pack
+ // expansion.
+ if (TTP->isParameterPack())
+ return false;
+
TemplateParameterList *Params = TTP->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
NamedDecl *P = Params->getParam(I);
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
- if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
+ if (!NTTP->isParameterPack() &&
+ S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
NTTP->getTypeSourceInfo(),
Sema::UPPC_NonTypeTemplateParameterType))
return true;
@@ -1321,7 +1329,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
// Check for unexpanded parameter packs.
- if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
+ if (!NewNonTypeParm->isParameterPack() &&
+ DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
NewNonTypeParm->getTypeSourceInfo(),
UPPC_NonTypeTemplateParameterType)) {
Invalid = true;
@@ -1342,7 +1351,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (NewNonTypeParm->isParameterPack()) {
assert(!NewNonTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
- SawParameterPack = true;
+ if (!NewNonTypeParm->isPackExpansion())
+ SawParameterPack = true;
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
@@ -1389,7 +1399,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (NewTemplateParm->isParameterPack()) {
assert(!NewTemplateParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
- SawParameterPack = true;
+ if (!NewTemplateParm->isPackExpansion())
+ SawParameterPack = true;
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
@@ -1416,10 +1427,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
MissingDefaultArg = true;
}
- // C++0x [temp.param]p11:
+ // C++11 [temp.param]p11:
// If a template parameter of a primary class template or alias template
// is a template parameter pack, it shall be the last template parameter.
- if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
+ if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
(TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
Diag((*NewParam)->getLocation(),
diag::err_template_param_pack_must_be_last_template_parameter);
@@ -1998,9 +2009,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
for (unsigned I = 0; I < Depth; ++I)
TemplateArgLists.addOuterTemplateArguments(0, 0);
+ LocalInstantiationScope Scope(*this);
InstantiatingTemplate Inst(*this, TemplateLoc, Template);
if (Inst)
return QualType();
+
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
@@ -2085,7 +2098,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Converted.data(),
Converted.size(), 0);
ClassTemplate->AddSpecialization(Decl, InsertPos);
- Decl->setLexicalDeclContext(CurContext);
+ if (ClassTemplate->isOutOfLine())
+ Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
}
CanonType = Context.getTypeDeclType(Decl);
@@ -2137,7 +2151,6 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
}
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
- TemplateArgsIn.release();
if (Result.isNull())
return true;
@@ -2831,6 +2844,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
Converted.push_back(Arg.getArgument());
@@ -2947,7 +2961,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (CheckTemplateArgument(TempParm, Arg))
+ if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex))
return true;
Converted.push_back(Arg.getArgument());
@@ -2965,6 +2979,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
llvm_unreachable("Declaration argument with template template parameter");
case TemplateArgument::Integral:
llvm_unreachable("Integral argument with template template parameter");
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Null pointer argument with template template parameter");
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
@@ -2996,6 +3012,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
return true;
}
+/// \brief Check whether the template parameter is a pack expansion, and if so,
+/// determine the number of parameters produced by that expansion. For instance:
+///
+/// \code
+/// template<typename ...Ts> struct A {
+/// template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B;
+/// };
+/// \endcode
+///
+/// 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) {
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (NTTP->isExpandedParameterPack())
+ return NTTP->getNumExpansionTypes();
+ }
+
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ if (TTP->isExpandedParameterPack())
+ return TTP->getNumExpansionTemplateParameters();
+ }
+
+ return llvm::Optional<unsigned>();
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -3008,15 +3051,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
*ExpansionIntoFixedList = false;
TemplateParameterList *Params = Template->getTemplateParameters();
- unsigned NumParams = Params->size();
- unsigned NumArgs = TemplateArgs.size();
- bool Invalid = false;
SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
- bool HasParameterPack =
- NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-
// C++ [temp.arg]p1:
// [...] The type and form of each template-argument specified in
// a template-id shall match the type and form specified for the
@@ -3024,38 +3061,50 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
SmallVector<TemplateArgument, 2> ArgumentPack;
- TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- unsigned ArgIdx = 0;
+ unsigned ArgIdx = 0, NumArgs = TemplateArgs.size();
LocalInstantiationScope InstScope(*this, true);
- bool SawPackExpansion = false;
- while (Param != ParamEnd) {
- if (ArgIdx < NumArgs) {
- // If we have an expanded parameter pack, make sure we don't have too
- // many arguments.
- // FIXME: This really should fall out from the normal arity checking.
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (NTTP->isExpandedParameterPack() &&
- ArgumentPack.size() >= NTTP->getNumExpansionTypes()) {
- Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
- << true
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
- << Template;
- Diag(Template->getLocation(), diag::note_template_decl_here)
- << Params->getSourceRange();
- return true;
- }
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ 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 (*Expansions == ArgumentPack.size()) {
+ // We're done with this parameter pack. Pack up its arguments and add
+ // them to the list.
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+
+ // This argument is assigned to the next parameter.
+ ++Param;
+ continue;
+ } else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
+ // Not enough arguments for this parameter pack.
+ Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+ << false
+ << (isa<ClassTemplateDecl>(Template)? 0 :
+ isa<FunctionTemplateDecl>(Template)? 1 :
+ isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << Template;
+ Diag(Template->getLocation(), diag::note_template_decl_here)
+ << Params->getSourceRange();
+ return true;
}
+ }
+ if (ArgIdx < NumArgs) {
// Check the template argument we were given.
if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
TemplateLoc, RAngleLoc,
ArgumentPack.size(), Converted))
return true;
+ // We're now done with this argument.
+ ++ArgIdx;
+
if ((*Param)->isTemplateParameterPack()) {
// The template parameter was a template parameter pack, so take the
// deduced argument and place it on the argument pack. Note that we
@@ -3067,16 +3116,47 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Move to the next template parameter.
++Param;
}
-
- // If this template argument is a pack expansion, record that fact
- // and break out; we can't actually check any more.
- if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
- SawPackExpansion = true;
- ++ArgIdx;
- break;
+
+ // If we just saw a pack expansion, then directly convert the remaining
+ // arguments, because we don't know what parameters they'll match up
+ // with.
+ if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) {
+ bool InFinalParameterPack = Param != ParamEnd &&
+ Param + 1 == ParamEnd &&
+ (*Param)->isTemplateParameterPack() &&
+ !getExpandedPackSize(*Param);
+
+ if (!InFinalParameterPack && !ArgumentPack.empty()) {
+ // If we were part way through filling in an expanded parameter pack,
+ // fall back to just producing individual arguments.
+ Converted.insert(Converted.end(),
+ ArgumentPack.begin(), ArgumentPack.end());
+ ArgumentPack.clear();
+ }
+
+ while (ArgIdx < NumArgs) {
+ if (InFinalParameterPack)
+ ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
+ else
+ Converted.push_back(TemplateArgs[ArgIdx].getArgument());
+ ++ArgIdx;
+ }
+
+ // Push the argument pack onto the list of converted arguments.
+ if (InFinalParameterPack) {
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+ } else if (ExpansionIntoFixedList) {
+ // We have expanded a pack into a fixed list.
+ *ExpansionIntoFixedList = true;
+ }
+
+ return false;
}
-
- ++ArgIdx;
+
continue;
}
@@ -3087,14 +3167,30 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgumentPack.data(),
ArgumentPack.size()));
- return Invalid;
+ return false;
}
// If we have a template parameter pack with no more corresponding
// arguments, just break out now and we'll fill in the argument pack below.
- if ((*Param)->isTemplateParameterPack())
- break;
-
+ if ((*Param)->isTemplateParameterPack()) {
+ assert(!getExpandedPackSize(*Param) &&
+ "Should have dealt with this already");
+
+ // A non-expanded parameter pack before the end of the parameter list
+ // only occurs for an ill-formed template parameter list, unless we've
+ // got a partial argument list for a function template, so just bail out.
+ if (Param + 1 != ParamEnd)
+ return true;
+
+ Converted.push_back(TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+
+ ++Param;
+ continue;
+ }
+
// Check whether we have a default argument.
TemplateArgumentLoc Arg;
@@ -3181,86 +3277,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
++ArgIdx;
}
- // If we saw a pack expansion, then directly convert the remaining arguments,
- // because we don't know what parameters they'll match up with.
- if (SawPackExpansion) {
- bool AddToArgumentPack
- = Param != ParamEnd && (*Param)->isTemplateParameterPack();
- while (ArgIdx < NumArgs) {
- if (AddToArgumentPack)
- ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
- else
- Converted.push_back(TemplateArgs[ArgIdx].getArgument());
- ++ArgIdx;
- }
-
- // Push the argument pack onto the list of converted arguments.
- if (AddToArgumentPack) {
- if (ArgumentPack.empty())
- Converted.push_back(TemplateArgument(0, 0));
- else {
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
- ArgumentPack.clear();
- }
- } else if (ExpansionIntoFixedList) {
- // We have expanded a pack into a fixed list.
- *ExpansionIntoFixedList = true;
- }
-
- return Invalid;
- }
-
// If we have any leftover arguments, then there were too many arguments.
// Complain and fail.
if (ArgIdx < NumArgs)
return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
-
- // If we have an expanded parameter pack, make sure we don't have too
- // many arguments.
- // FIXME: This really should fall out from the normal arity checking.
- if (Param != ParamEnd) {
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (NTTP->isExpandedParameterPack() &&
- ArgumentPack.size() < NTTP->getNumExpansionTypes()) {
- Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
- << false
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
- << Template;
- Diag(Template->getLocation(), diag::note_template_decl_here)
- << Params->getSourceRange();
- return true;
- }
- }
- }
-
- // Form argument packs for each of the parameter packs remaining.
- while (Param != ParamEnd) {
- // If we're checking a partial list of template arguments, don't fill
- // in arguments for non-template parameter packs.
- if ((*Param)->isTemplateParameterPack()) {
- if (!HasParameterPack)
- return true;
- if (ArgumentPack.empty())
- Converted.push_back(TemplateArgument(0, 0));
- else {
- Converted.push_back(TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
- ArgumentPack.clear();
- }
- } else if (!PartialTemplateArgs)
- return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
-
- ++Param;
- }
- return Invalid;
+ return false;
}
namespace {
@@ -3650,7 +3672,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument((Decl *)0);
+ Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
return false;
case NPV_Error:
@@ -3738,7 +3760,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
- NamedDecl *Entity = DRE->getDecl();
+ ValueDecl *Entity = DRE->getDecl();
// Cannot refer to non-static data members
if (FieldDecl *Field = dyn_cast<FieldDecl>(Entity)) {
@@ -3926,7 +3948,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
// Create the template argument.
- Converted = TemplateArgument(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
+ ParamType->isReferenceType());
S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
return false;
}
@@ -3947,7 +3970,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
return true;
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument((Decl *)0);
+ Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
return false;
case NPV_NotNullPointer:
break;
@@ -4016,10 +4039,12 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
if (isa<NonTypeTemplateParmDecl>(VD) ||
(isa<VarDecl>(VD) &&
S.Context.getCanonicalType(VD->getType()).isConstQualified())) {
- if (Arg->isTypeDependent() || Arg->isValueDependent())
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
- else
- Converted = TemplateArgument(VD->getCanonicalDecl());
+ } else {
+ VD = cast<ValueDecl>(VD->getCanonicalDecl());
+ Converted = TemplateArgument(VD, /*isReferenceParam*/false);
+ }
return Invalid;
}
}
@@ -4040,10 +4065,12 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
- if (Arg->isTypeDependent() || Arg->isValueDependent())
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
- else
- Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl());
+ } else {
+ ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
+ Converted = TemplateArgument(D, /*isReferenceParam*/false);
+ }
return Invalid;
}
@@ -4396,8 +4423,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument((Decl *)0);
- return Owned(Arg);;
+ Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
+ return Owned(Arg);
}
}
@@ -4417,8 +4444,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
- const TemplateArgumentLoc &Arg) {
- TemplateName Name = Arg.getArgument().getAsTemplate();
+ const TemplateArgumentLoc &Arg,
+ unsigned ArgumentPackIndex) {
+ TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template) {
// Any dependent template name is fine.
@@ -4448,8 +4476,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
<< Template;
}
+ TemplateParameterList *Params = Param->getTemplateParameters();
+ if (Param->isExpandedParameterPack())
+ Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
+
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
- Param->getTemplateParameters(),
+ Params,
true,
TPL_TemplateTemplateArgumentMatch,
Arg.getLocation());
@@ -4463,12 +4495,9 @@ ExprResult
Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ParamType,
SourceLocation Loc) {
- assert(Arg.getKind() == TemplateArgument::Declaration &&
- "Only declaration template arguments permitted here");
-
// For a NULL non-type template argument, return nullptr casted to the
// parameter's type.
- if (!Arg.getAsDecl()) {
+ if (Arg.getKind() == TemplateArgument::NullPtr) {
return ImpCastExprToType(
new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc),
ParamType,
@@ -4476,7 +4505,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
? CK_NullToMemberPointer
: CK_NullToPointer);
}
-
+ assert(Arg.getKind() == TemplateArgument::Declaration &&
+ "Only declaration template arguments permitted here");
+
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
if (VD->getDeclContext()->isRecord() &&
@@ -4524,7 +4555,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
assert(!RefExpr.isInvalid() &&
Context.hasSameType(((Expr*) RefExpr.get())->getType(),
ParamType.getUnqualifiedType()));
- return move(RefExpr);
+ return RefExpr;
}
}
@@ -4542,7 +4573,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
if (RefExpr.isInvalid())
return ExprError();
- return move(RefExpr);
+ return RefExpr;
}
// Take the address of everything else
@@ -5071,10 +5102,10 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
continue;
}
- Expr *ArgExpr = Args[I].getAsExpr();
- if (!ArgExpr) {
+ if (Args[I].getKind() != TemplateArgument::Expression)
continue;
- }
+
+ Expr *ArgExpr = Args[I].getAsExpr();
// We can have a pack expansion of any of the bullets below.
if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr))
@@ -5173,7 +5204,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
- ? TemplateParameterLists.get()[0]->getTemplateLoc() : SourceLocation();
+ ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation();
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
@@ -5199,7 +5230,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
TemplateNameLoc,
SS,
- (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.data(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
isExplicitSpecialization,
@@ -5354,7 +5385,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size(),
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
PrevDecl = 0;
CanonType = Context.getTypeDeclType(Specialization);
@@ -5382,7 +5413,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateParams,
AS_none, /*ModulePrivateLoc=*/SourceLocation(),
TemplateParameterLists.size() - 1,
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
// Create a new class template partial specialization declaration node.
@@ -5406,7 +5437,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size() - 1,
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
if (!PrevPartial)
@@ -5461,7 +5492,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size(),
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
if (!PrevDecl)
@@ -5544,7 +5575,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Specialization->setTypeAsWritten(WrittenTy);
Specialization->setTemplateKeywordLoc(TemplateKWLoc);
}
- TemplateArgsIn.release();
// C++ [temp.expl.spec]p9:
// A template explicit specialization is in the scope of the
@@ -5579,7 +5609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Decl *Sema::ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
- Decl *NewDecl = HandleDeclarator(S, D, move(TemplateParameterLists));
+ Decl *NewDecl = HandleDeclarator(S, D, TemplateParameterLists);
ActOnDocumentableDecl(NewDecl);
return NewDecl;
}
@@ -5598,7 +5628,7 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists));
+ TemplateParameterLists);
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast_or_null<FunctionTemplateDecl>(DP))
return ActOnStartOfFunctionDef(FnBodyScope,
@@ -5902,7 +5932,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Perform template argument deduction to determine whether we may be
// specializing this template.
// FIXME: It is somewhat wasteful to build
- TemplateDeductionInfo Info(Context, FD->getLocation());
+ TemplateDeductionInfo Info(FD->getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
@@ -6399,7 +6429,6 @@ Sema::ActOnExplicitInstantiation(Scope *S,
TemplateArgs,
Context.getTypeDeclType(Specialization));
Specialization->setTypeAsWritten(WrittenTy);
- TemplateArgsIn.release();
// Set source locations for keywords.
Specialization->setExternLoc(ExternLoc);
@@ -6475,9 +6504,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
KWLoc, SS, Name, NameLoc, Attr, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
- MultiTemplateParamsArg(*this, 0, 0),
- Owned, IsDependent, SourceLocation(), false,
- TypeResult());
+ MultiTemplateParamsArg(), Owned, IsDependent,
+ SourceLocation(), false, TypeResult());
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -6729,12 +6757,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
HasExplicitTemplateArgs = true;
- TemplateArgsPtr.release();
}
// C++ [temp.explicit]p1:
@@ -6762,7 +6788,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!FunTmpl)
continue;
- TemplateDeductionInfo Info(Context, D.getIdentifierLoc());
+ TemplateDeductionInfo Info(D.getIdentifierLoc());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl,
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 9500ec3219d4..bf4533d6998c 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -158,9 +158,6 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
/// \brief Determine whether two declaration pointers refer to the same
/// declaration.
static bool isSameDeclaration(Decl *X, Decl *Y) {
- if (!X || !Y)
- return !X && !Y;
-
if (NamedDecl *NX = dyn_cast<NamedDecl>(X))
X = NX->getUnderlyingDecl();
if (NamedDecl *NY = dyn_cast<NamedDecl>(Y))
@@ -262,7 +259,27 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced two declarations, make sure they they refer to the
// same declaration.
if (Y.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(X.getAsDecl(), Y.getAsDecl()))
+ isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) &&
+ X.isDeclForReferenceParam() == Y.isDeclForReferenceParam())
+ return X;
+
+ // All other combinations are incompatible.
+ return DeducedTemplateArgument();
+
+ case TemplateArgument::NullPtr:
+ // If we deduced a null pointer and a dependent expression, keep the
+ // null pointer.
+ if (Y.getKind() == TemplateArgument::Expression)
+ return X;
+
+ // If we deduced a null pointer and an integral constant, keep the
+ // integral constant.
+ if (Y.getKind() == TemplateArgument::Integral)
+ return Y;
+
+ // If we deduced two null pointers, make sure they have the same type.
+ if (Y.getKind() == TemplateArgument::NullPtr &&
+ Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType()))
return X;
// All other combinations are incompatible.
@@ -356,13 +373,15 @@ DeduceNonTypeTemplateArgument(Sema &S,
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
- Decl *D,
+ ValueDecl *D,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
- DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0);
+ D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : 0;
+ TemplateArgument New(D, NTTP->getType()->isReferenceType());
+ DeducedTemplateArgument NewDeduced(New);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
@@ -570,7 +589,10 @@ static void PrepareArgumentPackDeduction(Sema &S,
SavedPacks[I] = Deduced[PackIndices[I]];
Deduced[PackIndices[I]] = TemplateArgument();
- // If the template arugment pack was explicitly specified, add that to
+ if (!S.CurrentInstantiationScope)
+ continue;
+
+ // If the template argument pack was explicitly specified, add that to
// the set of deduced arguments.
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
@@ -612,7 +634,7 @@ FinishArgumentPackDeduction(Sema &S,
if (NewlyDeducedPacks[I].empty()) {
// If we deduced an empty argument pack, create it now.
- NewPack = DeducedTemplateArgument(TemplateArgument(0, 0));
+ NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
} else {
TemplateArgument *ArgumentPack
= new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
@@ -1371,9 +1393,11 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// If this is a base class, try to perform template argument
// deduction from it.
if (NextT != RecordT) {
+ TemplateDeductionInfo BaseInfo(Info.getLocation());
Sema::TemplateDeductionResult BaseResult
= DeduceTemplateArguments(S, TemplateParams, SpecParam,
- QualType(NextT, 0), Info, Deduced);
+ QualType(NextT, 0), BaseInfo,
+ Deduced);
// If template argument deduction for this base was successful,
// note that we had some success. Otherwise, ignore any deductions
@@ -1382,6 +1406,9 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
Successful = true;
DeducedOrig.clear();
DeducedOrig.append(Deduced.begin(), Deduced.end());
+ Info.Param = BaseInfo.Param;
+ Info.FirstArg = BaseInfo.FirstArg;
+ Info.SecondArg = BaseInfo.SecondArg;
}
else
Deduced = DeducedOrig;
@@ -1596,7 +1623,17 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Declaration:
if (Arg.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
+ isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()) &&
+ Param.isDeclForReferenceParam() == Arg.isDeclForReferenceParam())
+ return Sema::TDK_Success;
+
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+
+ case TemplateArgument::NullPtr:
+ if (Arg.getKind() == TemplateArgument::NullPtr &&
+ S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -1867,7 +1904,11 @@ static bool isSameTemplateArg(ASTContext &Context,
Context.getCanonicalType(Y.getAsType());
case TemplateArgument::Declaration:
- return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
+ return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) &&
+ X.isDeclForReferenceParam() == Y.isDeclForReferenceParam();
+
+ case TemplateArgument::NullPtr:
+ return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType());
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
@@ -1937,6 +1978,14 @@ getTrivialTemplateArgumentLoc(Sema &S,
return TemplateArgumentLoc(TemplateArgument(E), E);
}
+ case TemplateArgument::NullPtr: {
+ Expr *E
+ = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true),
+ E);
+ }
+
case TemplateArgument::Integral: {
Expr *E
= S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
@@ -2162,6 +2211,9 @@ Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info) {
+ if (Partial->isInvalidDecl())
+ return TDK_Invalid;
+
// C++ [temp.class.spec.match]p2:
// A partial specialization matches a given actual template
// argument list if the template arguments of the partial
@@ -2601,12 +2653,13 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// explicitly-specified set (C++0x [temp.arg.explicit]p9).
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
- if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
+ if (CurrentInstantiationScope &&
+ CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
&NumExplicitArgs)
== Param)
Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));
else
- Builder.push_back(TemplateArgument(0, 0));
+ Builder.push_back(TemplateArgument::getEmptyPack());
continue;
}
@@ -2784,7 +2837,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// Otherwise, see if we can resolve a function type
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ TemplateDeductionInfo Info(Ovl->getNameLoc());
if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs,
Specialization, Info))
continue;
@@ -2815,7 +2868,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// So we do not reject deductions which were made elsewhere.
SmallVector<DeducedTemplateArgument, 8>
Deduced(TemplateParams->size());
- TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ TemplateDeductionInfo Info(Ovl->getNameLoc());
Sema::TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
@@ -2992,8 +3045,6 @@ DeduceTemplateArgumentByListElement(Sema &S,
///
/// \param Args the function call arguments
///
-/// \param NumArgs the number of arguments in Args
-///
/// \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
@@ -3013,6 +3064,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
llvm::ArrayRef<Expr *> Args,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
+ if (FunctionTemplate->isInvalidDecl())
+ return TDK_Invalid;
+
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
// C++ [temp.deduct.call]p1:
@@ -3269,6 +3323,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
+ if (FunctionTemplate->isInvalidDecl())
+ return TDK_Invalid;
+
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -3328,6 +3385,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info) {
+ if (FunctionTemplate->isInvalidDecl())
+ return TDK_Invalid;
+
CXXConversionDecl *Conv
= cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
QualType FromType = Conv->getConversionType();
@@ -3572,7 +3632,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
QualType InitType = Init->getType();
unsigned TDF = 0;
- TemplateDeductionInfo Info(Context, Loc);
+ TemplateDeductionInfo Info(Loc);
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (InitList) {
@@ -3594,10 +3654,11 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
return DAR_Failed;
}
- QualType DeducedType = Deduced[0].getAsType();
- if (DeducedType.isNull())
+ if (Deduced[0].getKind() != TemplateArgument::Type)
return DAR_Failed;
+ QualType DeducedType = Deduced[0].getAsType();
+
if (InitList) {
DeducedType = BuildStdInitializerList(DeducedType, Loc);
if (DeducedType.isNull())
@@ -3637,26 +3698,23 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
llvm::SmallBitVector &Deduced);
/// \brief If this is a non-static member function,
-static void MaybeAddImplicitObjectParameterType(ASTContext &Context,
+static void AddImplicitObjectParameterType(ASTContext &Context,
CXXMethodDecl *Method,
SmallVectorImpl<QualType> &ArgTypes) {
- if (Method->isStatic())
- return;
-
- // C++ [over.match.funcs]p4:
- //
- // For non-static member functions, the type of the implicit
- // object parameter is
- // - "lvalue reference to cv X" for functions declared without a
- // ref-qualifier or with the & ref-qualifier
- // - "rvalue reference to cv X" for functions declared with the
- // && ref-qualifier
+ // C++11 [temp.func.order]p3:
+ // [...] The new parameter is of type "reference to cv A," where cv are
+ // the cv-qualifiers of the function template (if any) and A is
+ // the class of which the function template is a member.
//
- // FIXME: We don't have ref-qualifiers yet, so we don't do that part.
+ // The standard doesn't say explicitly, but we pick the appropriate kind of
+ // reference type based on [over.match.funcs]p4.
QualType ArgTy = Context.getTypeDeclType(Method->getParent());
ArgTy = Context.getQualifiedType(ArgTy,
Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
- ArgTy = Context.getLValueReferenceType(ArgTy);
+ if (Method->getRefQualifier() == RQ_RValue)
+ ArgTy = Context.getRValueReferenceType(ArgTy);
+ else
+ ArgTy = Context.getLValueReferenceType(ArgTy);
ArgTypes.push_back(ArgTy);
}
@@ -3682,7 +3740,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// C++0x [temp.deduct.partial]p3:
// The types used to determine the ordering depend on the context in which
// the partial ordering is done:
- TemplateDeductionInfo Info(S.Context, Loc);
+ TemplateDeductionInfo Info(Loc);
CXXMethodDecl *Method1 = 0;
CXXMethodDecl *Method2 = 0;
bool IsNonStatic2 = false;
@@ -3697,7 +3755,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
IsNonStatic1 = Method1 && !Method1->isStatic();
IsNonStatic2 = Method2 && !Method2->isStatic();
- // C++0x [temp.func.order]p3:
+ // C++11 [temp.func.order]p3:
// [...] If only one of the function templates is a non-static
// member, that function template is considered to have a new
// first parameter inserted in its function parameter list. The
@@ -3705,22 +3763,25 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// the cv-qualifiers of the function template (if any) and A is
// the class of which the function template is a member.
//
+ // Note that we interpret this to mean "if one of the function
+ // templates is a non-static member and the other is a non-member";
+ // otherwise, the ordering rules for static functions against non-static
+ // functions don't make any sense.
+ //
// C++98/03 doesn't have this provision, so instead we drop the
- // first argument of the free function or static member, which
- // seems to match existing practice.
+ // first argument of the free function, which seems to match
+ // existing practice.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = !S.getLangOpts().CPlusPlus0x &&
- IsNonStatic2 && !IsNonStatic1;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2)
- MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1);
+ unsigned Skip1 = !S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1;
+ if (S.getLangOpts().CPlusPlus0x && 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 && !IsNonStatic2;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
- MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2);
+ Skip2 = !S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2;
+ if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1)
+ AddImplicitObjectParameterType(S.Context, Method2, Args2);
Args2.insert(Args2.end(),
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
@@ -4118,7 +4179,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// template partial specialization's template arguments, for
// example.
SmallVector<DeducedTemplateArgument, 4> Deduced;
- TemplateDeductionInfo Info(Context, Loc);
+ TemplateDeductionInfo Info(Loc);
QualType PT1 = PS1->getInjectedSpecializationType();
QualType PT2 = PS2->getInjectedSpecializationType();
@@ -4496,6 +4557,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
case TemplateArgument::Declaration:
break;
+ case TemplateArgument::NullPtr:
+ MarkUsedTemplateParameters(Ctx, TemplateArg.getNullPtrType(), OnlyDeduced,
+ Depth, Used);
+ break;
+
case TemplateArgument::Type:
MarkUsedTemplateParameters(Ctx, TemplateArg.getAsType(), OnlyDeduced,
Depth, Used);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 20e755fdaee1..665dd07b8f85 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -769,7 +769,7 @@ namespace {
/// instantiating it.
Decl *TransformDefinition(SourceLocation Loc, Decl *D);
- /// \bried Transform the first qualifier within a scope by instantiating the
+ /// \brief Transform the first qualifier within a scope by instantiating the
/// declaration.
NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
@@ -802,11 +802,24 @@ namespace {
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+
ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E);
-
+
+ /// \brief Rebuild a DeclRefExpr for a ParmVarDecl reference.
+ ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc);
+
+ /// \brief Transform a reference to a function parameter pack.
+ ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E,
+ ParmVarDecl *PD);
+
+ /// \brief Transform a FunctionParmPackExpr which was built when we couldn't
+ /// expand a function parameter pack reference which refers to an expanded
+ /// pack.
+ ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
+
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL);
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
@@ -835,7 +848,7 @@ namespace {
ExprResult Result =
TreeTransform<TemplateInstantiator>::TransformCallExpr(CE);
getSema().CallsUndergoingInstantiation.pop_back();
- return move(Result);
+ return Result;
}
ExprResult TransformLambdaExpr(LambdaExpr *E) {
@@ -1161,10 +1174,11 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
result = SemaRef.Owned(argExpr);
type = argExpr->getType();
- } else if (arg.getKind() == TemplateArgument::Declaration) {
+ } else if (arg.getKind() == TemplateArgument::Declaration ||
+ arg.getKind() == TemplateArgument::NullPtr) {
ValueDecl *VD;
- if (Decl *D = arg.getAsDecl()) {
- VD = cast<ValueDecl>(D);
+ if (arg.getKind() == TemplateArgument::Declaration) {
+ VD = cast<ValueDecl>(arg.getAsDecl());
// Find the instantiation of the template argument. This is
// required for nested templates.
@@ -1230,8 +1244,81 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
}
ExprResult
+TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD,
+ SourceLocation Loc) {
+ DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
+ return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD);
+}
+
+ExprResult
+TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ if (getSema().ArgumentPackSubstitutionIndex != -1) {
+ // We can expand this parameter pack now.
+ ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex);
+ ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D));
+ if (!VD)
+ return ExprError();
+ return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc());
+ }
+
+ QualType T = TransformType(E->getType());
+ if (T.isNull())
+ return ExprError();
+
+ // Transform each of the parameter expansions into the corresponding
+ // parameters in the instantiation of the function decl.
+ llvm::SmallVector<Decl*, 8> Parms;
+ Parms.reserve(E->getNumExpansions());
+ for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
+ I != End; ++I) {
+ ParmVarDecl *D =
+ cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I));
+ if (!D)
+ return ExprError();
+ Parms.push_back(D);
+ }
+
+ return FunctionParmPackExpr::Create(getSema().Context, T,
+ E->getParameterPack(),
+ E->getParameterPackLocation(), Parms);
+}
+
+ExprResult
+TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
+ ParmVarDecl *PD) {
+ typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
+ = getSema().CurrentInstantiationScope->findInstantiationOf(PD);
+ assert(Found && "no instantiation for parameter pack");
+
+ Decl *TransformedDecl;
+ if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) {
+ // If this is a reference to a function parameter pack which we can substitute
+ // but can't yet expand, build a FunctionParmPackExpr for it.
+ if (getSema().ArgumentPackSubstitutionIndex == -1) {
+ QualType T = TransformType(E->getType());
+ if (T.isNull())
+ return ExprError();
+ return FunctionParmPackExpr::Create(getSema().Context, T, PD,
+ E->getExprLoc(), *Pack);
+ }
+
+ TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
+ } else {
+ TransformedDecl = Found->get<Decl*>();
+ }
+
+ // We have either an unexpanded pack or a specific expansion.
+ return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl),
+ E->getExprLoc());
+}
+
+ExprResult
TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
NamedDecl *D = E->getDecl();
+
+ // Handle references to non-type template parameters and non-type template
+ // parameter packs.
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
if (NTTP->getDepth() < TemplateArgs.getNumLevels())
return TransformTemplateParmRefExpr(E, NTTP);
@@ -1240,6 +1327,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
// FindInstantiatedDecl will find it in the local instantiation scope.
}
+ // Handle references to function parameter packs.
+ if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D))
+ if (PD->isParameterPack())
+ return TransformFunctionParmPackRefExpr(E, PD);
+
return TreeTransform<TemplateInstantiator>::TransformDeclRefExpr(E);
}
@@ -2159,7 +2251,7 @@ Sema::InstantiateClassTemplateSpecialization(
Template->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
- TemplateDeductionInfo Info(Context, PointOfInstantiation);
+ TemplateDeductionInfo Info(PointOfInstantiation);
if (TemplateDeductionResult Result
= DeduceTemplateArguments(Partial,
ClassTemplateSpec->getTemplateArgs(),
@@ -2543,8 +2635,25 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
return Instantiator.TransformTemplateArguments(Args, NumArgs, Result);
}
+
+static const Decl* getCanonicalParmVarDecl(const Decl *D) {
+ // When storing ParmVarDecls in the local instantiation scope, we always
+ // want to use the ParmVarDecl from the canonical function declaration,
+ // since the map is then valid for any redeclaration or definition of that
+ // function.
+ if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+ unsigned i = PV->getFunctionScopeIndex();
+ return FD->getCanonicalDecl()->getParamDecl(i);
+ }
+ }
+ return D;
+}
+
+
llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
LocalInstantiationScope::findInstantiationOf(const Decl *D) {
+ D = getCanonicalParmVarDecl(D);
for (LocalInstantiationScope *Current = this; Current;
Current = Current->Outer) {
@@ -2576,6 +2685,7 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
}
void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
+ D = getCanonicalParmVarDecl(D);
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
if (Stored.isNull())
Stored = Inst;
@@ -2588,11 +2698,13 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
Decl *Inst) {
+ D = getCanonicalParmVarDecl(D);
DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
Pack->push_back(Inst);
}
void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
+ D = getCanonicalParmVarDecl(D);
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
assert(Stored.isNull() && "Already instantiated this local");
DeclArgumentPack *Pack = new DeclArgumentPack;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bdbe71dd8aba..19c46ab9c97f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -158,6 +158,22 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
+ // HACK: g++ has a bug where it gets the value kind of ?: wrong.
+ // libstdc++ relies upon this bug in its implementation of common_type.
+ // If we happen to be processing that implementation, fake up the g++ ?:
+ // semantics. See LWG issue 2141 for more information on the bug.
+ const DecltypeType *DT = DI->getType()->getAs<DecltypeType>();
+ CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext());
+ if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) &&
+ DT->isReferenceType() &&
+ RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() &&
+ RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") &&
+ D->getIdentifier() && D->getIdentifier()->isStr("type") &&
+ SemaRef.getSourceManager().isInSystemHeader(D->getLocStart()))
+ // Fold it to the (non-reference) type which g++ would have produced.
+ DI = SemaRef.Context.getTrivialTypeSourceInfo(
+ DI->getType().getNonReferenceType());
+
// Create the new typedef
TypedefNameDecl *Typedef;
if (IsTypeAlias)
@@ -510,7 +526,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
if (!InstTy)
return 0;
- FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocation(),
+ FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocStart(),
D->getFriendLoc(), InstTy);
if (!FD)
return 0;
@@ -1008,6 +1024,30 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
return Record;
}
+/// \brief Adjust the given function type for an instantiation of the
+/// given declaration, to cope with modifications to the function's type that
+/// aren't reflected in the type-source information.
+///
+/// \param D The declaration we're instantiating.
+/// \param TInfo The already-instantiated type.
+static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
+ FunctionDecl *D,
+ TypeSourceInfo *TInfo) {
+ const FunctionProtoType *OrigFunc
+ = D->getType()->castAs<FunctionProtoType>();
+ const FunctionProtoType *NewFunc
+ = TInfo->getType()->castAs<FunctionProtoType>();
+ if (OrigFunc->getExtInfo() == NewFunc->getExtInfo())
+ return TInfo->getType();
+
+ FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
+ NewEPI.ExtInfo = OrigFunc->getExtInfo();
+ return Context.getFunctionType(NewFunc->getResultType(),
+ NewFunc->arg_type_begin(),
+ NewFunc->getNumArgs(),
+ NewEPI);
+}
+
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves two purposes:
/// 1) instantiating function templates
@@ -1048,7 +1088,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return 0;
- QualType T = TInfo->getType();
+ QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
@@ -1075,7 +1115,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
- D->getLocation(), D->getDeclName(), T, TInfo,
+ D->getNameInfo(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
D->isConstexpr());
@@ -1366,7 +1406,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return 0;
- QualType T = TInfo->getType();
+ QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
// \brief If the type of this function, after ignoring parentheses,
// is not *directly* a function type, then we're instantiating a function
@@ -1657,7 +1697,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
IsExpandedParameterPack = true;
DI = D->getTypeSourceInfo();
T = DI->getType();
- } else if (isa<PackExpansionTypeLoc>(TL)) {
+ } else if (D->isPackExpansion()) {
// 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.
@@ -1771,27 +1811,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
return Param;
}
+static void collectUnexpandedParameterPacks(
+ Sema &S,
+ TemplateParameterList *Params,
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ for (TemplateParameterList::const_iterator I = Params->begin(),
+ E = Params->end(); I != E; ++I) {
+ if ((*I)->isTemplateParameterPack())
+ continue;
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*I))
+ S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(),
+ Unexpanded);
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*I))
+ collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(),
+ Unexpanded);
+ }
+}
+
Decl *
TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
TemplateTemplateParmDecl *D) {
// Instantiate the template parameter list of the template template parameter.
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams;
- {
+ SmallVector<TemplateParameterList*, 8> ExpandedParams;
+
+ bool IsExpandedParameterPack = false;
+
+ if (D->isExpandedParameterPack()) {
+ // The template template parameter pack is an already-expanded pack
+ // expansion of template parameters. Substitute into each of the expanded
+ // parameters.
+ ExpandedParams.reserve(D->getNumExpansionTemplateParameters());
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I) {
+ LocalInstantiationScope Scope(SemaRef);
+ TemplateParameterList *Expansion =
+ SubstTemplateParams(D->getExpansionTemplateParameters(I));
+ if (!Expansion)
+ return 0;
+ ExpandedParams.push_back(Expansion);
+ }
+
+ IsExpandedParameterPack = true;
+ InstParams = TempParams;
+ } else if (D->isPackExpansion()) {
+ // The template template parameter pack expands to a pack of template
+ // template parameters. Determine whether we need to expand this parameter
+ // pack into separate parameters.
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(),
+ Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ llvm::Optional<unsigned> NumExpansions;
+ if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
+ TempParams->getSourceRange(),
+ Unexpanded,
+ TemplateArgs,
+ Expand, RetainExpansion,
+ NumExpansions))
+ return 0;
+
+ if (Expand) {
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
+ LocalInstantiationScope Scope(SemaRef);
+ TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
+ if (!Expansion)
+ return 0;
+ ExpandedParams.push_back(Expansion);
+ }
+
+ // Note that we have an expanded parameter pack. The "type" of this
+ // expanded parameter pack is the original expansion type, but callers
+ // will end up using the expanded parameter pack types for type-checking.
+ IsExpandedParameterPack = true;
+ InstParams = TempParams;
+ } else {
+ // We cannot fully expand the pack expansion now, so just substitute
+ // into the pattern.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
+
+ LocalInstantiationScope Scope(SemaRef);
+ InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return 0;
+ }
+ } else {
// Perform the actual substitution of template parameters within a new,
// local instantiation scope.
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return NULL;
+ return 0;
}
// Build the template template parameter.
- TemplateTemplateParmDecl *Param
- = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ TemplateTemplateParmDecl *Param;
+ if (IsExpandedParameterPack)
+ Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumLevels(),
+ D->getPosition(),
+ D->getIdentifier(), InstParams,
+ ExpandedParams);
+ else
+ Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(), D->isParameterPack(),
- D->getIdentifier(), InstParams);
+ D->getPosition(),
+ D->isParameterPack(),
+ D->getIdentifier(), InstParams);
Param->setDefaultArgument(D->getDefaultArgument(), false);
Param->setAccess(AS_public);
@@ -1813,7 +1947,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
D->getIdentLocation(),
D->getNominatedNamespace(),
D->getCommonAncestor());
- Owner->addDecl(Inst);
+
+ // Add the using directive to its declaration context
+ // only if this is not a function or method.
+ if (!Owner->isFunctionOrMethod())
+ Owner->addDecl(Inst);
+
return Inst;
}
@@ -2863,7 +3002,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const MultiLevelTemplateArgumentList &TemplateArgs) {
SmallVector<CXXCtorInitializer*, 4> NewInits;
- bool AnyErrors = false;
+ bool AnyErrors = Tmpl->isInvalidDecl();
// Instantiate all the initializers.
for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
@@ -3031,7 +3170,7 @@ ExprResult Sema::SubstInitializer(Expr *Init,
isa<CXXTemporaryObjectExpr>(Construct))
return SubstExpr(Init, TemplateArgs);
- ASTOwningVector<Expr*> NewArgs(*this);
+ SmallVector<Expr*, 8> NewArgs;
if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
TemplateArgs, NewArgs))
return ExprError();
@@ -3043,7 +3182,7 @@ ExprResult Sema::SubstInitializer(Expr *Init,
// Build a ParenListExpr to represent anything else.
// FIXME: Fake locations!
SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart());
- return ActOnParenListExpr(Loc, Loc, move_arg(NewArgs));
+ return ActOnParenListExpr(Loc, Loc, NewArgs);
}
// TODO: this could be templated if the various decl types used the
@@ -3298,7 +3437,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (Decl *FD = Found->dyn_cast<Decl *>())
return cast<NamedDecl>(FD);
- unsigned PackIdx = ArgumentPackSubstitutionIndex;
+ int PackIdx = ArgumentPackSubstitutionIndex;
+ assert(PackIdx != -1 && "found declaration pack but not pack expanding");
return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index aece90b78590..6147d63ef44b 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_enum:
case TST_union:
case TST_struct:
+ case TST_interface:
case TST_class:
case TST_auto:
case TST_unknown_anytype:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 54f8dbaf0127..4b23167951aa 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -105,7 +105,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_ThisCall: \
case AttributeList::AT_Pascal: \
case AttributeList::AT_Regparm: \
- case AttributeList::AT_Pcs \
+ case AttributeList::AT_Pcs: \
+ case AttributeList::AT_PnaclCall \
namespace {
/// An object which stores processing state for the entire
@@ -552,19 +553,28 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
SourceLocation loc = declarator.getLocStart();
// ...and *prepend* it to the declarator.
+ SourceLocation NoLoc;
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
- /*proto*/ true,
- /*variadic*/ false,
- /*ambiguous*/ false, SourceLocation(),
- /*args*/ 0, 0,
- /*type quals*/ 0,
- /*ref-qualifier*/true, SourceLocation(),
- /*const qualifier*/SourceLocation(),
- /*volatile qualifier*/SourceLocation(),
- /*mutable qualifier*/SourceLocation(),
- /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
- /*parens*/ loc, loc,
- declarator));
+ /*HasProto=*/true,
+ /*IsAmbiguous=*/false,
+ /*LParenLoc=*/NoLoc,
+ /*ArgInfo=*/0,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ loc, loc, declarator));
// For consistency, make sure the state still has us as processing
// the decl spec.
@@ -636,7 +646,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**)PQ,
+ (ObjCProtocolDecl*const*)PQ,
DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Result);
break;
@@ -698,11 +708,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TSW_longlong:
Result = Context.LongLongTy;
- // long long is a C99 feature.
- if (!S.getLangOpts().C99)
- S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!S.getLangOpts().C99) {
+ if (S.getLangOpts().CPlusPlus)
+ S.Diag(DS.getTypeSpecWidthLoc(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
+ }
break;
}
} else {
@@ -713,11 +727,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TSW_longlong:
Result = Context.UnsignedLongLongTy;
- // long long is a C99 feature.
- if (!S.getLangOpts().C99)
- S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!S.getLangOpts().C99) {
+ if (S.getLangOpts().CPlusPlus)
+ S.Diag(DS.getTypeSpecWidthLoc(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
+ }
break;
}
}
@@ -753,7 +771,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TST_class:
case DeclSpec::TST_enum:
case DeclSpec::TST_union:
- case DeclSpec::TST_struct: {
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_interface: {
TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl());
if (!D) {
// This can happen in C++ with ambiguous lookups.
@@ -794,18 +813,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (DS.getNumProtocolQualifiers())
Result = Context.getObjCObjectType(Result,
- (ObjCProtocolDecl**) PQ,
+ (ObjCProtocolDecl*const*) PQ,
DS.getNumProtocolQualifiers());
} else if (Result->isObjCIdType()) {
// id<protocol-list>
Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**) PQ,
+ (ObjCProtocolDecl*const*) PQ,
DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Result);
} else if (Result->isObjCClassType()) {
// Class<protocol-list>
Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy,
- (ObjCProtocolDecl**) PQ,
+ (ObjCProtocolDecl*const*) PQ,
DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Result);
} else {
@@ -1853,30 +1872,31 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case TTK_Struct: Error = 1; /* Struct member */ break;
case TTK_Union: Error = 2; /* Union member */ break;
case TTK_Class: Error = 3; /* Class member */ break;
+ case TTK_Interface: Error = 4; /* Interface member */ break;
}
break;
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
- Error = 4; // Exception declaration
+ Error = 5; // Exception declaration
break;
case Declarator::TemplateParamContext:
- Error = 5; // Template parameter
+ Error = 6; // Template parameter
break;
case Declarator::BlockLiteralContext:
- Error = 6; // Block literal
+ Error = 7; // Block literal
break;
case Declarator::TemplateTypeArgContext:
- Error = 7; // Template type argument
+ Error = 8; // Template type argument
break;
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
- Error = 9; // Type alias
+ Error = 10; // Type alias
break;
case Declarator::TrailingReturnContext:
- Error = 10; // Function return type
+ Error = 11; // Function return type
break;
case Declarator::TypeNameContext:
- Error = 11; // Generic
+ Error = 12; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
@@ -1887,11 +1907,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
}
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- Error = 8;
+ Error = 9;
// In Objective-C it is an error to use 'auto' on a function declarator.
if (D.isFunctionDeclarator())
- Error = 10;
+ Error = 11;
// C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
// contains a trailing return type. That is only legal at the outermost
@@ -2149,16 +2169,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
ASTContext &Context = S.Context;
const LangOptions &LangOpts = S.getLangOpts();
- bool ImplicitlyNoexcept = false;
- if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId &&
- LangOpts.CPlusPlus0x) {
- OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
- /// In C++0x, deallocation functions (normal and array operator delete)
- /// are implicitly noexcept.
- if (OO == OO_Delete || OO == OO_Array_Delete)
- ImplicitlyNoexcept = true;
- }
-
// The name we're declaring, if any.
DeclarationName Name;
if (D.getIdentifier())
@@ -2558,12 +2568,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI);
- if (FTI.getExceptionSpecType() == EST_None &&
- ImplicitlyNoexcept && chunkIndex == 0) {
- // Only the outermost chunk is marked noexcept, of course.
- EPI.ExceptionSpecType = EST_BasicNoexcept;
- }
-
T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);
}
@@ -2657,6 +2661,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// 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 &&
@@ -2668,6 +2675,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
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):
@@ -2721,6 +2734,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
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);
+ }
}
}
@@ -2985,6 +3004,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_Pascal;
case AttributedType::attr_pcs:
return AttributeList::AT_Pcs;
+ case AttributedType::attr_pnaclcall:
+ return AttributeList::AT_PnaclCall;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -3271,6 +3292,8 @@ namespace {
TL.setLocalRangeEnd(Chunk.EndLoc);
const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
+ TL.setLParenLoc(FTI.getLParenLoc());
+ TL.setRParenLoc(FTI.getRParenLoc());
for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
TL.setArg(tpi++, Param);
@@ -3588,7 +3611,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Forbid __weak if the runtime doesn't support it.
if (lifetime == Qualifiers::OCL_Weak &&
- !S.getLangOpts().ObjCRuntimeHasWeak && !NonObjCPointer) {
+ !S.getLangOpts().ObjCARCWeak && !NonObjCPointer) {
// Actually, delay this until we know what we're parsing.
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
@@ -3611,11 +3634,12 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
while (const PointerType *ptr = T->getAs<PointerType>())
T = ptr->getPointeeType();
if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
- ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
- if (Class->isArcWeakrefUnavailable()) {
- S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
- S.Diag(ObjT->getInterfaceDecl()->getLocation(),
- diag::note_class_declared);
+ if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) {
+ if (Class->isArcWeakrefUnavailable()) {
+ S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
+ S.Diag(ObjT->getInterfaceDecl()->getLocation(),
+ diag::note_class_declared);
+ }
}
}
}
@@ -3875,14 +3899,14 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
+ // Delay if the type didn't work out to a function.
+ if (!unwrapped.isFunctionType()) return false;
+
// Otherwise, a calling convention.
CallingConv CC;
if (S.CheckCallingConvAttr(attr, CC))
return true;
- // Delay if the type didn't work out to a function.
- if (!unwrapped.isFunctionType()) return false;
-
const FunctionType *fn = unwrapped.get();
CallingConv CCOld = fn->getCallConv();
if (S.Context.getCanonicalCallConv(CC) ==
@@ -4429,6 +4453,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return RequireCompleteType(Loc, T, Diagnoser);
}
+/// \brief Get diagnostic %select index for tag kind for
+/// literal type diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for literal type diagnostic!");
+ }
+}
+
/// @brief Ensure that the type T is a literal type.
///
/// This routine checks whether the type @p T is a literal type. If @p T is an
@@ -4485,7 +4523,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
// of constexpr constructors.
if (RD->getNumVBases()) {
Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
- << RD->isStruct() << RD->getNumVBases();
+ << getLiteralDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getLocStart(),
@@ -4578,15 +4616,21 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// member access (5.2.5), decltype(e) is the type of the entity named
// by e. If there is no such entity, or if e names a set of overloaded
// functions, the program is ill-formed;
+ //
+ // We apply the same rules for Objective-C ivar and property references.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
return VD->getType();
- }
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
return FD->getType();
+ } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) {
+ return IR->getDecl()->getType();
+ } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (PR->isExplicitProperty())
+ return PR->getExplicitProperty()->getType();
}
-
+
// C++11 [expr.lambda.prim]p18:
// Every occurrence of decltype((x)) where x is a possibly
// parenthesized id-expression that names an entity of automatic
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 619ad330b95b..294d74244673 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -574,6 +574,10 @@ public:
/// \brief Transform the captures and body of a lambda expression.
ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+ ExprResult TransformAddressOfOperand(Expr *E);
+ ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
+ bool IsAddressOfOperand);
+
#define STMT(Node, Parent) \
StmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
@@ -1162,32 +1166,23 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildAsmStmt(SourceLocation AsmLoc,
- bool IsSimple,
- bool IsVolatile,
- unsigned NumOutputs,
- unsigned NumInputs,
- IdentifierInfo **Names,
- MultiExprArg Constraints,
- MultiExprArg Exprs,
- Expr *AsmString,
- MultiExprArg Clobbers,
- SourceLocation RParenLoc,
- bool MSAsm) {
- return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
- NumInputs, Names, move(Constraints),
- Exprs, AsmString, Clobbers,
- RParenLoc, MSAsm);
+ StmtResult RebuildGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+ bool IsVolatile, unsigned NumOutputs,
+ unsigned NumInputs, IdentifierInfo **Names,
+ MultiExprArg Constraints, MultiExprArg Exprs,
+ Expr *AsmString, MultiExprArg Clobbers,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs,
+ AsmString, Clobbers, RParenLoc);
}
/// \brief Build a new MS style inline asm statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc,
- SourceLocation LBraceLoc,
- ArrayRef<Token> AsmToks,
- SourceLocation EndLoc) {
+ StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
+ ArrayRef<Token> AsmToks, SourceLocation EndLoc) {
return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc);
}
@@ -1199,7 +1194,7 @@ public:
Stmt *TryBody,
MultiStmtArg CatchStmts,
Stmt *Finally) {
- return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, move(CatchStmts),
+ return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, CatchStmts,
Finally);
}
@@ -1325,7 +1320,7 @@ public:
StmtResult RebuildCXXTryStmt(SourceLocation TryLoc,
Stmt *TryBlock,
MultiStmtArg Handlers) {
- return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers));
+ return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, Handlers);
}
/// \brief Build a new C++0x range-based for statement.
@@ -1339,7 +1334,8 @@ public:
Stmt *LoopVar,
SourceLocation RParenLoc) {
return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
- Cond, Inc, LoopVar, RParenLoc);
+ Cond, Inc, LoopVar, RParenLoc,
+ Sema::BFRK_Rebuild);
}
/// \brief Build a new C++0x range-based for statement.
@@ -1478,7 +1474,7 @@ public:
if (Result.isInvalid())
return ExprError();
- return move(Result);
+ return Result;
}
/// \brief Build a new array subscript expression.
@@ -1503,7 +1499,7 @@ public:
SourceLocation RParenLoc,
Expr *ExecConfig = 0) {
return getSema().ActOnCallExpr(/*Scope=*/0, Callee, LParenLoc,
- move(Args), RParenLoc, ExecConfig);
+ Args, RParenLoc, ExecConfig);
}
/// \brief Build a new member access expression.
@@ -1638,15 +1634,15 @@ public:
SourceLocation RBraceLoc,
QualType ResultTy) {
ExprResult Result
- = SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
+ = SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc);
if (Result.isInvalid() || ResultTy->isDependentType())
- return move(Result);
+ return Result;
// Patch in the result type we were given, which may have been computed
// when the initial InitListExpr was built.
InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get());
ILE->setType(ResultTy);
- return move(Result);
+ return Result;
}
/// \brief Build a new designated initializer expression.
@@ -1664,8 +1660,7 @@ public:
if (Result.isInvalid())
return ExprError();
- ArrayExprs.release();
- return move(Result);
+ return Result;
}
/// \brief Build a new value-initialized expression.
@@ -1696,7 +1691,7 @@ public:
ExprResult RebuildParenListExpr(SourceLocation LParenLoc,
MultiExprArg SubExprs,
SourceLocation RParenLoc) {
- return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs));
+ return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs);
}
/// \brief Build a new address-of-label expression.
@@ -1974,8 +1969,7 @@ public:
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc,
- MultiExprArg(getSema(), 0, 0),
- RParenLoc);
+ MultiExprArg(), RParenLoc);
}
/// \brief Build a new C++ "new" expression.
@@ -1995,7 +1989,7 @@ public:
Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ PlacementArgs,
PlacementRParen,
TypeIdParens,
AllocatedType,
@@ -2083,7 +2077,8 @@ public:
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsAddressOfOperand) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -2091,7 +2086,8 @@ public:
return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc,
NameInfo, TemplateArgs);
- return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo);
+ return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo,
+ IsAddressOfOperand);
}
/// \brief Build a new template-id expression.
@@ -2120,13 +2116,13 @@ public:
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
- ASTOwningVector<Expr*> ConvertedArgs(SemaRef);
- if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc,
+ SmallVector<Expr*, 8> ConvertedArgs;
+ if (getSema().CompleteConstructorCall(Constructor, Args, Loc,
ConvertedArgs))
return ExprError();
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
- move_arg(ConvertedArgs),
+ ConvertedArgs,
HadMultipleCandidates,
RequiresZeroInit, ConstructKind,
ParenRange);
@@ -2142,7 +2138,7 @@ public:
SourceLocation RParenLoc) {
return getSema().BuildCXXTypeConstructExpr(TSInfo,
LParenLoc,
- move(Args),
+ Args,
RParenLoc);
}
@@ -2156,7 +2152,7 @@ public:
SourceLocation RParenLoc) {
return getSema().BuildCXXTypeConstructExpr(TSInfo,
LParenLoc,
- move(Args),
+ Args,
RParenLoc);
}
@@ -2288,7 +2284,7 @@ public:
ReceiverTypeInfo->getType(),
/*SuperLoc=*/SourceLocation(),
Sel, Method, LBracLoc, SelectorLocs,
- RBracLoc, move(Args));
+ RBracLoc, Args);
}
/// \brief Build a new Objective-C instance message.
@@ -2303,7 +2299,7 @@ public:
Receiver->getType(),
/*SuperLoc=*/SourceLocation(),
Sel, Method, LBracLoc, SelectorLocs,
- RBracLoc, move(Args));
+ RBracLoc, Args);
}
/// \brief Build a new Objective-C ivar reference expression.
@@ -2326,7 +2322,7 @@ public:
return ExprError();
if (Result.get())
- return move(Result);
+ return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IvarLoc, IsArrow,
@@ -2355,7 +2351,7 @@ public:
return ExprError();
if (Result.get())
- return move(Result);
+ return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/PropertyLoc, IsArrow,
@@ -2398,7 +2394,7 @@ public:
return ExprError();
if (Result.get())
- return move(Result);
+ return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IsaLoc, IsArrow,
@@ -2424,21 +2420,17 @@ public:
// Build a reference to the __builtin_shufflevector builtin
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
- ExprResult Callee
- = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, false,
- Builtin->getType(),
- VK_LValue, BuiltinLoc));
- Callee = SemaRef.UsualUnaryConversions(Callee.take());
- if (Callee.isInvalid())
- return ExprError();
+ Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false,
+ SemaRef.Context.BuiltinFnTy,
+ VK_RValue, BuiltinLoc);
+ QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType());
+ Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy,
+ CK_BuiltinFnToFnPtr).take();
// Build the CallExpr
- unsigned NumSubExprs = SubExprs.size();
- Expr **Subs = (Expr **)SubExprs.release();
ExprResult TheCall = SemaRef.Owned(
- new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(),
- Subs, NumSubExprs,
- Builtin->getCallResultType(),
+ new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, SubExprs,
+ Builtin->getCallResultType(),
Expr::getValueKindForType(Builtin->getResultType()),
RParenLoc));
@@ -2478,6 +2470,7 @@ public:
case TemplateArgument::Declaration:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::NullPtr:
llvm_unreachable("Pack expansion pattern has no parameter packs");
case TemplateArgument::Type:
@@ -2515,10 +2508,7 @@ public:
// Just create the expression; there is not any interesting semantic
// analysis here because we can't actually build an AtomicExpr until
// we are sure it is semantically sound.
- unsigned NumSubExprs = SubExprs.size();
- Expr **Subs = (Expr **)SubExprs.release();
- return new (SemaRef.Context) AtomicExpr(BuiltinLoc, Subs,
- NumSubExprs, RetTy, Op,
+ return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op,
RParenLoc);
}
@@ -2963,6 +2953,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::Pack:
+ case TemplateArgument::NullPtr:
Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
break;
}
@@ -2976,8 +2967,10 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
- Output = Input;
- return false;
+ case TemplateArgument::Pack:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Unexpected TemplateArgument");
case TemplateArgument::Type: {
TypeSourceInfo *DI = Input.getTypeSourceInfo();
@@ -2991,28 +2984,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
return false;
}
- case TemplateArgument::Declaration: {
- // FIXME: we should never have to transform one of these.
- DeclarationName Name;
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl()))
- Name = ND->getDeclName();
- TemporaryBase Rebase(*this, Input.getLocation(), Name);
- Decl *D = getDerived().TransformDecl(Input.getLocation(), Arg.getAsDecl());
- if (!D) return true;
-
- Expr *SourceExpr = Input.getSourceDeclExpression();
- if (SourceExpr) {
- EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::ConstantEvaluated);
- ExprResult E = getDerived().TransformExpr(SourceExpr);
- E = SemaRef.ActOnConstantExpression(E);
- SourceExpr = (E.isInvalid() ? 0 : E.take());
- }
-
- Output = TemplateArgumentLoc(TemplateArgument(D), SourceExpr);
- return false;
- }
-
case TemplateArgument::Template: {
NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc();
if (QualifierLoc) {
@@ -3051,35 +3022,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take());
return false;
}
-
- case TemplateArgument::Pack: {
- SmallVector<TemplateArgument, 4> TransformedArgs;
- TransformedArgs.reserve(Arg.pack_size());
- for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
- AEnd = Arg.pack_end();
- A != AEnd; ++A) {
-
- // FIXME: preserve source information here when we start
- // caring about parameter packs.
-
- TemplateArgumentLoc InputArg;
- TemplateArgumentLoc OutputArg;
- getDerived().InventTemplateArgumentLoc(*A, InputArg);
- if (getDerived().TransformTemplateArgument(InputArg, OutputArg))
- return true;
-
- TransformedArgs.push_back(OutputArg.getArgument());
- }
-
- TemplateArgument *TransformedArgsPtr
- = new (getSema().Context) TemplateArgument[TransformedArgs.size()];
- std::copy(TransformedArgs.begin(), TransformedArgs.end(),
- TransformedArgsPtr);
- Output = TemplateArgumentLoc(TemplateArgument(TransformedArgsPtr,
- TransformedArgs.size()),
- Input.getLocInfo());
- return false;
- }
}
// Work around bogus GCC warning
@@ -4260,6 +4202,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result);
NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i)
NewTL.setArg(i, ParamDecls[i]);
@@ -4283,6 +4227,8 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result);
NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
return Result;
@@ -4339,7 +4285,8 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
TypeOfExprTypeLoc TL) {
// typeof expressions are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr());
if (E.isInvalid())
@@ -5099,7 +5046,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
bool SubStmtInvalid = false;
bool SubStmtChanged = false;
- ASTOwningVector<Stmt*> Statements(getSema());
+ SmallVector<Stmt*, 8> Statements;
for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
B != BEnd; ++B) {
StmtResult Result = getDerived().TransformStmt(*B);
@@ -5126,7 +5073,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
return SemaRef.Owned(S);
return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
- move_arg(Statements),
+ Statements,
S->getRBracLoc(),
IsStmtExpr);
}
@@ -5533,14 +5480,14 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
template<typename Derived>
StmtResult
-TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
+TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
- ASTOwningVector<Expr*> Constraints(getSema());
- ASTOwningVector<Expr*> Exprs(getSema());
+ SmallVector<Expr*, 8> Constraints;
+ SmallVector<Expr*, 8> Exprs;
SmallVector<IdentifierInfo *, 4> Names;
ExprResult AsmString;
- ASTOwningVector<Expr*> Clobbers(getSema());
+ SmallVector<Expr*, 8> Clobbers;
bool ExprsChanged = false;
@@ -5585,23 +5532,15 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
// Go through the clobbers.
for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I)
- Clobbers.push_back(S->getClobber(I));
+ Clobbers.push_back(S->getClobberStringLiteral(I));
// No need to transform the asm string literal.
AsmString = SemaRef.Owned(S->getAsmString());
-
- return getDerived().RebuildAsmStmt(S->getAsmLoc(),
- S->isSimple(),
- S->isVolatile(),
- S->getNumOutputs(),
- S->getNumInputs(),
- Names.data(),
- move_arg(Constraints),
- move_arg(Exprs),
- AsmString.get(),
- move_arg(Clobbers),
- S->getRParenLoc(),
- S->isMSAsm());
+ return getDerived().RebuildGCCAsmStmt(S->getAsmLoc(), S->isSimple(),
+ S->isVolatile(), S->getNumOutputs(),
+ S->getNumInputs(), Names.data(),
+ Constraints, Exprs, AsmString.get(),
+ Clobbers, S->getRParenLoc());
}
template<typename Derived>
@@ -5624,7 +5563,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
// Transform the @catch statements (if present).
bool AnyCatchChanged = false;
- ASTOwningVector<Stmt*> CatchStmts(SemaRef);
+ SmallVector<Stmt*, 8> CatchStmts;
for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
StmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I));
if (Catch.isInvalid())
@@ -5651,7 +5590,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
// Build a new statement.
return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(),
- move_arg(CatchStmts), Finally.get());
+ CatchStmts, Finally.get());
}
template<typename Derived>
@@ -5855,7 +5794,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
// Transform the handlers.
bool HandlerChanged = false;
- ASTOwningVector<Stmt*> Handlers(SemaRef);
+ SmallVector<Stmt*, 8> Handlers;
for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
StmtResult Handler
= getDerived().TransformCXXCatchStmt(S->getHandler(I));
@@ -5872,7 +5811,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
return SemaRef.Owned(S);
return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(),
- move_arg(Handlers));
+ Handlers);
}
template<typename Derived>
@@ -6205,10 +6144,22 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
E->getRParen());
}
+/// \brief The operand of a unary address-of operator has special rules: it's
+/// allowed to refer to a non-static member of a class even if there's no 'this'
+/// object available.
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
+ if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E))
+ return getDerived().TransformDependentScopeDeclRefExpr(DRE, true);
+ else
+ return getDerived().TransformExpr(E);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
- ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ ExprResult SubExpr = TransformAddressOfOperand(E->getSubExpr());
if (SubExpr.isInvalid())
return ExprError();
@@ -6338,7 +6289,8 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
// C++0x [expr.sizeof]p1:
// The operand is either an expression, which is an unevaluated operand
// [...]
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
if (SubExpr.isInvalid())
@@ -6386,7 +6338,7 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
// Transform arguments.
bool ArgChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgChanged))
return ExprError();
@@ -6394,13 +6346,13 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Callee.get() == E->getCallee() &&
!ArgChanged)
- return SemaRef.MaybeBindToTemporary(E);;
+ return SemaRef.MaybeBindToTemporary(E);
// FIXME: Wrong source location information for the '('.
SourceLocation FakeLParenLoc
= ((Expr *)Callee.get())->getSourceRange().getBegin();
return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc,
- move_arg(Args),
+ Args,
E->getRParenLoc());
}
@@ -6499,6 +6451,9 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
RHS.get() == E->getRHS())
return SemaRef.Owned(E);
+ Sema::FPContractStateRAII FPContractState(getSema());
+ getSema().FPFeatures.fp_contract = E->isFPContractable();
+
return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
LHS.get(), RHS.get());
}
@@ -6645,7 +6600,7 @@ ExprResult
TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
bool InitChanged = false;
- ASTOwningVector<Expr*, 4> Inits(SemaRef);
+ SmallVector<Expr*, 4> Inits;
if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false,
Inits, &InitChanged))
return ExprError();
@@ -6653,7 +6608,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
if (!getDerived().AlwaysRebuild() && !InitChanged)
return SemaRef.Owned(E);
- return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits),
+ return getDerived().RebuildInitList(E->getLBraceLoc(), Inits,
E->getRBraceLoc(), E->getType());
}
@@ -6668,7 +6623,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
return ExprError();
// transform the designators.
- ASTOwningVector<Expr*, 4> ArrayExprs(SemaRef);
+ SmallVector<Expr*, 4> ArrayExprs;
bool ExprChanged = false;
for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
DEnd = E->designators_end();
@@ -6720,7 +6675,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
!ExprChanged)
return SemaRef.Owned(E);
- return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs),
+ return getDerived().RebuildDesignatedInitExpr(Desig, ArrayExprs,
E->getEqualOrColonLoc(),
E->usesGNUSyntax(), Init.get());
}
@@ -6768,13 +6723,13 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) {
bool ArgumentChanged = false;
- ASTOwningVector<Expr*, 4> Inits(SemaRef);
+ SmallVector<Expr*, 4> Inits;
if (TransformExprs(E->getExprs(), E->getNumExprs(), true, Inits,
&ArgumentChanged))
return ExprError();
return getDerived().RebuildParenListExpr(E->getLParenLoc(),
- move_arg(Inits),
+ Inits,
E->getRParenLoc());
}
@@ -6875,13 +6830,13 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
static_cast<Expr *>(Object.get())->getLocEnd());
// Transform the call arguments.
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true,
Args))
return ExprError();
return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc,
- move_arg(Args),
+ Args,
E->getLocEnd());
}
@@ -6905,7 +6860,11 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
if (Callee.isInvalid())
return ExprError();
- ExprResult First = getDerived().TransformExpr(E->getArg(0));
+ ExprResult First;
+ if (E->getOperator() == OO_Amp)
+ First = getDerived().TransformAddressOfOperand(E->getArg(0));
+ else
+ First = getDerived().TransformExpr(E->getArg(0));
if (First.isInvalid())
return ExprError();
@@ -6922,6 +6881,9 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
(E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
return SemaRef.MaybeBindToTemporary(E);
+ Sema::FPContractStateRAII FPContractState(getSema());
+ getSema().FPFeatures.fp_contract = E->isFPContractable();
+
return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
E->getOperatorLoc(),
Callee.get(),
@@ -6950,7 +6912,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
// Transform arguments.
bool ArgChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgChanged))
return ExprError();
@@ -6964,7 +6926,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
SourceLocation FakeLParenLoc
= ((Expr *)Callee.get())->getSourceRange().getBegin();
return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc,
- move_arg(Args),
+ Args,
E->getRParenLoc(), EC.get());
}
@@ -6989,9 +6951,6 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
SourceLocation FakeLAngleLoc
= SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
- SourceLocation FakeRParenLoc
- = SemaRef.PP.getLocForEndOfToken(
- E->getSubExpr()->getSourceRange().getEnd());
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
FakeLAngleLoc,
@@ -6999,7 +6958,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
FakeRAngleLoc,
FakeRAngleLoc,
SubExpr.get(),
- FakeRParenLoc);
+ E->getRParenLoc());
}
template<typename Derived>
@@ -7074,7 +7033,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
// after we perform semantic analysis. We speculatively assume it is
// unevaluated; it will get fixed later if the subexpression is in fact
// potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
if (SubExpr.isInvalid())
@@ -7222,7 +7182,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Transform the placement arguments (if any).
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> PlacementArgs(SemaRef);
+ SmallVector<Expr*, 8> PlacementArgs;
if (getDerived().TransformExprs(E->getPlacementArgs(),
E->getNumPlacementArgs(), true,
PlacementArgs, &ArgumentChanged))
@@ -7313,7 +7273,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return getDerived().RebuildCXXNewExpr(E->getLocStart(),
E->isGlobalNew(),
/*FIXME:*/E->getLocStart(),
- move_arg(PlacementArgs),
+ PlacementArgs,
/*FIXME:*/E->getLocStart(),
E->getTypeIdParens(),
AllocType,
@@ -7512,7 +7472,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
// If we have template arguments, rebuild them, then rebuild the
// templateid expression.
TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
- if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
+ if (Old->hasExplicitTemplateArgs() &&
+ getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
Old->getNumTemplateArgs(),
TransArgs))
return ExprError();
@@ -7732,6 +7693,14 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *E) {
+ return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand*/false);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *E,
+ bool IsAddressOfOperand) {
NestedNameSpecifierLoc QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
if (!QualifierLoc)
@@ -7758,7 +7727,8 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
TemplateKWLoc,
NameInfo,
- /*TemplateArgs*/ 0);
+ /*TemplateArgs*/ 0,
+ IsAddressOfOperand);
}
TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
@@ -7770,7 +7740,8 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
TemplateKWLoc,
NameInfo,
- &TransArgs);
+ &TransArgs,
+ IsAddressOfOperand);
}
template<typename Derived>
@@ -7796,7 +7767,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
return ExprError();
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
return ExprError();
@@ -7813,7 +7784,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
Constructor, E->isElidable(),
- move_arg(Args),
+ Args,
E->hadMultipleCandidates(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
@@ -7857,7 +7828,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return ExprError();
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
Args.reserve(E->getNumArgs());
if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
@@ -7874,19 +7845,13 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return getDerived().RebuildCXXTemporaryObjectExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
- move_arg(Args),
+ Args,
E->getLocEnd());
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- // Create the local class that will describe the lambda.
- CXXRecordDecl *Class
- = getSema().createLambdaClosureType(E->getIntroducerRange(),
- /*KnownDependent=*/false);
- getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
-
// Transform the type of the lambda parameters and start the definition of
// the lambda itself.
TypeSourceInfo *MethodTy
@@ -7894,6 +7859,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (!MethodTy)
return ExprError();
+ // Create the local class that will describe the lambda.
+ CXXRecordDecl *Class
+ = getSema().createLambdaClosureType(E->getIntroducerRange(),
+ MethodTy,
+ /*KnownDependent=*/false);
+ getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
+
// Transform lambda parameters.
llvm::SmallVector<QualType, 4> ParamTypes;
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -8038,7 +8010,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
return ExprError();
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
Args.reserve(E->arg_size());
if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args,
&ArgumentChanged))
@@ -8052,7 +8024,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
// FIXME: we're faking the locations of the commas
return getDerived().RebuildCXXUnresolvedConstructExpr(T,
E->getLParenLoc(),
- move_arg(Args),
+ Args,
E->getRParenLoc());
}
@@ -8346,6 +8318,13 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ // Default behavior is to do nothing with this transformation.
+ return SemaRef.Owned(E);
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
MaterializeTemporaryExpr *E) {
return getDerived().TransformExpr(E->GetTemporaryExpr());
@@ -8576,7 +8555,7 @@ ExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// Transform arguments.
bool ArgChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
Args.reserve(E->getNumArgs());
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args,
&ArgChanged))
@@ -8602,7 +8581,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
SelLocs,
E->getMethodDecl(),
E->getLeftLoc(),
- move_arg(Args),
+ Args,
E->getRightLoc());
}
@@ -8627,7 +8606,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
SelLocs,
E->getMethodDecl(),
E->getLeftLoc(),
- move_arg(Args),
+ Args,
E->getRightLoc());
}
@@ -8740,7 +8719,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> SubExprs(SemaRef);
+ SmallVector<Expr*, 8> SubExprs;
SubExprs.reserve(E->getNumSubExprs());
if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
SubExprs, &ArgumentChanged))
@@ -8751,7 +8730,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
return SemaRef.Owned(E);
return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(),
- move_arg(SubExprs),
+ SubExprs,
E->getRParenLoc());
}
@@ -8854,7 +8833,7 @@ ExprResult
TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
QualType RetTy = getDerived().TransformType(E->getType());
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> SubExprs(SemaRef);
+ SmallVector<Expr*, 8> SubExprs;
SubExprs.reserve(E->getNumSubExprs());
if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
SubExprs, &ArgumentChanged))
@@ -8864,7 +8843,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
!ArgumentChanged)
return SemaRef.Owned(E);
- return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs),
+ return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs,
RetTy, E->getOp(), E->getRParenLoc());
}
@@ -9185,7 +9164,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (Result.isInvalid())
return ExprError();
- return move(Result);
+ return Result;
}
}
@@ -9200,7 +9179,12 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// IsAcceptableNonMemberOperatorCandidate for each of these?
Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
- Functions.addDecl(cast<DeclRefExpr>(Callee)->getDecl());
+ // If we've resolved this to a particular non-member function, just call
+ // that function. If we resolved it to a member function,
+ // CreateOverloaded* will find that function for us.
+ NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl();
+ if (!isa<CXXMethodDecl>(ND))
+ Functions.addDecl(ND);
}
// Add any functions found via argument-dependent lookup.
@@ -9240,7 +9224,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (Result.isInvalid())
return ExprError();
- return move(Result);
+ return Result;
}
template<typename Derived>
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 67f74f7d7a51..0ec03cfe1e68 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -60,6 +60,9 @@ 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::BuiltinFn:
+ ID = PREDEF_TYPE_BUILTIN_FN; break;
+
}
return TypeIdx(ID);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 3adbc5783397..deba302e2138 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -30,13 +30,16 @@
#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/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 "llvm/ADT/StringExtras.h"
@@ -62,353 +65,306 @@ using namespace clang::serialization::reader;
ASTReaderListener::~ASTReaderListener() {}
-bool
-PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
- const LangOptions &PPLangOpts = PP.getLangOpts();
-
-#define LANGOPT(Name, Bits, Default, Description) \
- if (PPLangOpts.Name != LangOpts.Name) { \
- Reader.Diag(diag::err_pch_langopt_mismatch) \
- << Description << LangOpts.Name << PPLangOpts.Name; \
+/// \brief Compare the given set of language options against an existing set of
+/// language options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the languagae options mis-match, false otherwise.
+static bool checkLanguageOptions(const LangOptions &LangOpts,
+ const LangOptions &ExistingLangOpts,
+ DiagnosticsEngine *Diags) {
+#define LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_mismatch) \
+ << Description << LangOpts.Name << ExistingLangOpts.Name; \
+ return true; \
+ }
+
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
return true; \
}
-#define VALUE_LANGOPT(Name, Bits, Default, Description) \
- if (PPLangOpts.Name != LangOpts.Name) { \
- Reader.Diag(diag::err_pch_langopt_value_mismatch) \
- << Description; \
- return true; \
-}
-
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- if (PPLangOpts.get##Name() != LangOpts.get##Name()) { \
- Reader.Diag(diag::err_pch_langopt_value_mismatch) \
- << Description; \
- return true; \
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
}
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- if (PPLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
- Reader.Diag(diag::err_pch_langopt_value_mismatch)
+ if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
<< "target Objective-C runtime";
return true;
}
-
+
return false;
}
-bool PCHValidator::ReadTargetTriple(StringRef Triple) {
- if (Triple == PP.getTargetInfo().getTriple().str())
- return false;
-
- Reader.Diag(diag::warn_pch_target_triple)
- << Triple << PP.getTargetInfo().getTriple().str();
- return true;
-}
+/// \brief Compare the given set of target options against an existing set of
+/// target options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the target options mis-match, false otherwise.
+static bool checkTargetOptions(const TargetOptions &TargetOpts,
+ const TargetOptions &ExistingTargetOpts,
+ DiagnosticsEngine *Diags) {
+#define CHECK_TARGET_OPT(Field, Name) \
+ if (TargetOpts.Field != ExistingTargetOpts.Field) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_targetopt_mismatch) \
+ << Name << TargetOpts.Field << ExistingTargetOpts.Field; \
+ return true; \
+ }
+
+ CHECK_TARGET_OPT(Triple, "target");
+ CHECK_TARGET_OPT(CPU, "target CPU");
+ CHECK_TARGET_OPT(ABI, "target ABI");
+ CHECK_TARGET_OPT(CXXABI, "target C++ ABI");
+ CHECK_TARGET_OPT(LinkerVersion, "target linker version");
+#undef CHECK_TARGET_OPT
+
+ // Compare feature sets.
+ SmallVector<StringRef, 4> ExistingFeatures(
+ ExistingTargetOpts.FeaturesAsWritten.begin(),
+ ExistingTargetOpts.FeaturesAsWritten.end());
+ SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
+ TargetOpts.FeaturesAsWritten.end());
+ std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
+ std::sort(ReadFeatures.begin(), ReadFeatures.end());
+
+ unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
+ unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
+ while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
+ if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
+ ++ExistingIdx;
+ ++ReadIdx;
+ continue;
+ }
-namespace {
- struct EmptyStringRef {
- bool operator ()(StringRef r) const { return r.empty(); }
- };
- struct EmptyBlock {
- bool operator ()(const PCHPredefinesBlock &r) const {return r.Data.empty();}
- };
-}
+ if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << false << ReadFeatures[ReadIdx];
+ return true;
+ }
-static bool EqualConcatenations(SmallVector<StringRef, 2> L,
- PCHPredefinesBlocks R) {
- // First, sum up the lengths.
- unsigned LL = 0, RL = 0;
- for (unsigned I = 0, N = L.size(); I != N; ++I) {
- LL += L[I].size();
- }
- for (unsigned I = 0, N = R.size(); I != N; ++I) {
- RL += R[I].Data.size();
- }
- if (LL != RL)
- return false;
- if (LL == 0 && RL == 0)
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << true << ExistingFeatures[ExistingIdx];
return true;
-
- // Kick out empty parts, they confuse the algorithm below.
- L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end());
- R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end());
-
- // Do it the hard way. At this point, both vectors must be non-empty.
- StringRef LR = L[0], RR = R[0].Data;
- unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size();
- (void) RN;
- for (;;) {
- // Compare the current pieces.
- if (LR.size() == RR.size()) {
- // If they're the same length, it's pretty easy.
- if (LR != RR)
- return false;
- // Both pieces are done, advance.
- ++LI;
- ++RI;
- // If either string is done, they're both done, since they're the same
- // length.
- if (LI == LN) {
- assert(RI == RN && "Strings not the same length after all?");
- return true;
- }
- LR = L[LI];
- RR = R[RI].Data;
- } else if (LR.size() < RR.size()) {
- // Right piece is longer.
- if (!RR.startswith(LR))
- return false;
- ++LI;
- assert(LI != LN && "Strings not the same length after all?");
- RR = RR.substr(LR.size());
- LR = L[LI];
- } else {
- // Left piece is longer.
- if (!LR.startswith(RR))
- return false;
- ++RI;
- assert(RI != RN && "Strings not the same length after all?");
- LR = LR.substr(RR.size());
- RR = R[RI].Data;
- }
}
-}
-static std::pair<FileID, StringRef::size_type>
-FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) {
- std::pair<FileID, StringRef::size_type> Res;
- for (unsigned I = 0, N = Buffers.size(); I != N; ++I) {
- Res.second = Buffers[I].Data.find(MacroDef);
- if (Res.second != StringRef::npos) {
- Res.first = Buffers[I].BufferID;
- break;
- }
+ if (ExistingIdx < ExistingN) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << true << ExistingFeatures[ExistingIdx];
+ return true;
}
- return Res;
-}
-
-bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- StringRef OriginalFileName,
- std::string &SuggestedPredefines,
- FileManager &FileMgr) {
- // We are in the context of an implicit include, so the predefines buffer will
- // have a #include entry for the PCH file itself (as normalized by the
- // preprocessor initialization). Find it and skip over it in the checking
- // below.
- SmallString<256> PCHInclude;
- PCHInclude += "#include \"";
- PCHInclude += HeaderSearch::NormalizeDashIncludePath(OriginalFileName,
- FileMgr);
- PCHInclude += "\"\n";
- std::pair<StringRef,StringRef> Split =
- StringRef(PP.getPredefines()).split(PCHInclude.str());
- StringRef Left = Split.first, Right = Split.second;
- if (Left == PP.getPredefines()) {
- Error("Missing PCH include entry!");
+
+ if (ReadIdx < ReadN) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << false << ReadFeatures[ReadIdx];
return true;
}
- // If the concatenation of all the PCH buffers is equal to the adjusted
- // command line, we're done.
- SmallVector<StringRef, 2> CommandLine;
- CommandLine.push_back(Left);
- CommandLine.push_back(Right);
- if (EqualConcatenations(CommandLine, Buffers))
- return false;
+ return false;
+}
- SourceManager &SourceMgr = PP.getSourceManager();
-
- // The predefines buffers are different. Determine what the differences are,
- // and whether they require us to reject the PCH file.
- SmallVector<StringRef, 8> PCHLines;
- for (unsigned I = 0, N = Buffers.size(); I != N; ++I)
- Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
-
- SmallVector<StringRef, 8> CmdLineLines;
- Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
-
- // Pick out implicit #includes after the PCH and don't consider them for
- // validation; we will insert them into SuggestedPredefines so that the
- // preprocessor includes them.
- std::string IncludesAfterPCH;
- SmallVector<StringRef, 8> AfterPCHLines;
- Right.split(AfterPCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- for (unsigned i = 0, e = AfterPCHLines.size(); i != e; ++i) {
- if (AfterPCHLines[i].startswith("#include ")) {
- IncludesAfterPCH += AfterPCHLines[i];
- IncludesAfterPCH += '\n';
- } else {
- CmdLineLines.push_back(AfterPCHLines[i]);
- }
- }
-
- // Make sure we add the includes last into SuggestedPredefines before we
- // exit this function.
- struct AddIncludesRAII {
- std::string &SuggestedPredefines;
- std::string &IncludesAfterPCH;
-
- AddIncludesRAII(std::string &SuggestedPredefines,
- std::string &IncludesAfterPCH)
- : SuggestedPredefines(SuggestedPredefines),
- IncludesAfterPCH(IncludesAfterPCH) { }
- ~AddIncludesRAII() {
- SuggestedPredefines += IncludesAfterPCH;
- }
- } AddIncludes(SuggestedPredefines, IncludesAfterPCH);
-
- // Sort both sets of predefined buffer lines, since we allow some extra
- // definitions and they may appear at any point in the output.
- std::sort(CmdLineLines.begin(), CmdLineLines.end());
- std::sort(PCHLines.begin(), PCHLines.end());
-
- // Determine which predefines that were used to build the PCH file are missing
- // from the command line.
- std::vector<StringRef> MissingPredefines;
- std::set_difference(PCHLines.begin(), PCHLines.end(),
- CmdLineLines.begin(), CmdLineLines.end(),
- std::back_inserter(MissingPredefines));
-
- bool MissingDefines = false;
- bool ConflictingDefines = false;
- for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
- StringRef Missing = MissingPredefines[I];
- if (Missing.startswith("#include ")) {
- // An -include was specified when generating the PCH; it is included in
- // the PCH, just ignore it.
- continue;
- }
- if (!Missing.startswith("#define ")) {
- Reader.Diag(diag::warn_pch_compiler_options_mismatch);
- return true;
- }
+bool
+PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ const LangOptions &ExistingLangOpts = PP.getLangOpts();
+ return checkLanguageOptions(LangOpts, ExistingLangOpts,
+ Complain? &Reader.Diags : 0);
+}
- // This is a macro definition. Determine the name of the macro we're
- // defining.
- std::string::size_type StartOfMacroName = strlen("#define ");
- std::string::size_type EndOfMacroName
- = Missing.find_first_of("( \n\r", StartOfMacroName);
- assert(EndOfMacroName != std::string::npos &&
- "Couldn't find the end of the macro name");
- StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
-
- // Determine whether this macro was given a different definition on the
- // command line.
- std::string MacroDefStart = "#define " + MacroName.str();
- std::string::size_type MacroDefLen = MacroDefStart.size();
- SmallVector<StringRef, 8>::iterator ConflictPos
- = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
- MacroDefStart);
- for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
- if (!ConflictPos->startswith(MacroDefStart)) {
- // Different macro; we're done.
- ConflictPos = CmdLineLines.end();
- break;
- }
+bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
+ return checkTargetOptions(TargetOpts, ExistingTargetOpts,
+ Complain? &Reader.Diags : 0);
+}
- assert(ConflictPos->size() > MacroDefLen &&
- "Invalid #define in predefines buffer?");
- if ((*ConflictPos)[MacroDefLen] != ' ' &&
- (*ConflictPos)[MacroDefLen] != '(')
- continue; // Longer macro name; keep trying.
+namespace {
+ typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
+ MacroDefinitionsMap;
+}
- // We found a conflicting macro definition.
- break;
- }
+/// \brief Collect the macro definitions provided by the given preprocessor
+/// options.
+static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
+ MacroDefinitionsMap &Macros,
+ SmallVectorImpl<StringRef> *MacroNames = 0){
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ StringRef Macro = PPOpts.Macros[I].first;
+ bool IsUndef = PPOpts.Macros[I].second;
- if (ConflictPos != CmdLineLines.end()) {
- Reader.Diag(diag::warn_cmdline_conflicting_macro_def)
- << MacroName;
+ std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
+ StringRef MacroName = MacroPair.first;
+ StringRef MacroBody = MacroPair.second;
- // Show the definition of this macro within the PCH file.
- std::pair<FileID, StringRef::size_type> MacroLoc =
- FindMacro(Buffers, Missing);
- assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!");
- SourceLocation PCHMissingLoc =
- SourceMgr.getLocForStartOfFile(MacroLoc.first)
- .getLocWithOffset(MacroLoc.second);
- Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
+ // For an #undef'd macro, we only care about the name.
+ if (IsUndef) {
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
- ConflictingDefines = true;
+ Macros[MacroName] = std::make_pair("", true);
continue;
}
- // If the macro doesn't conflict, then we'll just pick up the macro
- // definition from the PCH file. Warn the user that they made a mistake.
- if (ConflictingDefines)
- continue; // Don't complain if there are already conflicting defs
-
- if (!MissingDefines) {
- Reader.Diag(diag::warn_cmdline_missing_macro_defs);
- MissingDefines = true;
+ // For a #define'd macro, figure out the actual definition.
+ if (MacroName.size() == Macro.size())
+ MacroBody = "1";
+ else {
+ // Note: GCC drops anything following an end-of-line character.
+ StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ MacroBody = MacroBody.substr(0, End);
}
- // Show the definition of this macro within the PCH file.
- std::pair<FileID, StringRef::size_type> MacroLoc =
- FindMacro(Buffers, Missing);
- assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!");
- SourceLocation PCHMissingLoc =
- SourceMgr.getLocForStartOfFile(MacroLoc.first)
- .getLocWithOffset(MacroLoc.second);
- Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
+ Macros[MacroName] = std::make_pair(MacroBody, false);
}
+}
+
+/// \brief Check the preprocessor options deserialized from the control block
+/// against the preprocessor options in an existing preprocessor.
+///
+/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
+static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ DiagnosticsEngine *Diags,
+ FileManager &FileMgr,
+ std::string &SuggestedPredefines) {
+ // Check macro definitions.
+ MacroDefinitionsMap ASTFileMacros;
+ collectMacroDefinitions(PPOpts, ASTFileMacros);
+ MacroDefinitionsMap ExistingMacros;
+ SmallVector<StringRef, 4> ExistingMacroNames;
+ collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
+
+ for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
+ // Dig out the macro definition in the existing preprocessor options.
+ StringRef MacroName = ExistingMacroNames[I];
+ std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
+
+ // Check whether we know anything about this macro name or not.
+ llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known
+ = ASTFileMacros.find(MacroName);
+ if (Known == ASTFileMacros.end()) {
+ // FIXME: Check whether this identifier was referenced anywhere in the
+ // AST file. If so, we should reject the AST file. Unfortunately, this
+ // information isn't in the control block. What shall we do about it?
+
+ if (Existing.second) {
+ SuggestedPredefines += "#undef ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += '\n';
+ } else {
+ SuggestedPredefines += "#define ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += ' ';
+ SuggestedPredefines += Existing.first.str();
+ SuggestedPredefines += '\n';
+ }
+ continue;
+ }
- if (ConflictingDefines)
- return true;
-
- // Determine what predefines were introduced based on command-line
- // parameters that were not present when building the PCH
- // file. Extra #defines are okay, so long as the identifiers being
- // defined were not used within the precompiled header.
- std::vector<StringRef> ExtraPredefines;
- std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
- PCHLines.begin(), PCHLines.end(),
- std::back_inserter(ExtraPredefines));
- for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
- StringRef &Extra = ExtraPredefines[I];
- if (!Extra.startswith("#define ")) {
- Reader.Diag(diag::warn_pch_compiler_options_mismatch);
+ // If the macro was defined in one but undef'd in the other, we have a
+ // conflict.
+ if (Existing.second != Known->second.second) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_undef)
+ << MacroName << Known->second.second;
+ }
return true;
}
- // This is an extra macro definition. Determine the name of the
- // macro we're defining.
- std::string::size_type StartOfMacroName = strlen("#define ");
- std::string::size_type EndOfMacroName
- = Extra.find_first_of("( \n\r", StartOfMacroName);
- assert(EndOfMacroName != std::string::npos &&
- "Couldn't find the end of the macro name");
- StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
-
- // Check whether this name was used somewhere in the PCH file. If
- // so, defining it as a macro could change behavior, so we reject
- // the PCH file.
- if (IdentifierInfo *II = Reader.get(MacroName)) {
- Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
- return true;
+ // If the macro was #undef'd in both, or if the macro bodies are identical,
+ // it's fine.
+ if (Existing.second || Existing.first == Known->second.first)
+ continue;
+
+ // The macro bodies differ; complain.
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_conflict)
+ << MacroName << Known->second.first << Existing.first;
}
+ return true;
+ }
- // Add this definition to the suggested predefines buffer.
- SuggestedPredefines += Extra;
- SuggestedPredefines += '\n';
+ // Check whether we're using predefines.
+ if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
+ }
+ return true;
+ }
+
+ // Compute the #include and #include_macros lines we need.
+ for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.Includes[I];
+ if (File == ExistingPPOpts.ImplicitPCHInclude)
+ continue;
+
+ if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File)
+ != PPOpts.Includes.end())
+ continue;
+
+ SuggestedPredefines += "#include \"";
+ SuggestedPredefines +=
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += "\"\n";
+ }
+
+ for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.MacroIncludes[I];
+ if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(),
+ File)
+ != PPOpts.MacroIncludes.end())
+ continue;
+
+ SuggestedPredefines += "#__include_macros \"";
+ SuggestedPredefines +=
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += "\"\n##\n";
}
- // If we get here, it's because the predefines buffer had compatible
- // contents. Accept the PCH file.
return false;
}
+bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
+
+ return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
+ Complain? &Reader.Diags : 0,
+ PP.getFileManager(),
+ SuggestedPredefines);
+}
+
void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
unsigned ID) {
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
++NumHeaderInfos;
}
-void PCHValidator::ReadCounter(unsigned Value) {
+void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
PP.setCounterValue(Value);
}
@@ -527,6 +483,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
return II;
}
+ unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d);
unsigned Bits = ReadUnalignedLE16(d);
bool CPlusPlusOperatorKeyword = Bits & 0x01;
Bits >>= 1;
@@ -536,13 +493,11 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
Bits >>= 1;
bool ExtensionToken = Bits & 0x01;
Bits >>= 1;
- bool hasMacroDefinition = Bits & 0x01;
+ bool hadMacroDefinition = Bits & 0x01;
Bits >>= 1;
- unsigned ObjCOrBuiltinID = Bits & 0x7FF;
- Bits >>= 11;
assert(Bits == 0 && "Extra bits in the identifier?");
- DataLen -= 6;
+ DataLen -= 8;
// Build the IdentifierInfo itself and link the identifier ID with
// the new IdentifierInfo.
@@ -570,31 +525,14 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// If this identifier is a macro, deserialize the macro
// definition.
- if (hasMacroDefinition) {
- // FIXME: Check for conflicts?
- uint32_t Offset = ReadUnalignedLE32(d);
- unsigned LocalSubmoduleID = ReadUnalignedLE32(d);
-
- // Determine whether this macro definition should be visible now, or
- // whether it is in a hidden submodule.
- bool Visible = true;
- if (SubmoduleID GlobalSubmoduleID
- = Reader.getGlobalSubmoduleID(F, LocalSubmoduleID)) {
- if (Module *Owner = Reader.getSubmodule(GlobalSubmoduleID)) {
- if (Owner->NameVisibility == Module::Hidden) {
- // The owning module is not visible, and this macro definition should
- // not be, either.
- Visible = false;
-
- // Note that this macro definition was hidden because its owning
- // module is not yet visible.
- Reader.HiddenNamesMap[Owner].push_back(II);
- }
- }
+ if (hadMacroDefinition) {
+ SmallVector<MacroID, 4> MacroIDs;
+ while (uint32_t LocalID = ReadUnalignedLE32(d)) {
+ MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID));
+ DataLen -= 4;
}
-
- Reader.setIdentifierIsMacro(II, F, Offset, Visible);
- DataLen -= 8;
+ DataLen -= 4;
+ Reader.setIdentifierIsMacro(II, MacroIDs);
}
Reader.SetIdentifierInfo(ID, II);
@@ -780,16 +718,6 @@ void ASTReader::Error(unsigned DiagID,
Diag(DiagID) << Arg1 << Arg2;
}
-/// \brief Tell the AST listener about the predefines buffers in the chain.
-bool ASTReader::CheckPredefinesBuffers() {
- if (Listener)
- return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
- ActualOriginalFileName,
- SuggestedPredefines,
- FileMgr);
- return false;
-}
-
//===----------------------------------------------------------------------===//
// Source Manager Deserialization
//===----------------------------------------------------------------------===//
@@ -808,7 +736,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
unsigned FilenameLen = Record[Idx++];
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
Idx += FilenameLen;
- MaybeAddSystemRootToFilename(Filename);
+ MaybeAddSystemRootToFilename(F, Filename);
FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
}
@@ -841,106 +769,8 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
return false;
}
-namespace {
-
-class ASTStatData {
-public:
- const ino_t ino;
- const dev_t dev;
- const mode_t mode;
- const time_t mtime;
- const off_t size;
-
- ASTStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
- : ino(i), dev(d), mode(mo), mtime(m), size(s) {}
-};
-
-class ASTStatLookupTrait {
- public:
- typedef const char *external_key_type;
- typedef const char *internal_key_type;
-
- typedef ASTStatData data_type;
-
- static unsigned ComputeHash(const char *path) {
- return llvm::HashString(path);
- }
-
- static internal_key_type GetInternalKey(const char *path) { return path; }
-
- static bool EqualKey(internal_key_type a, internal_key_type b) {
- return strcmp(a, b) == 0;
- }
-
- static std::pair<unsigned, unsigned>
- ReadKeyDataLength(const unsigned char*& d) {
- unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
- unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
- }
-
- static internal_key_type ReadKey(const unsigned char *d, unsigned) {
- return (const char *)d;
- }
-
- static data_type ReadData(const internal_key_type, const unsigned char *d,
- unsigned /*DataLen*/) {
- using namespace clang::io;
-
- ino_t ino = (ino_t) ReadUnalignedLE32(d);
- dev_t dev = (dev_t) ReadUnalignedLE32(d);
- mode_t mode = (mode_t) ReadUnalignedLE16(d);
- time_t mtime = (time_t) ReadUnalignedLE64(d);
- off_t size = (off_t) ReadUnalignedLE64(d);
- return data_type(ino, dev, mode, mtime, size);
- }
-};
-
-/// \brief stat() cache for precompiled headers.
-///
-/// This cache is very similar to the stat cache used by pretokenized
-/// headers.
-class ASTStatCache : public FileSystemStatCache {
- typedef OnDiskChainedHashTable<ASTStatLookupTrait> CacheTy;
- CacheTy *Cache;
-
- unsigned &NumStatHits, &NumStatMisses;
-public:
- ASTStatCache(const unsigned char *Buckets, const unsigned char *Base,
- unsigned &NumStatHits, unsigned &NumStatMisses)
- : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
- Cache = CacheTy::Create(Buckets, Base);
- }
-
- ~ASTStatCache() { delete Cache; }
-
- LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
- // Do the lookup for the file's data in the AST file.
- CacheTy::iterator I = Cache->find(Path);
-
- // If we don't get a hit in the AST file just forward to 'stat'.
- if (I == Cache->end()) {
- ++NumStatMisses;
- return statChained(Path, StatBuf, FileDescriptor);
- }
-
- ++NumStatHits;
- ASTStatData Data = *I;
-
- StatBuf.st_ino = Data.ino;
- StatBuf.st_dev = Data.dev;
- StatBuf.st_mtime = Data.mtime;
- StatBuf.st_mode = Data.mode;
- StatBuf.st_size = Data.size;
- return CacheExists;
- }
-};
-} // end anonymous namespace
-
-
/// \brief Read a source manager block
-ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
+bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
@@ -954,13 +784,13 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
// The stream itself is going to skip over the source manager block.
if (F.Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
// Enter the source manager block.
if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) {
Error("malformed source manager block record in AST file");
- return Failure;
+ return true;
}
RecordData Record;
@@ -969,9 +799,9 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
if (Code == llvm::bitc::END_BLOCK) {
if (SLocEntryCursor.ReadBlockEnd()) {
Error("error at end of Source Manager block in AST file");
- return Failure;
+ return true;
}
- return Success;
+ return false;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
@@ -979,7 +809,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
SLocEntryCursor.ReadSubBlockID();
if (SLocEntryCursor.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
continue;
}
@@ -1001,7 +831,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
case SM_SLOC_BUFFER_ENTRY:
case SM_SLOC_EXPANSION_ENTRY:
// Once we hit one of the source location entries, we're done.
- return Success;
+ return false;
}
}
}
@@ -1039,14 +869,13 @@ resolveFileRelativeToOriginalDir(const std::string &Filename,
return currPCHPath.str();
}
-/// \brief Read in the source location entry with the given ID.
-ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
+bool ASTReader::ReadSLocEntry(int ID) {
if (ID == 0)
- return Success;
+ return false;
if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
Error("source location entry ID out-of-range for AST file");
- return Failure;
+ return true;
}
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
@@ -1060,7 +889,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
Code == llvm::bitc::ENTER_SUBBLOCK ||
Code == llvm::bitc::DEFINE_ABBREV) {
Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ return true;
}
RecordData Record;
@@ -1069,58 +898,18 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
default:
Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ return true;
case SM_SLOC_FILE_ENTRY: {
- if (Record.size() < 7) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
// We will detect whether a file changed and return 'Failure' for it, but
// we will also try to fail gracefully by setting up the SLocEntry.
- ASTReader::ASTReadResult Result = Success;
-
- bool OverriddenBuffer = Record[6];
-
- std::string OrigFilename(BlobStart, BlobStart + BlobLen);
- std::string Filename = OrigFilename;
- MaybeAddSystemRootToFilename(Filename);
- const FileEntry *File =
- OverriddenBuffer? FileMgr.getVirtualFile(Filename, (off_t)Record[4],
- (time_t)Record[5])
- : FileMgr.getFile(Filename, /*OpenFile=*/false);
- if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
- OriginalDir != CurrentDir) {
- std::string resolved = resolveFileRelativeToOriginalDir(Filename,
- OriginalDir,
- CurrentDir);
- if (!resolved.empty())
- File = FileMgr.getFile(resolved);
- }
- if (File == 0)
- File = FileMgr.getVirtualFile(Filename, (off_t)Record[4],
- (time_t)Record[5]);
- if (File == 0) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- return Failure;
- }
+ unsigned InputID = Record[4];
+ InputFile IF = getInputFile(*F, InputID);
+ const FileEntry *File = IF.getPointer();
+ bool OverriddenBuffer = IF.getInt();
- if (!DisableValidation &&
- ((off_t)Record[4] != 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.
- || (time_t)Record[5] != File->getModificationTime()
-#endif
- )) {
- Error(diag::err_fe_pch_file_modified, Filename);
- Result = Failure;
- }
+ if (!IF.getPointer())
+ return true;
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
@@ -1133,12 +922,12 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
ID, BaseOffset + Record[0]);
SrcMgr::FileInfo &FileInfo =
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
- FileInfo.NumCreatedFIDs = Record[7];
+ FileInfo.NumCreatedFIDs = Record[5];
if (Record[3])
FileInfo.setHasLineDirectives();
- const DeclID *FirstDecl = F->FileSortedDecls + Record[8];
- unsigned NumFileDecls = Record[9];
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
+ unsigned NumFileDecls = Record[7];
if (NumFileDecls) {
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
@@ -1157,23 +946,24 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
- return Failure;
+ return true;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Filename);
+ File->getName());
SourceMgr.overrideFileContents(File, Buffer);
}
- if (Result == Failure)
- return Failure;
break;
}
case SM_SLOC_BUFFER_ENTRY: {
const char *Name = BlobStart;
unsigned Offset = Record[0];
+ SrcMgr::CharacteristicKind
+ FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode
@@ -1181,23 +971,14 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
- return Failure;
+ return true;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
Name);
- FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID,
- BaseOffset + Offset);
-
- if (strcmp(Name, "<built-in>") == 0 && F->Kind == MK_PCH) {
- PCHPredefinesBlock Block = {
- BufferID,
- StringRef(BlobStart, BlobLen - 1)
- };
- PCHPredefinesBuffers.push_back(Block);
- }
-
+ SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
+ BaseOffset + Offset, IncludeLoc);
break;
}
@@ -1213,7 +994,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
}
}
- return Success;
+ return false;
}
/// \brief Find the location where the module F is imported.
@@ -1258,7 +1039,8 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
}
-void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
+void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
+ MacroInfo *Hint) {
llvm::BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
@@ -1270,6 +1052,24 @@ 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) {
@@ -1312,18 +1112,31 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
Error("macro must have a name in AST file");
return;
}
-
- SourceLocation Loc = ReadSourceLocation(F, Record[1]);
- bool isUsed = Record[2];
+ 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;
+ SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
MacroInfo *MI = PP.AllocateMacroInfo(Loc);
- MI->setIsUsed(isUsed);
+
+ // Record this macro.
+ MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI;
+
+ SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex);
+ if (UndefLoc.isValid())
+ MI->setUndefLoc(UndefLoc);
+
+ MI->setIsUsed(Record[NextIndex++]);
MI->setIsFromAST();
- bool IsPublic = Record[3];
- unsigned NextIndex = 4;
+ 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++];
@@ -1341,8 +1154,60 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
PP.getPreprocessorAllocator());
}
- // Finally, install the macro.
- PP.setMacroInfo(II, MI, /*LoadedFromAST=*/true);
+ 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.
@@ -1451,18 +1316,16 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
return HFI;
}
-void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F,
- uint64_t LocalOffset, bool Visible) {
- if (Visible) {
- // Note that this identifier has a macro definition.
- II->setHasMacroDefinition(true);
- }
-
- // Adjust the offset to a global offset.
- UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset;
+void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){
+ II->setHadMacroDefinition(true);
+ assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
+ PendingMacroIDs[II].append(IDs.begin(), IDs.end());
}
void ASTReader::ReadDefinedMacros() {
+ // Note that we are loading defined macros.
+ Deserializing Macros(this);
+
for (ModuleReverseIterator I = ModuleMgr.rbegin(),
E = ModuleMgr.rend(); I != E; ++I) {
llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
@@ -1514,26 +1377,6 @@ void ASTReader::ReadDefinedMacros() {
}
}
}
-
- // Drain the unread macro-record offsets map.
- while (!UnreadMacroRecordOffsets.empty())
- LoadMacroDefinition(UnreadMacroRecordOffsets.begin());
-}
-
-void ASTReader::LoadMacroDefinition(
- llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) {
- assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition");
- uint64_t Offset = Pos->second;
- UnreadMacroRecordOffsets.erase(Pos);
-
- RecordLocation Loc = getLocalBitOffset(Offset);
- ReadMacroRecord(*Loc.F, Loc.Offset);
-}
-
-void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {
- llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos
- = UnreadMacroRecordOffsets.find(II);
- LoadMacroDefinition(Pos);
}
namespace {
@@ -1582,6 +1425,9 @@ namespace {
}
void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
unsigned PriorGeneration = 0;
if (getContext().getLangOpts().Modules)
PriorGeneration = IdentifierGeneration[&II];
@@ -1602,14 +1448,132 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
IdentifierGeneration[II] = CurrentGeneration;
}
+llvm::PointerIntPair<const FileEntry *, 1, bool>
+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())
+ return F.InputFilesLoaded[ID-1];
+
+ // Go find this input file.
+ llvm::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)) {
+ case INPUT_FILE: {
+ unsigned StoredID = Record[0];
+ assert(ID == StoredID && "Bogus stored ID or offset");
+ (void)StoredID;
+ off_t StoredSize = (off_t)Record[1];
+ time_t StoredTime = (time_t)Record[2];
+ bool Overridden = (bool)Record[3];
+
+ // Get the file entry for this input file.
+ StringRef OrigFilename(BlobStart, BlobLen);
+ std::string Filename = OrigFilename;
+ MaybeAddSystemRootToFilename(F, Filename);
+ const FileEntry *File
+ = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
+ : FileMgr.getFile(Filename, /*OpenFile=*/false);
+
+ // If we didn't find the file, resolve it relative to the
+ // original directory from which this AST file was created.
+ if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() &&
+ F.OriginalDir != CurrentDir) {
+ std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
+ F.OriginalDir,
+ CurrentDir);
+ if (!Resolved.empty())
+ File = FileMgr.getFile(Resolved);
+ }
+
+ // For an overridden file, create a virtual file with the stored
+ // size/timestamp.
+ if (Overridden && File == 0) {
+ File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
+ }
+
+ if (File == 0) {
+ if (Complain) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ }
+ return InputFile();
+ }
+
+ // 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);
+ // After emitting the diagnostic, recover by disabling the override so
+ // that the original file will be used.
+ SM.disableFileContentsOverride(File);
+ // The FileEntry is a virtual file entry with the size of the contents
+ // that would override the original contents. Set it to the original's
+ // size/time.
+ FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
+ StoredSize, StoredTime);
+ }
+
+ // For an overridden file, 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();
+ }
+
+ if ((StoredSize != StatBuf.st_size
+#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
+#endif
+ )) {
+ if (Complain)
+ Error(diag::err_fe_pch_file_modified, Filename);
+
+ return InputFile();
+ }
+
+ return InputFile(File, Overridden);
+ }
+ }
+
+ return InputFile();
+}
+
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
+ ModuleFile &M = ModuleMgr.getPrimaryModule();
std::string Filename = filenameStrRef;
- MaybeAddSystemRootToFilename(Filename);
+ MaybeAddSystemRootToFilename(M, Filename);
const FileEntry *File = FileMgr.getFile(Filename);
- if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
- OriginalDir != CurrentDir) {
+ if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() &&
+ M.OriginalDir != CurrentDir) {
std::string resolved = resolveFileRelativeToOriginalDir(Filename,
- OriginalDir,
+ M.OriginalDir,
CurrentDir);
if (!resolved.empty())
File = FileMgr.getFile(resolved);
@@ -1621,9 +1585,10 @@ const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
-void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) {
+void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
+ std::string &Filename) {
// If this is not a relocatable PCH file, there's nothing to do.
- if (!RelocatablePCH)
+ if (!M.RelocatablePCH)
return;
if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
@@ -1643,29 +1608,226 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) {
}
ASTReader::ASTReadResult
-ASTReader::ReadASTBlock(ModuleFile &F) {
+ASTReader::ReadControlBlock(ModuleFile &F,
+ llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ unsigned ClientLoadCapabilities) {
llvm::BitstreamCursor &Stream = F.Stream;
- if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
- // Read all of the records and blocks for the ASt file.
+ // 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 module block in AST file");
+ Error("error at end of control block in AST file");
return Failure;
}
+ // Validate all of the 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())
+ return OutOfDate;
+ }
+
return Success;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
switch (Stream.ReadSubBlockID()) {
+ case INPUT_FILES_BLOCK_ID:
+ F.InputFilesCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor
+ // Read the abbreviations
+ ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+
+ default:
+ if (!Stream.SkipBlock())
+ continue;
+ break;
+ }
+
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
+ : diag::warn_pch_version_too_new);
+ return VersionMismatch;
+ }
+
+ bool hasErrors = Record[5];
+ if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
+ Diag(diag::err_pch_with_compiler_errors);
+ return HadErrors;
+ }
+
+ F.RelocatablePCH = Record[4];
+
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ StringRef ASTBranch(BlobStart, BlobLen);
+ if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
+ return VersionMismatch;
+ }
+ break;
+ }
+
+ case IMPORTS: {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ ModuleKind ImportedKind = (ModuleKind)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,
+ ClientLoadCapabilities)) {
+ case Failure: return Failure;
+ // If we have to ignore the dependency, we'll have to ignore this too.
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
+ case Success: break;
+ }
+ }
+ break;
+ }
+
+ case LANGUAGE_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseLanguageOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case TARGET_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseTargetOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseDiagnosticOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case FILE_SYSTEM_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseFileSystemOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case HEADER_SEARCH_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseHeaderSearchOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case PREPROCESSOR_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParsePreprocessorOptions(Record, Complain, *Listener,
+ SuggestedPredefines) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case ORIGINAL_FILE:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen);
+ F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
+ MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
+ break;
+
+ case ORIGINAL_PCH_DIR:
+ F.OriginalDir.assign(BlobStart, BlobLen);
+ break;
+
+ case INPUT_FILE_OFFSETS:
+ F.InputFileOffsets = (const uint32_t *)BlobStart;
+ 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;
+
+ if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+
+ // 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;
+ }
+
+ DeclContext *DC = Context.getTranslationUnitDecl();
+ if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ DC->setMustBuildLookupTable();
+
+ return false;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
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
@@ -1676,14 +1838,14 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
// Read the abbrevs.
ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
break;
case DECL_UPDATES_BLOCK_ID:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
break;
@@ -1695,7 +1857,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
@@ -1706,7 +1868,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID)) {
Error("malformed preprocessor detail record in AST file");
- return Failure;
+ return true;
}
F.PreprocessorDetailStartOffset
= F.PreprocessorDetailCursor.GetCurrentBitNo();
@@ -1718,31 +1880,13 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case SOURCE_MANAGER_BLOCK_ID:
- switch (ReadSourceManagerBlock(F)) {
- case Success:
- break;
-
- case Failure:
- Error("malformed source manager block in AST file");
- return Failure;
-
- case IgnorePCH:
- return IgnorePCH;
- }
+ if (ReadSourceManagerBlock(F))
+ return true;
break;
case SUBMODULE_BLOCK_ID:
- switch (ReadSubmoduleBlock(F)) {
- case Success:
- break;
-
- case Failure:
- Error("malformed submodule block in AST file");
- return Failure;
-
- case IgnorePCH:
- return IgnorePCH;
- }
+ if (ReadSubmoduleBlock(F))
+ return true;
break;
case COMMENTS_BLOCK_ID: {
@@ -1750,7 +1894,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
Error("malformed comments block in AST file");
- return Failure;
+ return true;
}
CommentsCursors.push_back(std::make_pair(C, &F));
break;
@@ -1760,7 +1904,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
if (!Stream.SkipBlock())
break;
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
continue;
}
@@ -1779,54 +1923,10 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
default: // Default behavior: ignore.
break;
- case METADATA: {
- if (Record[0] != VERSION_MAJOR && !DisableValidation) {
- Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
- : diag::warn_pch_version_too_new);
- return IgnorePCH;
- }
-
- bool hasErrors = Record[5];
- if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
- Diag(diag::err_pch_with_compiler_errors);
- return IgnorePCH;
- }
-
- RelocatablePCH = Record[4];
- if (Listener) {
- std::string TargetTriple(BlobStart, BlobLen);
- if (Listener->ReadTargetTriple(TargetTriple))
- return IgnorePCH;
- }
- break;
- }
-
- case IMPORTS: {
- // Load each of the imported PCH files.
- unsigned Idx = 0, N = Record.size();
- while (Idx < N) {
- // Read information about the AST file.
- ModuleKind ImportedKind = (ModuleKind)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)) {
- case Failure: return Failure;
- // If we have to ignore the dependency, we'll have to ignore this too.
- case IgnorePCH: return IgnorePCH;
- case Success: break;
- }
- }
- break;
- }
-
case TYPE_OFFSET: {
if (F.LocalNumTypes != 0) {
Error("duplicate TYPE_OFFSET record in AST file");
- return Failure;
+ return true;
}
F.TypeOffsets = (const uint32_t *)BlobStart;
F.LocalNumTypes = Record[0];
@@ -1850,7 +1950,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_OFFSET: {
if (F.LocalNumDecls != 0) {
Error("duplicate DECL_OFFSET record in AST file");
- return Failure;
+ return true;
}
F.DeclOffsets = (const DeclOffset *)BlobStart;
F.LocalNumDecls = Record[0];
@@ -1904,11 +2004,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
break;
}
- case LANGUAGE_OPTIONS:
- if (ParseLanguageOptions(Record) && !DisableValidation)
- return IgnorePCH;
- break;
-
case IDENTIFIER_TABLE:
F.IdentifierTableData = BlobStart;
if (Record[0]) {
@@ -1925,7 +2020,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case IDENTIFIER_OFFSET: {
if (F.LocalNumIdentifiers != 0) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
- return Failure;
+ return true;
}
F.IdentifierOffsets = (const uint32_t *)BlobStart;
F.LocalNumIdentifiers = Record[0];
@@ -1949,7 +2044,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
break;
}
-
+
case EXTERNAL_DEFINITIONS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I]));
@@ -1980,7 +2075,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case WEAK_UNDECLARED_IDENTIFIERS:
if (Record.size() % 4 != 0) {
Error("invalid weak identifiers record");
- return Failure;
+ return true;
}
// FIXME: Ignore weak undeclared identifiers from non-original PCH
@@ -2050,11 +2145,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case PP_COUNTER_VALUE:
if (!Record.empty() && Listener)
- Listener->ReadCounter(Record[0]);
+ Listener->ReadCounter(F, Record[0]);
break;
case FILE_SORTED_DECLS:
F.FileSortedDecls = (const DeclID *)BlobStart;
+ F.NumFileSortedDecls = Record[0];
break;
case SOURCE_LOCATION_OFFSETS: {
@@ -2098,7 +2194,9 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder
IdentifierRemap(F.IdentifierRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ MacroRemap(F.MacroRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
PreprocessedEntityRemap(F.PreprocessedEntityRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder
SubmoduleRemap(F.SubmoduleRemap);
@@ -2114,11 +2212,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
ModuleFile *OM = ModuleMgr.lookup(Name);
if (!OM) {
Error("SourceLocation remap refers to unknown module");
- return Failure;
+ return true;
}
uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data);
uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
@@ -2131,6 +2230,8 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
IdentifierRemap.insert(
std::make_pair(IdentifierIDOffset,
OM->BaseIdentifierID - IdentifierIDOffset));
+ MacroRemap.insert(std::make_pair(MacroIDOffset,
+ OM->BaseMacroID - MacroIDOffset));
PreprocessedEntityRemap.insert(
std::make_pair(PreprocessedEntityIDOffset,
OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
@@ -2152,12 +2253,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case SOURCE_MANAGER_LINE_TABLE:
if (ParseLineTable(F, Record))
- return Failure;
- break;
-
- case FILE_SOURCE_LOCATION_OFFSETS:
- F.SLocFileOffsets = (const uint32_t *)BlobStart;
- F.LocalNumSLocFileEntries = Record[0];
+ return true;
break;
case SOURCE_LOCATION_PRELOADS: {
@@ -2165,25 +2261,13 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
// which is based off F.SLocEntryBaseID.
if (!F.PreloadSLocEntries.empty()) {
Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
- return Failure;
+ return true;
}
F.PreloadSLocEntries.swap(Record);
break;
}
- case STAT_CACHE: {
- if (!DisableStatCache) {
- ASTStatCache *MyStatCache =
- new ASTStatCache((const unsigned char *)BlobStart + Record[0],
- (const unsigned char *)BlobStart,
- NumStatHits, NumStatMisses);
- FileMgr.addStatCache(MyStatCache);
- F.StatCache = MyStatCache;
- }
- break;
- }
-
case EXT_VECTOR_DECLS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
@@ -2192,7 +2276,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case VTABLE_USES:
if (Record.size() % 3 != 0) {
Error("Invalid VTABLE_USES record");
- return Failure;
+ return true;
}
// Later tables overwrite earlier ones.
@@ -2215,13 +2299,15 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case PENDING_IMPLICIT_INSTANTIATIONS:
if (PendingInstantiations.size() % 2 != 0) {
+ Error("Invalid existing PendingInstantiations");
+ return true;
+ }
+
+ if (Record.size() % 2 != 0) {
Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
- return Failure;
+ return true;
}
-
- // Later lists of pending instantiations overwrite earlier ones.
- // FIXME: This is most certainly wrong for modules.
- PendingInstantiations.clear();
+
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
PendingInstantiations.push_back(
@@ -2237,34 +2323,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
break;
- case ORIGINAL_FILE_NAME:
- // The primary AST will be the last to get here, so it will be the one
- // that's used.
- ActualOriginalFileName.assign(BlobStart, BlobLen);
- OriginalFileName = ActualOriginalFileName;
- MaybeAddSystemRootToFilename(OriginalFileName);
- break;
-
- case ORIGINAL_FILE_ID:
- OriginalFileID = FileID::get(Record[0]);
- break;
-
- case ORIGINAL_PCH_DIR:
- // The primary AST will be the last to get here, so it will be the one
- // that's used.
- OriginalDir.assign(BlobStart, BlobLen);
- break;
-
- case VERSION_CONTROL_BRANCH_REVISION: {
- const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
- if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
- Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
- return IgnorePCH;
- }
- break;
- }
-
case PPD_ENTITIES_OFFSETS: {
F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart;
assert(BlobLen % sizeof(PPEntityOffset) == 0);
@@ -2300,7 +2358,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_UPDATE_OFFSETS: {
if (Record.size() % 2 != 0) {
Error("invalid DECL_UPDATE_OFFSETS block in AST file");
- return Failure;
+ return true;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 2)
DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
@@ -2311,7 +2369,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_REPLACEMENTS: {
if (Record.size() % 3 != 0) {
Error("invalid DECL_REPLACEMENTS block in AST file");
- return Failure;
+ return true;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 3)
ReplacedDecls[getGlobalDeclID(F, Record[I])]
@@ -2322,7 +2380,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case OBJC_CATEGORIES_MAP: {
if (F.LocalNumObjCCategoriesInMap != 0) {
Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
- return Failure;
+ return true;
}
F.LocalNumObjCCategoriesInMap = Record[0];
@@ -2337,7 +2395,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
- return Failure;
+ return true;
}
F.LocalNumCXXBaseSpecifiers = Record[0];
@@ -2347,11 +2405,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
case DIAG_PRAGMA_MAPPINGS:
- if (Record.size() % 2 != 0) {
- Error("invalid DIAG_USER_MAPPINGS block in AST file");
- return Failure;
- }
-
if (F.PragmaDiagMappings.empty())
F.PragmaDiagMappings.swap(Record);
else
@@ -2428,7 +2481,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case LOCAL_REDECLARATIONS_MAP: {
if (F.LocalNumRedeclarationsInMap != 0) {
Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
- return Failure;
+ return true;
}
F.LocalNumRedeclarationsInMap = Record[0];
@@ -2445,113 +2498,77 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
break;
}
- }
- }
- Error("premature end of bitstream in AST file");
- return Failure;
-}
-
-ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) {
- llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor;
-
- for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) {
- SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]);
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
- }
- RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default:
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ case MACRO_OFFSET: {
+ if (F.LocalNumMacros != 0) {
+ Error("duplicate MACRO_OFFSET record in AST file");
+ return true;
+ }
+ F.MacroOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumMacros = Record[0];
+ unsigned LocalBaseMacroID = Record[1];
+ F.BaseMacroID = getTotalNumMacros();
- case SM_SLOC_FILE_ENTRY: {
- // If the buffer was overridden, the file need not exist.
- if (Record[6])
- break;
-
- StringRef Filename(BlobStart, BlobLen);
- const FileEntry *File = getFileEntry(Filename);
+ if (F.LocalNumMacros > 0) {
+ // Introduce the global -> local mapping for macros within this module.
+ GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F));
- if (File == 0) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- return IgnorePCH;
- }
+ // Introduce the local -> global mapping for macros within this module.
+ F.MacroRemap.insertOrReplace(
+ std::make_pair(LocalBaseMacroID,
+ F.BaseMacroID - LocalBaseMacroID));
- if (Record.size() < 7) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
- off_t StoredSize = (off_t)Record[4];
- time_t StoredTime = (time_t)Record[5];
-
- // 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 (SM.isFileOverridden(File)) {
- Error(diag::err_fe_pch_file_overridden, Filename);
- // After emitting the diagnostic, recover by disabling the override so
- // that the original file will be used.
- SM.disableFileContentsOverride(File);
- // The FileEntry is a virtual file entry with the size of the contents
- // that would override the original contents. Set it to the original's
- // size/time.
- FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
- StoredSize, StoredTime);
+ MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros);
}
+ break;
+ }
- // 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();
- }
+ case MACRO_UPDATES: {
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ MacroID ID = getGlobalMacroID(F, Record[I++]);
+ if (I == N)
+ break;
- if ((StoredSize != StatBuf.st_size
-#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
-#endif
- )) {
- Error(diag::err_fe_pch_file_modified, Filename);
- return IgnorePCH;
+ 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));
}
-
break;
}
}
}
-
- return Success;
+ 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) {
- if (Decl *D = Names[I].dyn_cast<Decl *>())
- D->Hidden = false;
- else {
- IdentifierInfo *II = Names[I].get<IdentifierInfo *>();
- if (!II->hasMacroDefinition()) {
- II->setHasMacroDefinition(true);
- if (DeserializationListener)
- DeserializationListener->MacroVisible(II);
+ switch (Names[I].getKind()) {
+ case HiddenName::Declaration:
+ Names[I].getDecl()->Hidden = false;
+ break;
+
+ 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);
+ }
+ 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);
}
+ break;
+ }
}
}
}
@@ -2631,7 +2648,7 @@ void ASTReader::makeModuleVisible(Module *Mod,
for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
Module *Imported = Mod->Imports[I];
- if (Visited.count(Imported))
+ if (!Visited.insert(Imported))
continue;
bool Acceptable = UnrestrictedWildcard;
@@ -2649,32 +2666,62 @@ void ASTReader::makeModuleVisible(Module *Mod,
if (!Acceptable)
continue;
- Visited.insert(Imported);
Stack.push_back(Imported);
}
}
}
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
- ModuleKind Type) {
+ ModuleKind Type,
+ unsigned ClientLoadCapabilities) {
// Bump the generation number.
unsigned PreviousGeneration = CurrentGeneration++;
-
- switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {
- case Failure: return Failure;
- case IgnorePCH: return IgnorePCH;
- case Success: break;
+
+ unsigned NumModules = ModuleMgr.size();
+ llvm::SmallVector<ModuleFile *, 4> Loaded;
+ switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type,
+ /*ImportedBy=*/0, Loaded,
+ ClientLoadCapabilities)) {
+ case Failure:
+ case OutOfDate:
+ case VersionMismatch:
+ case ConfigurationMismatch:
+ case HadErrors:
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
+ return ReadResult;
+
+ case Success:
+ break;
}
// Here comes stuff that we only do once the entire chain is loaded.
- // Check the predefines buffers.
- if (!DisableValidation && Type == MK_PCH &&
- // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
- // if DisableValidation is true, defines that were set on command-line
- // but not in the PCH file will not be added to SuggestedPredefines.
- CheckPredefinesBuffers())
- return IgnorePCH;
+ // Load the AST blocks of all of the modules that we loaded.
+ for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = **M;
+
+ // Read the AST block.
+ if (ReadASTBlock(F))
+ return Failure;
+
+ // Once read, set the ModuleFile bit base offset and update the size in
+ // bits of all files we've seen.
+ F.GlobalBitOffset = TotalModulesSizeInBits;
+ TotalModulesSizeInBits += F.SizeInBits;
+ GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
+
+ // Preload SLocEntries.
+ for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
+ int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
+ // Load it through the SourceManager and don't call ReadSLocEntry()
+ // directly because the entry may have already been loaded in which case
+ // calling ReadSLocEntry() directly would trigger an assertion in
+ // SourceManager.
+ SourceMgr.getLoadedSLocEntryByID(Index);
+ }
+ }
// 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
@@ -2707,17 +2754,19 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
- if (!OriginalFileID.isInvalid()) {
- OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
- + OriginalFileID.getOpaqueValue() - 1);
+ ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
+ if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
+ PrimaryModule.OriginalSourceFileID
+ = FileID::get(PrimaryModule.SLocEntryBaseID
+ + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
- // If this AST file is a precompiled preamble, then set the preamble file ID
- // of the source manager to the file source file from which the preamble was
- // built.
+ // If this AST file is a precompiled preamble, then set the
+ // preamble file ID of the source manager to the file source file
+ // from which the preamble was built.
if (Type == MK_Preamble) {
- SourceMgr.setPreambleFileID(OriginalFileID);
+ SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID);
} else if (Type == MK_MainFile) {
- SourceMgr.setMainFileID(OriginalFileID);
+ SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID);
}
}
@@ -2732,9 +2781,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
return Success;
}
-ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
- ModuleKind Type,
- ModuleFile *ImportedBy) {
+ASTReader::ASTReadResult
+ASTReader::ReadASTCore(StringRef FileName,
+ ModuleKind Type,
+ ModuleFile *ImportedBy,
+ llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ unsigned ClientLoadCapabilities) {
ModuleFile *M;
bool NewModule;
std::string ErrorStr;
@@ -2785,7 +2837,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
unsigned BlockID = Stream.ReadSubBlockID();
- // We only know the AST subblock ID.
+ // We only know the control subblock ID.
switch (BlockID) {
case llvm::bitc::BLOCKINFO_BLOCK_ID:
if (Stream.ReadBlockInfoBlock()) {
@@ -2793,29 +2845,23 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
return Failure;
}
break;
- case AST_BLOCK_ID:
- switch (ReadASTBlock(F)) {
+ case CONTROL_BLOCK_ID:
+ switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
case Success:
break;
- case Failure:
- return Failure;
-
- case IgnorePCH:
- // FIXME: We could consider reading through to the end of this
- // AST block, skipping subblocks, to see if there are other
- // AST blocks elsewhere.
-
- // FIXME: We can't clear loaded slocentries anymore.
- //SourceMgr.ClearPreallocatedSLocEntries();
-
- // Remove the stat cache.
- if (F.StatCache)
- FileMgr.removeStatCache((ASTStatCache*)F.StatCache);
-
- return IgnorePCH;
+ case Failure: return Failure;
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
}
break;
+ case AST_BLOCK_ID:
+ // Record that we've loaded this module.
+ Loaded.push_back(M);
+ return Success;
+
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
@@ -2825,32 +2871,6 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
}
}
- // Once read, set the ModuleFile bit base offset and update the size in
- // bits of all files we've seen.
- F.GlobalBitOffset = TotalModulesSizeInBits;
- TotalModulesSizeInBits += F.SizeInBits;
- GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
-
- // Make sure that the files this module was built against are still available.
- if (!DisableValidation) {
- switch(validateFileEntries(*M)) {
- case Failure: return Failure;
- case IgnorePCH: return IgnorePCH;
- case Success: break;
- }
- }
-
- // Preload SLocEntries.
- for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) {
- int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
- // Load it through the SourceManager and don't call ReadSLocEntryRecord()
- // directly because the entry may have already been loaded in which case
- // calling ReadSLocEntryRecord() directly would trigger an assertion in
- // SourceManager.
- SourceMgr.getLoadedSLocEntryByID(Index);
- }
-
-
return Success;
}
@@ -3038,8 +3058,8 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
// We only know the AST subblock ID.
switch (BlockID) {
- case AST_BLOCK_ID:
- if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ case CONTROL_BLOCK_ID:
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
return std::string();
}
@@ -3071,19 +3091,191 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
Record.clear();
const char *BlobStart = 0;
unsigned BlobLen = 0;
- if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
- == ORIGINAL_FILE_NAME)
+ if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE)
return std::string(BlobStart, BlobLen);
}
return std::string();
}
-ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+namespace {
+ class SimplePCHValidator : public ASTReaderListener {
+ const LangOptions &ExistingLangOpts;
+ const TargetOptions &ExistingTargetOpts;
+ const PreprocessorOptions &ExistingPPOpts;
+ FileManager &FileMgr;
+
+ public:
+ SimplePCHValidator(const LangOptions &ExistingLangOpts,
+ const TargetOptions &ExistingTargetOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ FileManager &FileMgr)
+ : ExistingLangOpts(ExistingLangOpts),
+ ExistingTargetOpts(ExistingTargetOpts),
+ ExistingPPOpts(ExistingPPOpts),
+ FileMgr(FileMgr)
+ {
+ }
+
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
+ }
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
+ }
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr,
+ SuggestedPredefines);
+ }
+ };
+}
+
+bool ASTReader::readASTFileControlBlock(StringRef Filename,
+ FileManager &FileMgr,
+ ASTReaderListener &Listener) {
+ // Open the AST file.
+ std::string ErrStr;
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ return true;
+ }
+
+ 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()) {
+ return true;
+ }
+
+ InControlBlock = false;
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ 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 DIAGNOSTIC_OPTIONS:
+ if (ParseDiagnosticOptions(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 PREPROCESSOR_OPTIONS: {
+ std::string IgnoredSuggestedPredefines;
+ if (ParsePreprocessorOptions(Record, false, Listener,
+ IgnoredSuggestedPredefines))
+ return true;
+ break;
+ }
+
+ default:
+ // No other validation to perform.
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool ASTReader::isAcceptableASTFile(StringRef Filename,
+ FileManager &FileMgr,
+ const LangOptions &LangOpts,
+ const TargetOptions &TargetOpts,
+ const PreprocessorOptions &PPOpts) {
+ SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr);
+ return !readASTFileControlBlock(Filename, FileMgr, validator);
+}
+
+bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
// Enter the submodule block.
if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
Error("malformed submodule block record in AST file");
- return Failure;
+ return true;
}
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
@@ -3095,9 +3287,9 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (Code == llvm::bitc::END_BLOCK) {
if (F.Stream.ReadBlockEnd()) {
Error("error at end of submodule block in AST file");
- return Failure;
+ return true;
}
- return Success;
+ return false;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
@@ -3105,7 +3297,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
F.Stream.ReadSubBlockID();
if (F.Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
continue;
}
@@ -3126,12 +3318,12 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_DEFINITION: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (Record.size() < 7) {
Error("malformed module definition");
- return Failure;
+ return true;
}
StringRef Name(BlobStart, BlobLen);
@@ -3157,9 +3349,10 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (GlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[GlobalIndex]) {
Error("too many submodules");
- return Failure;
+ return true;
}
+ CurrentModule->setASTFile(F.File);
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->InferSubmodules = InferSubmodules;
@@ -3175,7 +3368,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_UMBRELLA_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3187,7 +3380,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
Error("mismatched umbrella headers in submodule");
- return Failure;
+ return true;
}
}
break;
@@ -3196,7 +3389,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3208,15 +3401,51 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (std::find(CurrentModule->Headers.begin(),
CurrentModule->Headers.end(),
File) == CurrentModule->Headers.end())
- ModMap.addHeader(CurrentModule, File);
+ ModMap.addHeader(CurrentModule, File, false);
}
break;
}
-
+
+ case SUBMODULE_EXCLUDED_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ 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);
+ }
+ break;
+ }
+
+ case SUBMODULE_TOPHEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ 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);
+ break;
+ }
+
case SUBMODULE_UMBRELLA_DIR: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3229,7 +3458,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
Error("mismatched umbrella directories in submodule");
- return Failure;
+ return true;
}
}
break;
@@ -3238,7 +3467,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_METADATA: {
if (!First) {
Error("submodule metadata record not at beginning of block");
- return Failure;
+ return true;
}
First = false;
@@ -3264,7 +3493,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_IMPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3285,7 +3514,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_EXPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3309,7 +3538,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_REQUIRES: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3331,27 +3560,144 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
/// them to the AST listener if one is set.
///
/// \returns true if the listener deems the file unacceptable, false otherwise.
-bool ASTReader::ParseLanguageOptions(const RecordData &Record) {
- if (Listener) {
- LangOptions LangOpts;
- unsigned Idx = 0;
+bool ASTReader::ParseLanguageOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ LangOptions LangOpts;
+ unsigned Idx = 0;
#define LANGOPT(Name, Bits, Default, Description) \
LangOpts.Name = Record[Idx++];
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
#include "clang/Basic/LangOptions.def"
- ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
- VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
- LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
-
- unsigned Length = Record[Idx++];
- LangOpts.CurrentModule.assign(Record.begin() + Idx,
- Record.begin() + Idx + Length);
- return Listener->ReadLanguageOptions(LangOpts);
+ ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
+ VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
+ LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
+
+ unsigned Length = Record[Idx++];
+ LangOpts.CurrentModule.assign(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ return Listener.ReadLanguageOptions(LangOpts, Complain);
+}
+
+bool ASTReader::ParseTargetOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ unsigned Idx = 0;
+ TargetOptions TargetOpts;
+ TargetOpts.Triple = ReadString(Record, Idx);
+ TargetOpts.CPU = ReadString(Record, Idx);
+ TargetOpts.ABI = ReadString(Record, Idx);
+ TargetOpts.CXXABI = ReadString(Record, Idx);
+ TargetOpts.LinkerVersion = ReadString(Record, Idx);
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
+ }
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.Features.push_back(ReadString(Record, Idx));
}
- return false;
+ return Listener.ReadTargetOptions(TargetOpts, Complain);
+}
+
+bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ DiagnosticOptions DiagOpts;
+ unsigned Idx = 0;
+#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
+#include "clang/Basic/DiagnosticOptions.def"
+
+ for (unsigned N = Record[Idx++]; N; --N) {
+ DiagOpts.Warnings.push_back(ReadString(Record, Idx));
+ }
+
+ return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
+}
+
+bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ FileSystemOptions FSOpts;
+ unsigned Idx = 0;
+ FSOpts.WorkingDir = ReadString(Record, Idx);
+ return Listener.ReadFileSystemOptions(FSOpts, Complain);
+}
+
+bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ HeaderSearchOptions HSOpts;
+ unsigned Idx = 0;
+ HSOpts.Sysroot = ReadString(Record, Idx);
+
+ // Include entries.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ 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));
+ }
+
+ // System header prefixes.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Prefix = ReadString(Record, Idx);
+ bool IsSystemHeader = Record[Idx++];
+ HSOpts.SystemHeaderPrefixes.push_back(
+ HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader));
+ }
+
+ HSOpts.ResourceDir = ReadString(Record, Idx);
+ HSOpts.ModuleCachePath = ReadString(Record, Idx);
+ HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.UseBuiltinIncludes = Record[Idx++];
+ HSOpts.UseStandardSystemIncludes = Record[Idx++];
+ HSOpts.UseStandardCXXIncludes = Record[Idx++];
+ HSOpts.UseLibcxx = Record[Idx++];
+
+ return Listener.ReadHeaderSearchOptions(HSOpts, Complain);
+}
+
+bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener,
+ std::string &SuggestedPredefines) {
+ PreprocessorOptions PPOpts;
+ unsigned Idx = 0;
+
+ // Macro definitions/undefs
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Macro = ReadString(Record, Idx);
+ bool IsUndef = Record[Idx++];
+ PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
+ }
+
+ // Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.Includes.push_back(ReadString(Record, Idx));
+ }
+
+ // Macro Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.MacroIncludes.push_back(ReadString(Record, Idx));
+ }
+
+ PPOpts.UsePredefines = Record[Idx++];
+ PPOpts.ImplicitPCHInclude = ReadString(Record, Idx);
+ PPOpts.ImplicitPTHInclude = ReadString(Record, Idx);
+ PPOpts.ObjCXXARCStandardLibrary =
+ static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
+ SuggestedPredefines.clear();
+ return Listener.ReadPreprocessorOptions(PPOpts, Complain,
+ SuggestedPredefines);
}
std::pair<ModuleFile *, unsigned>
@@ -3365,6 +3711,23 @@ ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
return std::make_pair(M, LocalIndex);
}
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const {
+ if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord())
+ return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID,
+ Mod.NumPreprocessedEntities);
+
+ return std::make_pair(PreprocessingRecord::iterator(),
+ PreprocessingRecord::iterator());
+}
+
+std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator>
+ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) {
+ return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls),
+ ModuleDeclIterator(this, &Mod,
+ Mod.FileSortedDecls + Mod.NumFileSortedDecls));
+}
+
PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
PreprocessedEntityID PPID = Index+1;
std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
@@ -3455,7 +3818,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
InclusionDirective *ID
= new (PPRec) InclusionDirective(PPRec, Kind,
StringRef(BlobStart, Record[0]),
- Record[1],
+ Record[1], Record[3],
File,
Range);
return ID;
@@ -3476,7 +3839,7 @@ PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
ModuleFile &M = *SLocMapI->second;
if (M.NumPreprocessedEntities)
- return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID);
+ return M.BasePreprocessedEntityID;
}
return getTotalNumPreprocessedEntities();
@@ -3559,8 +3922,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
if (PPI == pp_end)
return findNextPreprocessedEntity(SLocMapI);
- return getGlobalPreprocessedEntityID(M,
- M.BasePreprocessedEntityID + (PPI - pp_begin));
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
}
/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
@@ -3589,8 +3951,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
if (PPI == pp_end)
return findNextPreprocessedEntity(SLocMapI);
- return getGlobalPreprocessedEntityID(M,
- M.BasePreprocessedEntityID + (PPI - pp_begin));
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
}
/// \brief Returns a pair of [Begin, End) indices of preallocated
@@ -3681,14 +4042,31 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
}
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
+ // FIXME: Make it work properly with modules.
+ llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
ModuleFile &F = *(*I);
unsigned Idx = 0;
+ DiagStates.clear();
+ assert(!Diag.DiagStates.empty());
+ DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
while (Idx < F.PragmaDiagMappings.size()) {
SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
+ if (DiagStateID != 0) {
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
+ FullSourceLoc(Loc, SourceMgr)));
+ continue;
+ }
+
+ assert(DiagStateID == 0);
+ // A new DiagState was created here.
Diag.DiagStates.push_back(*Diag.GetCurDiagState());
+ DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
+ DiagStates.push_back(NewState);
Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(&Diag.DiagStates.back(),
+ DiagnosticsEngine::DiagStatePoint(NewState,
FullSourceLoc(Loc, SourceMgr)));
while (1) {
assert(Idx < F.PragmaDiagMappings.size() &&
@@ -4258,6 +4636,8 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
}
void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
@@ -4467,6 +4847,10 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_VA_LIST_TAG:
T = Context.getVaListTagType();
break;
+
+ case PREDEF_TYPE_BUILTIN_FN:
+ T = Context.BuiltinFnTy;
+ break;
}
assert(!T.isNull() && "Unknown predefined type");
@@ -4537,7 +4921,9 @@ ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
case TemplateArgument::Pack:
+ // FIXME: Is this right?
return TemplateArgumentLocInfo();
}
llvm_unreachable("unexpected template argument loc");
@@ -4593,7 +4979,7 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
}
serialization::DeclID
-ASTReader::getGlobalDeclID(ModuleFile &F, unsigned LocalID) const {
+ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
if (LocalID < NUM_PREDEF_DECL_IDS)
return LocalID;
@@ -4930,8 +5316,10 @@ namespace {
continue;
if (ND->getDeclName() != This->Name) {
- assert(!This->Name.getCXXNameType().isNull() &&
- "Name mismatch without a type");
+ // A name might be null because the decl's redeclarable part is
+ // currently read before reading its name. The lookup is triggered by
+ // building that decl (likely indirectly), and so it is later in the
+ // sense of "already existing" and can be ignored here.
continue;
}
@@ -5132,13 +5520,15 @@ void ASTReader::PrintStats() {
= IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
IdentifiersLoaded.end(),
(IdentifierInfo *)0);
+ unsigned NumMacrosLoaded
+ = MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
+ MacrosLoaded.end(),
+ (MacroInfo *)0);
unsigned NumSelectorsLoaded
= SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
SelectorsLoaded.end(),
Selector());
- std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
- std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
NumSLocEntriesRead, TotalNumSLocEntries,
@@ -5155,6 +5545,10 @@ void ASTReader::PrintStats() {
std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
+ if (!MacrosLoaded.empty())
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosLoaded, (unsigned)MacrosLoaded.size(),
+ ((float)NumMacrosLoaded/MacrosLoaded.size() * 100));
if (!SelectorsLoaded.empty())
std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(),
@@ -5213,6 +5607,7 @@ void ASTReader::dump() {
dumpModuleIDMap("Global type map", GlobalTypeMap);
dumpModuleIDMap("Global declaration map", GlobalDeclMap);
dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
+ dumpModuleIDMap("Global macro map", GlobalMacroMap);
dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
dumpModuleIDMap("Global selector map", GlobalSelectorMap);
dumpModuleIDMap("Global preprocessed entity map",
@@ -5246,7 +5641,7 @@ void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
void ASTReader::InitializeSema(Sema &S) {
SemaObj = &S;
- S.ExternalSource = this;
+ S.addExternalSource(this);
// Makes sure any declarations that were deserialized "too early"
// still get added to the identifier's declaration chains.
@@ -5281,6 +5676,9 @@ 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);
@@ -5570,6 +5968,7 @@ void ASTReader::ReadPendingInstantiations(
ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++]));
SourceLocation Loc
= SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]);
+
Pending.push_back(std::make_pair(D, Loc));
}
PendingInstantiations.clear();
@@ -5682,8 +6081,37 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
return LocalID + I->second;
}
-bool ASTReader::ReadSLocEntry(int ID) {
- return ReadSLocEntryRecord(ID) != Success;
+MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
+ if (ID == 0)
+ return 0;
+
+ if (MacrosLoaded.empty()) {
+ Error("no macro table in AST file");
+ return 0;
+ }
+
+ ID -= NUM_PREDEF_MACRO_IDS;
+ if (!MacrosLoaded[ID]) {
+ GlobalMacroMapType::iterator I
+ = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS);
+ assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
+ ModuleFile *M = I->second;
+ unsigned Index = ID - M->BaseMacroID;
+ ReadMacroRecord(*M, M->MacroOffsets[Index], Hint);
+ }
+
+ return MacrosLoaded[ID];
+}
+
+MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_MACRO_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
+ assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
+
+ return LocalID + I->second;
}
serialization::SubmoduleID
@@ -5694,7 +6122,7 @@ ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
assert(I != M.SubmoduleRemap.end()
- && "Invalid index into identifier index remap");
+ && "Invalid index into submodule index remap");
return LocalID + I->second;
}
@@ -5759,7 +6187,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
assert(I != M.SelectorRemap.end()
- && "Invalid index into identifier index remap");
+ && "Invalid index into selector index remap");
return LocalID + I->second;
}
@@ -5926,8 +6354,13 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
return TemplateArgument();
case TemplateArgument::Type:
return TemplateArgument(readType(F, Record, Idx));
- case TemplateArgument::Declaration:
- return TemplateArgument(ReadDecl(F, Record, Idx));
+ case TemplateArgument::Declaration: {
+ ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
+ bool ForReferenceParam = Record[Idx++];
+ return TemplateArgument(D, ForReferenceParam);
+ }
+ case TemplateArgument::NullPtr:
+ return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
case TemplateArgument::Integral: {
llvm::APSInt Value = ReadAPSInt(Record, Idx);
QualType T = readType(F, Record, Idx);
@@ -6340,7 +6773,8 @@ void ASTReader::ReadComments() {
}
void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty()) {
+ while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
+ !PendingMacroIDs.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
while (!PendingIdentifierInfos.empty()) {
@@ -6355,6 +6789,18 @@ void ASTReader::finishPendingActions() {
PendingDeclChainsKnown.erase(PendingDeclChains[I]);
}
PendingDeclChains.clear();
+
+ // 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;
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ ++IDIdx) {
+ Hint = getMacro(GlobalIDs[IDIdx], Hint);
+ }
+ }
+ PendingMacroIDs.clear();
}
// If we deserialized any C++ or Objective-C class definitions, any
@@ -6408,9 +6854,29 @@ void ASTReader::finishPendingActions() {
for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
REnd = RTD->redecls_end();
R != REnd; ++R)
- R->Common = RTD->Common;
+ R->Common = RTD->Common;
}
PendingDefinitions.clear();
+
+ // Load the bodies of any functions or methods we've encountered. We do
+ // this now (delayed) so that we can be sure that the declaration chains
+ // have been fully wired up.
+ for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
+ PBEnd = PendingBodies.end();
+ PB != PBEnd; ++PB) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
+ // FIXME: Check for =delete/=default?
+ // FIXME: Complain about ODR violations here?
+ if (!getContext().getLangOpts().Modules || !FD->hasBody())
+ FD->setLazyBody(PB->second);
+ continue;
+ }
+
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
+ if (!getContext().getLangOpts().Modules || !MD->hasBody())
+ MD->setLazyBody(PB->second);
+ }
+ PendingBodies.clear();
}
void ASTReader::FinishedDeserializing() {
@@ -6442,17 +6908,14 @@ void ASTReader::FinishedDeserializing() {
ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
StringRef isysroot, bool DisableValidation,
- bool DisableStatCache, bool AllowASTWithCompilerErrors)
+ bool AllowASTWithCompilerErrors)
: 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(FileMgr.getFileSystemOptions()),
- RelocatablePCH(false), isysroot(isysroot),
- DisableValidation(DisableValidation),
- DisableStatCache(DisableStatCache),
+ Consumer(0), ModuleMgr(PP.getFileManager()),
+ isysroot(isysroot), DisableValidation(DisableValidation),
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
- NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index cb21f82600e0..c42944df6344 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -37,7 +37,6 @@ namespace clang {
class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
ASTReader &Reader;
ModuleFile &F;
- llvm::BitstreamCursor &Cursor;
const DeclID ThisDeclID;
const unsigned RawLocation;
typedef ASTReader::RecordData RecordData;
@@ -48,6 +47,8 @@ namespace clang {
DeclID DeclContextIDForTemplateParmDecl;
DeclID LexicalDeclContextIDForTemplateParmDecl;
+ bool HasPendingBody;
+
uint64_t GetCurrentCursorOffset();
SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
@@ -116,7 +117,7 @@ namespace clang {
GlobalDeclID FirstID;
mutable bool Owning;
- RedeclarableResult &operator=(RedeclarableResult&); // DO NOT IMPLEMENT
+ void operator=(RedeclarableResult &) LLVM_DELETED_FUNCTION;
public:
RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID)
@@ -162,7 +163,7 @@ namespace clang {
NamedDecl *Existing;
mutable bool AddResult;
- FindExistingResult &operator=(FindExistingResult&); // DO NOT IMPLEMENT
+ void operator=(FindExistingResult&) LLVM_DELETED_FUNCTION;
public:
FindExistingResult(ASTReader &Reader)
@@ -194,16 +195,19 @@ namespace clang {
public:
ASTDeclReader(ASTReader &Reader, ModuleFile &F,
- llvm::BitstreamCursor &Cursor, DeclID thisDeclID,
+ DeclID thisDeclID,
unsigned RawLocation,
const RecordData &Record, unsigned &Idx)
- : Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID),
+ : Reader(Reader), F(F), ThisDeclID(thisDeclID),
RawLocation(RawLocation), Record(Record), Idx(Idx),
- TypeIDForTypeDecl(0) { }
+ TypeIDForTypeDecl(0), HasPendingBody(false) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
static void attachLatestDecl(Decl *D, Decl *latest);
+ /// \brief Determine whether this declaration has a pending body.
+ bool hasPendingBody() const { return HasPendingBody; }
+
void Visit(Decl *D);
void UpdateDecl(Decl *D, ModuleFile &ModuleFile,
@@ -321,8 +325,14 @@ void ASTDeclReader::Visit(Decl *D) {
ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
- if (Record[Idx++])
- FD->setLazyBody(GetCurrentCursorOffset());
+ // We only read it if FD doesn't already have a body (e.g., from another
+ // module).
+ // FIXME: Also consider = default and = delete.
+ // FIXME: Can we diagnose ODR violations somehow?
+ if (Record[Idx++]) {
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ }
} else if (D->isTemplateParameter()) {
// If we have a fully initialized template parameter, we can now
// set its DeclContext.
@@ -590,8 +600,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
TemplArgs.size(), C);
void *InsertPos = 0;
CanonTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
- assert(InsertPos && "Another specialization already inserted!");
- CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos);
+ if (InsertPos)
+ CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos);
+ else
+ assert(0 && "Another specialization already inserted!");
}
break;
}
@@ -628,19 +640,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
VisitNamedDecl(MD);
if (Record[Idx++]) {
- // In practice, this won't be executed (since method definitions
- // don't occur in header files).
- // Switch case IDs for this method body.
- ASTReader::SwitchCaseMapTy SwitchCaseStmtsForObjCMethod;
- SaveAndRestore<ASTReader::SwitchCaseMapTy *>
- SCFOM(Reader.CurrSwitchCaseStmts, &SwitchCaseStmtsForObjCMethod);
- MD->setBody(Reader.ReadStmt(F));
+ // Load the body on-demand. Most clients won't care, because method
+ // definitions rarely show up in headers.
+ Reader.PendingBodies[MD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
}
MD->setInstanceMethod(Record[Idx++]);
MD->setVariadic(Record[Idx++]);
- MD->setSynthesized(Record[Idx++]);
+ MD->setPropertyAccessor(Record[Idx++]);
MD->setDefined(Record[Idx++]);
MD->IsOverriding = Record[Idx++];
@@ -846,6 +855,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
+ D->setHasNonZeroConstructors(Record[Idx++]);
+ D->setHasDestructors(Record[Idx++]);
llvm::tie(D->IvarInitializers, D->NumIvarInitializers)
= Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
@@ -897,7 +908,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->VarDeclBits.NRVOVariable = Record[Idx++];
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
-
+ VD->VarDeclBits.IsConstexpr = Record[Idx++];
+
// Only true variables (not parameters or implicit parameters) can be merged.
if (VD->getKind() == Decl::Var)
mergeRedeclarable(VD, Redecl);
@@ -1135,6 +1147,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.Captures
= (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
+ Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
SourceLocation Loc = ReadSourceLocation(Record, Idx);
bool IsImplicit = Record[Idx++];
@@ -1155,7 +1168,8 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record[Idx++];
if (IsLambda)
- D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, false);
+ D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0,
+ false);
else
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
@@ -1242,6 +1256,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1);
for (unsigned I = 0, N = Record.back(); I != N; ++I)
StoredLocs[I] = ReadSourceLocation(Record, Idx);
+ ++Idx; // The number of stored source locations.
}
void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
@@ -1308,10 +1323,12 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
D->setMemberSpecialization();
}
}
-
+
VisitTemplateDecl(D);
D->IdentifierNamespace = Record[Idx++];
-
+
+ mergeRedeclarable(D, Redecl);
+
return Redecl;
}
@@ -1336,10 +1353,10 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
for (unsigned I = 0; I != Size; ++I)
SpecIDs.push_back(ReadDeclID(Record, Idx));
+ ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
if (SpecIDs[0]) {
typedef serialization::DeclID DeclID;
- ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
// FIXME: Append specializations!
CommonPtr->LazySpecializations
= new (Reader.getContext()) DeclID [SpecIDs.size()];
@@ -1347,7 +1364,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
SpecIDs.size() * sizeof(DeclID));
}
- // InjectedClassNameType is computed.
+ CommonPtr->InjectedClassNameType = Reader.readType(F, Record, Idx);
}
}
@@ -1391,14 +1408,17 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
TemplArgs.size());
D->PointOfInstantiation = ReadSourceLocation(Record, Idx);
D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
-
- if (D->isCanonicalDecl()) { // It's kept in the folding set.
+
+ bool writtenAsCanonicalDecl = Record[Idx++];
+ if (writtenAsCanonicalDecl) {
ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
- if (ClassTemplatePartialSpecializationDecl *Partial
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
- CanonPattern->getCommonPtr()->PartialSpecializations.InsertNode(Partial);
- } else {
- CanonPattern->getCommonPtr()->Specializations.InsertNode(D);
+ if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ if (ClassTemplatePartialSpecializationDecl *Partial
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+ CanonPattern->getCommonPtr()->PartialSpecializations.GetOrInsertNode(Partial);
+ } else {
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
}
}
}
@@ -1486,11 +1506,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
// TemplateParmPosition.
D->setDepth(Record[Idx++]);
D->setPosition(Record[Idx++]);
- // Rest of TemplateTemplateParmDecl.
- TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
- bool IsInherited = Record[Idx++];
- D->setDefaultArgument(Arg, IsInherited);
- D->ParameterPack = Record[Idx++];
+ if (D->isExpandedParameterPack()) {
+ void **Data = reinterpret_cast<void **>(D + 1);
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I)
+ Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx);
+ } else {
+ // Rest of TemplateTemplateParmDecl.
+ TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
+ bool IsInherited = Record[Idx++];
+ D->setDefaultArgument(Arg, IsInherited);
+ D->ParameterPack = Record[Idx++];
+ }
}
void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
@@ -1640,7 +1667,7 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) {
/// This routine should return true for anything that might affect
/// code generation, e.g., inline function definitions, Objective-C
/// declarations with metadata, etc.
-static bool isConsumerInterestedIn(Decl *D) {
+static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
// An ObjCMethodDecl is never considered as "interesting" because its
// implementation container always is.
@@ -1652,7 +1679,7 @@ static bool isConsumerInterestedIn(Decl *D) {
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- return Func->doesThisDeclarationHaveABody();
+ return Func->doesThisDeclarationHaveABody() || HasBody;
return false;
}
@@ -1719,8 +1746,10 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
TagDecl *TagY = cast<TagDecl>(Y);
return (TagX->getTagKind() == TagY->getTagKind()) ||
- ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
- (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
+ ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class ||
+ TagX->getTagKind() == TTK_Interface) &&
+ (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
+ TagY->getTagKind() == TTK_Interface));
}
// Functions with the same type and linkage match.
@@ -1731,7 +1760,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
return (FuncX->getLinkage() == FuncY->getLinkage()) &&
FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
}
-
+
// Variables with the same type and linkage match.
if (VarDecl *VarX = dyn_cast<VarDecl>(X)) {
VarDecl *VarY = cast<VarDecl>(Y);
@@ -1744,7 +1773,11 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
return NamespaceX->isInline() == NamespaceY->isInline();
}
-
+
+ // Identical template names and kinds match.
+ if (isa<TemplateDecl>(X))
+ return true;
+
// FIXME: Many other cases to implement.
return false;
}
@@ -1753,11 +1786,13 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
if (!AddResult || Existing)
return;
- DeclContext *DC = New->getDeclContext()->getRedeclContext();
- if (DC->isTranslationUnit() && Reader.SemaObj) {
+ if (New->getDeclContext()->getRedeclContext()->isTranslationUnit()
+ && Reader.SemaObj) {
Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
- } else if (DC->isNamespace()) {
- DC->addDecl(New);
+ } else {
+ DeclContext *DC = New->getLexicalDeclContext();
+ if (DC->isNamespace())
+ DC->addDecl(New);
}
}
@@ -1899,7 +1934,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned Idx = 0;
- ASTDeclReader Reader(*this, *Loc.F, DeclsCursor, ID, RawLocation, Record,Idx);
+ ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx);
Decl *D = 0;
switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
@@ -2002,6 +2037,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK:
+ D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID,
+ Record[Idx++]);
+ break;
case DECL_TYPE_ALIAS_TEMPLATE:
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
break;
@@ -2110,6 +2149,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
}
PendingVisibleUpdates.erase(I);
}
+
+ if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ DC->setMustBuildLookupTable();
}
assert(Idx == Record.size());
@@ -2125,9 +2167,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
// loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(D))
+ if (isConsumerInterestedIn(D, Reader.hasPendingBody()))
InterestingDecls.push_back(D);
-
+
return D;
}
@@ -2152,7 +2194,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
unsigned Idx = 0;
- ASTDeclReader Reader(*this, *F, Cursor, ID, 0, Record, Idx);
+ ASTDeclReader Reader(*this, *F, ID, 0, Record, Idx);
Reader.UpdateDecl(D, *F, Record);
}
}
@@ -2207,10 +2249,8 @@ namespace {
if (!D)
return;
- if (Deserialized.count(D)) {
- Deserialized.erase(D);
+ if (Deserialized.erase(D))
Chain.push_back(D);
- }
}
void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
@@ -2275,7 +2315,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
}
MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID);
if (MergedPos != MergedDecls.end())
- SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
+ SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
// Build up the list of redeclarations.
RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
@@ -2331,9 +2371,8 @@ namespace {
void add(ObjCCategoryDecl *Cat) {
// Only process each category once.
- if (!Deserialized.count(Cat))
+ if (!Deserialized.erase(Cat))
return;
- Deserialized.erase(Cat);
// Check for duplicate categories.
if (Cat->getDeclName()) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index c5325b5f7837..367f75f55eb0 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -288,7 +288,7 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
}
}
-void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
+void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitStmt(S);
unsigned NumOutputs = Record[Idx++];
unsigned NumInputs = Record[Idx++];
@@ -297,7 +297,6 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setRParenLoc(ReadSourceLocation(Record, Idx));
S->setVolatile(Record[Idx++]);
S->setSimple(Record[Idx++]);
- S->setMSAsm(Record[Idx++]);
S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
@@ -566,6 +565,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
E->setRHS(Reader.ReadSubExpr());
E->setOpcode((BinaryOperator::Opcode)Record[Idx++]);
E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+ E->setFPContractable((bool)Record[Idx++]);
}
void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -627,7 +627,8 @@ void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
- E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt()));
+ if (InitListExpr *SyntForm = cast_or_null<InitListExpr>(Reader.ReadSubStmt()))
+ E->setSyntacticForm(SyntForm);
E->setLBraceLoc(ReadSourceLocation(Record, Idx));
E->setRBraceLoc(ReadSourceLocation(Record, Idx));
bool isArrayFiller = Record[Idx++];
@@ -1087,6 +1088,7 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
E->Operator = (OverloadedOperatorKind)Record[Idx++];
E->Range = Reader.ReadSourceRange(F, Record, Idx);
+ E->setFPContractable((bool)Record[Idx++]);
}
void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -1242,7 +1244,7 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx));
E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx);
E->TypeIdParens = ReadSourceRange(Record, Idx);
- E->StartLoc = ReadSourceLocation(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
E->DirectInitRange = ReadSourceRange(Record, Idx);
E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs,
@@ -1367,8 +1369,6 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
E->RequiresADL = Record[Idx++];
- if (E->RequiresADL)
- E->StdIsAssociatedNamespace = Record[Idx++];
E->Overloaded = Record[Idx++];
E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx);
}
@@ -1469,6 +1469,16 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
E->NameLoc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ VisitExpr(E);
+ E->NumParameters = Record[Idx++];
+ E->ParamPack = ReadDeclAs<ParmVarDecl>(Record, Idx);
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+ ParmVarDecl **Parms = reinterpret_cast<ParmVarDecl**>(E+1);
+ for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
+ Parms[i] = ReadDeclAs<ParmVarDecl>(Record, Idx);
+}
+
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
E->Temporary = Reader.ReadSubExpr();
@@ -1701,8 +1711,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) DeclStmt(Empty);
break;
- case STMT_ASM:
- S = new (Context) AsmStmt(Empty);
+ case STMT_GCCASM:
+ S = new (Context) GCCAsmStmt(Empty);
+ break;
+
+ case STMT_MSASM:
+ S = new (Context) MSAsmStmt(Empty);
break;
case EXPR_PREDEFINED:
@@ -2180,6 +2194,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK:
S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
break;
+
+ case EXPR_FUNCTION_PARM_PACK:
+ S = FunctionParmPackExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
case EXPR_MATERIALIZE_TEMPORARY:
S = new (Context) MaterializeTemporaryExpr(Empty);
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 425d2e32a7b1..a2e8b71123b1 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -25,9 +25,11 @@
#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"
@@ -35,6 +37,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APFloat.h"
@@ -485,6 +488,8 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
}
void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
Writer.AddDeclRef(TL.getArg(i), Record);
@@ -667,7 +672,8 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_BREAK);
RECORD(STMT_RETURN);
RECORD(STMT_DECL);
- RECORD(STMT_ASM);
+ RECORD(STMT_GCCASM);
+ RECORD(STMT_MSASM);
RECORD(EXPR_PREDEFINED);
RECORD(EXPR_DECL_REF);
RECORD(EXPR_INTEGER_LITERAL);
@@ -763,14 +769,27 @@ void ASTWriter::WriteBlockInfoBlock() {
#define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record)
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
+ // Control Block.
+ BLOCK(CONTROL_BLOCK);
+ RECORD(METADATA);
+ RECORD(IMPORTS);
+ RECORD(LANGUAGE_OPTIONS);
+ RECORD(TARGET_OPTIONS);
+ RECORD(ORIGINAL_FILE);
+ RECORD(ORIGINAL_PCH_DIR);
+ RECORD(INPUT_FILE_OFFSETS);
+ RECORD(DIAGNOSTIC_OPTIONS);
+ RECORD(FILE_SYSTEM_OPTIONS);
+ RECORD(HEADER_SEARCH_OPTIONS);
+ RECORD(PREPROCESSOR_OPTIONS);
+
+ BLOCK(INPUT_FILES_BLOCK);
+ RECORD(INPUT_FILE);
+
// AST Top-Level Block.
BLOCK(AST_BLOCK);
- RECORD(ORIGINAL_FILE_NAME);
- RECORD(ORIGINAL_FILE_ID);
RECORD(TYPE_OFFSET);
RECORD(DECL_OFFSET);
- RECORD(LANGUAGE_OPTIONS);
- RECORD(METADATA);
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
RECORD(EXTERNAL_DEFINITIONS);
@@ -784,11 +803,8 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(PP_COUNTER_VALUE);
RECORD(SOURCE_LOCATION_OFFSETS);
RECORD(SOURCE_LOCATION_PRELOADS);
- RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
- RECORD(VERSION_CONTROL_BRANCH_REVISION);
RECORD(PPD_ENTITIES_OFFSETS);
- RECORD(IMPORTS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
RECORD(LOCAL_REDECLARATIONS_MAP);
@@ -803,11 +819,9 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DIAG_PRAGMA_MAPPINGS);
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
- RECORD(ORIGINAL_PCH_DIR);
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
- RECORD(FILE_SOURCE_LOCATION_OFFSETS);
RECORD(KNOWN_NAMESPACES);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
@@ -817,6 +831,8 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(MERGED_DECLARATIONS);
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
+ RECORD(MACRO_OFFSET);
+ RECORD(MACRO_UPDATES);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -972,25 +988,25 @@ adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
return Filename + Pos;
}
-/// \brief Write the AST metadata (e.g., i686-apple-darwin9).
-void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
- const std::string &OutputFile) {
+/// \brief Write the control block.
+void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot,
+ const std::string &OutputFile) {
using namespace llvm;
-
- // Metadata
- const TargetInfo &Target = Context.getTargetInfo();
- BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
- MetaAbbrev->Add(BitCodeAbbrevOp(METADATA));
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
- unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
-
+ Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
RecordData Record;
+
+ // Metadata
+ BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev();
+ MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj.
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min.
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
+ unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev);
Record.push_back(METADATA);
Record.push_back(VERSION_MAJOR);
Record.push_back(VERSION_MINOR);
@@ -998,9 +1014,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Record.push_back(CLANG_VERSION_MINOR);
Record.push_back(!isysroot.empty());
Record.push_back(ASTHasCompilerErrors);
- const std::string &Triple = Target.getTriple().getTriple();
- Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple);
+ Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
+ getClangFullRepositoryVersion());
+ // Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
llvm::SmallVector<char, 128> ModulePaths;
@@ -1022,11 +1039,131 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Stream.EmitRecord(IMPORTS, Record);
}
+ // Language options.
+ Record.clear();
+ const LangOptions &LangOpts = Context.getLangOpts();
+#define LANGOPT(Name, Bits, Default, Description) \
+ Record.push_back(LangOpts.Name);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
+#include "clang/Basic/LangOptions.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());
+ Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
+
+ // Target options.
+ Record.clear();
+ const TargetInfo &Target = Context.getTargetInfo();
+ const TargetOptions &TargetOpts = Target.getTargetOpts();
+ AddString(TargetOpts.Triple, Record);
+ AddString(TargetOpts.CPU, Record);
+ AddString(TargetOpts.ABI, Record);
+ AddString(TargetOpts.CXXABI, Record);
+ AddString(TargetOpts.LinkerVersion, Record);
+ Record.push_back(TargetOpts.FeaturesAsWritten.size());
+ for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
+ AddString(TargetOpts.FeaturesAsWritten[I], Record);
+ }
+ Record.push_back(TargetOpts.Features.size());
+ for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) {
+ AddString(TargetOpts.Features[I], Record);
+ }
+ Stream.EmitRecord(TARGET_OPTIONS, Record);
+
+ // Diagnostic options.
+ Record.clear();
+ const DiagnosticOptions &DiagOpts
+ = Context.getDiagnostics().getDiagnosticOptions();
+#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
+#include "clang/Basic/DiagnosticOptions.def"
+ Record.push_back(DiagOpts.Warnings.size());
+ for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
+ AddString(DiagOpts.Warnings[I], Record);
+ // Note: we don't serialize the log or serialization file names, because they
+ // are generally transient files and will almost always be overridden.
+ Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
+
+ // File system options.
+ Record.clear();
+ const FileSystemOptions &FSOpts
+ = Context.getSourceManager().getFileManager().getFileSystemOptions();
+ AddString(FSOpts.WorkingDir, Record);
+ Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record);
+
+ // Header search options.
+ Record.clear();
+ const HeaderSearchOptions &HSOpts
+ = PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ AddString(HSOpts.Sysroot, Record);
+
+ // Include entries.
+ Record.push_back(HSOpts.UserEntries.size());
+ for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
+ 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.
+ Record.push_back(HSOpts.SystemHeaderPrefixes.size());
+ for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
+ AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
+ Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
+ }
+
+ AddString(HSOpts.ResourceDir, Record);
+ AddString(HSOpts.ModuleCachePath, Record);
+ Record.push_back(HSOpts.DisableModuleHash);
+ Record.push_back(HSOpts.UseBuiltinIncludes);
+ Record.push_back(HSOpts.UseStandardSystemIncludes);
+ Record.push_back(HSOpts.UseStandardCXXIncludes);
+ Record.push_back(HSOpts.UseLibcxx);
+ Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record);
+
+ // Preprocessor options.
+ Record.clear();
+ const PreprocessorOptions &PPOpts = PP.getPreprocessorOpts();
+
+ // Macro definitions.
+ Record.push_back(PPOpts.Macros.size());
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ AddString(PPOpts.Macros[I].first, Record);
+ Record.push_back(PPOpts.Macros[I].second);
+ }
+
+ // Includes
+ Record.push_back(PPOpts.Includes.size());
+ for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I)
+ AddString(PPOpts.Includes[I], Record);
+
+ // Macro includes
+ Record.push_back(PPOpts.MacroIncludes.size());
+ for (unsigned I = 0, N = PPOpts.MacroIncludes.size(); I != N; ++I)
+ AddString(PPOpts.MacroIncludes[I], Record);
+
+ Record.push_back(PPOpts.UsePredefines);
+ AddString(PPOpts.ImplicitPCHInclude, Record);
+ AddString(PPOpts.ImplicitPTHInclude, Record);
+ Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary));
+ Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record);
+
// Original file name and file ID
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
- FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE_NAME));
+ FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));
+ FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
@@ -1037,13 +1174,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
const char *MainFileNameStr = MainFilePath.c_str();
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
isysroot);
- RecordData Record;
- Record.push_back(ORIGINAL_FILE_NAME);
- Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
-
Record.clear();
+ Record.push_back(ORIGINAL_FILE);
Record.push_back(SM.getMainFileID().getOpaqueValue());
- Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
+ Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
// Original PCH directory
@@ -1063,32 +1197,86 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
- // Repository branch/version information.
- BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
- RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION));
- RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
- unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev);
- Record.clear();
- Record.push_back(VERSION_CONTROL_BRANCH_REVISION);
- Stream.EmitRecordWithBlob(RepoAbbrevCode, Record,
- getClangFullRepositoryVersion());
+ WriteInputFiles(Context.SourceMgr, isysroot);
+ Stream.ExitBlock();
}
-/// \brief Write the LangOptions structure.
-void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
+ using namespace llvm;
+ Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
-#define LANGOPT(Name, Bits, Default, Description) \
- Record.push_back(LangOpts.Name);
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
-#include "clang/Basic/LangOptions.def"
+
+ // Create input-file abbreviation.
+ BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
+ IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
+
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ 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);
+ assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc);
- Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
- AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
+ // We only care about file entries that were not overridden.
+ if (!SLoc->isFile())
+ continue;
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (!Cache->OrigEntry)
+ continue;
+
+ // Record this entry's offset.
+ InputFileOffsets.push_back(Stream.GetCurrentBitNo());
+ InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size();
+
+ 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());
+
+ // Whether this file was overridden.
+ Record.push_back(Cache->BufferOverridden);
+
+ // Turn the file name into an absolute path, if it isn't already.
+ const char *Filename = Cache->OrigEntry->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);
+
+ // FIXME: This call to make_absolute shouldn't be necessary, the
+ // call to FixupRelativePath should always return an absolute path.
+ llvm::sys::fs::make_absolute(FilePath);
+ Filename = FilePath.c_str();
+
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+
+ Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
+ }
- Record.push_back(LangOpts.CurrentModule.size());
- Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
- Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
+ 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::Blob)); // Array
+ unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
+
+ // Write input file offsets.
+ Record.clear();
+ Record.push_back(INPUT_FILE_OFFSETS);
+ Record.push_back(InputFileOffsets.size());
+ Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
//===----------------------------------------------------------------------===//
@@ -1139,46 +1327,6 @@ public:
};
} // end anonymous namespace
-/// \brief Write the stat() system call cache to the AST file.
-void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
- // Build the on-disk hash table containing information about every
- // stat() call.
- OnDiskChainedHashTableGenerator<ASTStatCacheTrait> Generator;
- unsigned NumStatEntries = 0;
- for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
- StatEnd = StatCalls.end();
- Stat != StatEnd; ++Stat, ++NumStatEntries) {
- StringRef Filename = Stat->first();
- Generator.insert(Filename.data(), Stat->second);
- }
-
- // Create the on-disk hash table in a buffer.
- SmallString<4096> StatCacheData;
- uint32_t BucketOffset;
- {
- llvm::raw_svector_ostream Out(StatCacheData);
- // Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
- BucketOffset = Generator.Emit(Out);
- }
-
- // Create a blob abbreviation
- using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
-
- // Write the stat cache
- RecordData Record;
- Record.push_back(STAT_CACHE);
- Record.push_back(BucketOffset);
- Record.push_back(NumStatEntries);
- Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
-}
-
//===----------------------------------------------------------------------===//
// Source Manager Serialization
//===----------------------------------------------------------------------===//
@@ -1194,13 +1342,10 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
// FileEntry fields.
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // BufferOverridden
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev);
}
@@ -1329,8 +1474,6 @@ namespace {
/// \brief Write the header search block for the list of files that
///
/// \param HS The header search structure to save.
-///
-/// \param Chain Whether we're creating a chained AST file.
void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
@@ -1427,15 +1570,14 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
- // Write out the offsets of only source location file entries.
- // We will go through them in ASTReader::validateFileEntries().
- std::vector<uint32_t> SLocFileEntryOffsets;
RecordData PreloadSLocs;
SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
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);
+ FileID FID = FileID::get(I);
+ assert(&SourceMgr.getSLocEntry(FID) == SLoc);
// Record the offset of this source-location entry.
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
@@ -1446,7 +1588,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
if (Cache->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
- SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
} else
Code = SM_SLOC_BUFFER_ENTRY;
} else
@@ -1467,16 +1608,13 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
assert(Content->OrigEntry == Content->ContentsEntry &&
"Writing to AST an overridden file is not supported");
- // The source location entry is a file. The blob associated
- // with this entry is the file name.
+ // The source location entry is a file. Emit input file ID.
+ assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry");
+ Record.push_back(InputFileIDs[Content->OrigEntry]);
- // Emit size/modification time for this file.
- Record.push_back(Content->OrigEntry->getSize());
- Record.push_back(Content->OrigEntry->getModificationTime());
- Record.push_back(Content->BufferOverridden);
Record.push_back(File.NumCreatedFIDs);
- FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc);
+ FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID);
if (FDI != FileDeclIDs.end()) {
Record.push_back(FDI->second->FirstDeclIndex);
Record.push_back(FDI->second->DeclIDs.size());
@@ -1485,21 +1623,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(0);
}
- // Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Content->OrigEntry->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);
-
- // FIXME: This call to make_absolute shouldn't be necessary, the
- // call to FixupRelativePath should always return an absolute path.
- llvm::sys::fs::make_absolute(FilePath);
- Filename = FilePath.c_str();
-
- Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
- Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
+ Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record);
if (Content->BufferOverridden) {
Record.clear();
@@ -1570,18 +1694,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
- Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
- unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
-
- Record.clear();
- Record.push_back(FILE_SOURCE_LOCATION_OFFSETS);
- Record.push_back(SLocFileEntryOffsets.size());
- Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record,
- data(SLocFileEntryOffsets));
-
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
@@ -1675,102 +1787,129 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
MacrosToEmit;
llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
- for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
+ for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
E = PP.macro_end(Chain == 0);
I != E; ++I) {
- const IdentifierInfo *Name = I->first;
if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(Name);
+ MacroDefinitionsSeen.insert(I->first);
MacrosToEmit.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(),
+ llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(),
&compareMacroDefinitions);
-
- // Resolve any identifiers that defined macros at the time they were
- // deserialized, adding them to the list of macros to emit (if appropriate).
- for (unsigned I = 0, N = DeserializedMacroNames.size(); I != N; ++I) {
- IdentifierInfo *Name
- = const_cast<IdentifierInfo *>(DeserializedMacroNames[I]);
- if (Name->hasMacroDefinition() && MacroDefinitionsSeen.insert(Name))
- MacrosToEmit.push_back(std::make_pair(Name, PP.getMacroInfo(Name)));
- }
-
+
+ /// \brief Offsets of each of the macros into the bitstream, indexed by
+ /// the local macro ID
+ ///
+ /// For each identifier that is associated with a macro, this map
+ /// provides the offset into the bitstream where that macro is
+ /// defined.
+ std::vector<uint32_t> MacroOffsets;
+
for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) {
const IdentifierInfo *Name = MacrosToEmit[I].first;
- MacroInfo *MI = MacrosToEmit[I].second;
- if (!MI)
- continue;
-
- // 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).
- // Also skip macros from a AST file if we're chaining.
-
- // FIXME: There is a (probably minor) optimization we could do here, if
- // the macro comes from the original PCH but the identifier comes from a
- // chained PCH, by storing the offset into the original PCH rather than
- // writing the macro definition a second time.
- if (MI->isBuiltinMacro() ||
- (Chain &&
- Name->isFromAST() && !Name->hasChangedSinceDeserialization() &&
- MI->isFromAST() && !MI->hasChangedAfterLoad()))
- continue;
- AddIdentifierRef(Name, Record);
- MacroOffsets[Name] = Stream.GetCurrentBitNo();
- Record.push_back(MI->getDefinitionLoc().getRawEncoding());
- 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;
+ for (MacroInfo *MI = MacrosToEmit[I].second; MI;
+ MI = MI->getPreviousDefinition()) {
+ MacroID ID = getMacroRef(MI);
+ if (!ID)
+ continue;
- 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);
- }
+ // Skip macros from a AST file if we're chaining.
+ if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad())
+ continue;
- // 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 (ID < FirstMacroID) {
+ // This will have been dealt with via an update record.
+ assert(MacroUpdates.count(MI) > 0 && "Missing macro update");
+ continue;
+ }
- Stream.EmitRecord(Code, Record);
- Record.clear();
+ // 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);
- // 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);
+ MacroOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ 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)]);
+
+ Stream.EmitRecord(Code, 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.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+
+ unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(MACRO_OFFSET);
+ Record.push_back(MacroOffsets.size());
+ Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS);
+ Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record,
+ data(MacroOffsets));
}
void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
@@ -1794,6 +1933,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
}
@@ -1836,6 +1976,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
Record.push_back(ID->getFileName().size());
Record.push_back(ID->wasInQuotes());
Record.push_back(static_cast<unsigned>(ID->getKind()));
+ Record.push_back(ID->importedModule());
SmallString<64> Buffer;
Buffer += ID->getFileName();
// Check that the FileEntry is not null because it was not resolved and
@@ -1935,6 +2076,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned TopHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -1944,6 +2090,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2005,6 +2156,19 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
Mod->Headers[I]->getName());
}
+ // Emit the excluded headers.
+ for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_EXCLUDED_HEADER);
+ Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
+ Mod->ExcludedHeaders[I]->getName());
+ }
+ for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_TOPHEADER);
+ Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
+ Mod->TopHeaders[I]->getName());
+ }
// Emit the imports.
if (!Mod->Imports.empty()) {
@@ -2067,24 +2231,35 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
}
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
+ // FIXME: Make it work properly with modules.
+ llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
+ DiagStateIDMap;
+ unsigned CurrID = 0;
+ DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one.
RecordData Record;
for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
I != E; ++I) {
- const DiagnosticsEngine::DiagStatePoint &point = *I;
+ const DiagnosticsEngine::DiagStatePoint &point = *I;
if (point.Loc.isInvalid())
continue;
Record.push_back(point.Loc.getRawEncoding());
- for (DiagnosticsEngine::DiagState::const_iterator
- I = point.State->begin(), E = point.State->end(); I != E; ++I) {
- if (I->second.isPragma()) {
- Record.push_back(I->first);
- Record.push_back(I->second.getMapping());
+ unsigned &DiagStateID = DiagStateIDMap[point.State];
+ Record.push_back(DiagStateID);
+
+ if (DiagStateID == 0) {
+ DiagStateID = ++CurrID;
+ for (DiagnosticsEngine::DiagState::const_iterator
+ I = point.State->begin(), E = point.State->end(); I != E; ++I) {
+ if (I->second.isPragma()) {
+ Record.push_back(I->first);
+ Record.push_back(I->second.getMapping());
+ }
}
+ Record.push_back(-1); // mark the end of the diag/map pairs for this
+ // location.
}
- Record.push_back(-1); // mark the end of the diag/map pairs for this
- // location.
}
if (!Record.empty())
@@ -2238,9 +2413,11 @@ void ASTWriter::WriteFileDeclIDsMap() {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
Record.push_back(FILE_SORTED_DECLS);
+ Record.push_back(FileSortedIDs.size());
Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs));
}
@@ -2495,17 +2672,17 @@ class ASTIdentifierTableTrait {
II->getFETokenInfo<void>())
return true;
- return hasMacroDefinition(II, Macro);
+ return hadMacroDefinition(II, Macro);
}
-
- bool hasMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
- if (!II->hasMacroDefinition())
+
+ bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
+ if (!II->hadMacroDefinition())
return false;
-
- if (Macro || (Macro = PP.getMacroInfo(II)))
+
+ if (Macro || (Macro = PP.getMacroInfoHistory(II)))
return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
-
- return false;
+
+ return false;
}
public:
@@ -2529,10 +2706,17 @@ public:
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
MacroInfo *Macro = 0;
if (isInterestingIdentifier(II, Macro)) {
- DataLen += 2; // 2 bytes for builtin ID, flags
- if (hasMacroDefinition(II, Macro))
- DataLen += 8;
-
+ 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;
+ }
+
for (IdentifierResolver::iterator D = IdResolver.begin(II),
DEnd = IdResolver.end();
D != DEnd; ++D)
@@ -2563,23 +2747,28 @@ public:
}
clang::io::Emit32(Out, (ID << 1) | 0x01);
- uint32_t Bits = 0;
- bool HasMacroDefinition = hasMacroDefinition(II, Macro);
- Bits = (uint32_t)II->getObjCOrBuiltinID();
- assert((Bits & 0x7ff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
- Bits = (Bits << 1) | unsigned(HasMacroDefinition);
+ uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID();
+ assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
+ clang::io::Emit16(Out, Bits);
+ Bits = 0;
+ bool HadMacroDefinition = hadMacroDefinition(II, Macro);
+ Bits = (Bits << 1) | unsigned(HadMacroDefinition);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
clang::io::Emit16(Out, Bits);
- if (HasMacroDefinition) {
- clang::io::Emit32(Out, Writer.getMacroOffset(II));
- clang::io::Emit32(Out,
- Writer.inferSubmoduleIDFromLocation(Macro->getDefinitionLoc()));
+ 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, 0);
}
-
+
// Emit the declaration IDs in reverse order, because the
// IdentifierResolver provides the declarations as they would be
// visible (e.g., the function "stat" would come before the struct
@@ -2756,30 +2945,32 @@ public:
void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) {
using namespace clang::io;
- assert(Name.getNameKind() < 0x100 && "Invalid name kind ?");
Emit8(Out, Name.getNameKind());
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
- break;
+ return;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
- break;
+ return;
case DeclarationName::CXXOperatorName:
- assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?");
+ assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS &&
+ "Invalid operator?");
Emit8(Out, Name.getCXXOverloadedOperator());
- break;
+ return;
case DeclarationName::CXXLiteralOperatorName:
Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
- break;
+ return;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
- break;
+ return;
}
+
+ llvm_unreachable("Invalid name kind?");
}
void EmitData(raw_ostream& Out, key_type_ref,
@@ -3147,7 +3338,8 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
ASTHasCompilerErrors(false),
FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
- FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID),
FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
NextSubmoduleID(FirstSubmoduleID),
FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
@@ -3171,7 +3363,7 @@ ASTWriter::~ASTWriter() {
delete I->second;
}
-void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+void ASTWriter::WriteAST(Sema &SemaRef,
const std::string &OutputFile,
Module *WritingModule, StringRef isysroot,
bool hasErrors) {
@@ -3190,7 +3382,7 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Context = &SemaRef.Context;
PP = &SemaRef.PP;
this->WritingModule = WritingModule;
- WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
+ WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);
Context = 0;
PP = 0;
this->WritingModule = 0;
@@ -3207,7 +3399,7 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
}
}
-void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+void ASTWriter::WriteASTCore(Sema &SemaRef,
StringRef isysroot,
const std::string &OutputFile,
Module *WritingModule) {
@@ -3357,14 +3549,13 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
if (!I->second)
AddDeclRef(I->first, KnownNamespaces);
}
-
+
+ // Write the control block
+ WriteControlBlock(PP, Context, isysroot, OutputFile);
+
// Write the remaining AST contents.
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
- WriteMetadata(Context, isysroot, OutputFile);
- WriteLanguageOptions(Context.getLangOpts());
- if (StatCalls && isysroot.empty())
- WriteStatCache(*StatCalls);
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
@@ -3482,6 +3673,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Out.write(FileName.data(), FileName.size());
io::Emit32(Out, (*M)->SLocEntryBaseOffset);
io::Emit32(Out, (*M)->BaseIdentifierID);
+ io::Emit32(Out, (*M)->BaseMacroID);
io::Emit32(Out, (*M)->BasePreprocessedEntityID);
io::Emit32(Out, (*M)->BaseSubmoduleID);
io::Emit32(Out, (*M)->BaseSelectorID);
@@ -3595,7 +3787,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Stream.EmitRecord(IMPORTED_MODULES, ImportedModules);
}
}
-
+
+ WriteMacroUpdates();
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
WriteMergedDecls();
@@ -3612,6 +3805,21 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
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() {
@@ -3707,6 +3915,10 @@ 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;
@@ -3717,6 +3929,19 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
+MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
+ // Don't emit builtin macros like __LINE__ to the AST file unless they
+ // have been redefined by the header (in which case they are not
+ // isBuiltinMacro).
+ if (MI == 0 || MI->isBuiltinMacro())
+ return 0;
+
+ MacroID &ID = MacroIDs[MI];
+ if (ID == 0)
+ ID = NextMacroID++;
+ return ID;
+}
+
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
Record.push_back(getSelectorRef(SelRef));
}
@@ -3774,7 +3999,9 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
case TemplateArgument::Pack:
+ // FIXME: Is this right?
break;
}
}
@@ -3931,10 +4158,9 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
if (FID.isInvalid())
return;
- const SrcMgr::SLocEntry *Entry = &SM.getSLocEntry(FID);
- assert(Entry->isFile());
+ assert(SM.getSLocEntry(FID).isFile());
- DeclIDInFileInfo *&Info = FileDeclIDs[Entry];
+ DeclIDInFileInfo *&Info = FileDeclIDs[FID];
if (!Info)
Info = new DeclIDInFileInfo();
@@ -4191,6 +4417,10 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::Declaration:
AddDeclRef(Arg.getAsDecl(), Record);
+ Record.push_back(Arg.isDeclForReferenceParam());
+ break;
+ case TemplateArgument::NullPtr:
+ AddTypeRef(Arg.getNullPtrType(), Record);
break;
case TemplateArgument::Integral:
AddAPSInt(Arg.getAsIntegral(), Record);
@@ -4403,6 +4633,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Lambda.NumExplicitCaptures);
Record.push_back(Lambda.ManglingNumber);
AddDeclRef(Lambda.ContextDecl, Record);
+ AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
LambdaExpr::Capture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record);
@@ -4423,6 +4654,7 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
assert(FirstDeclID == NextDeclID &&
FirstTypeID == NextTypeID &&
FirstIdentID == NextIdentID &&
+ FirstMacroID == NextMacroID &&
FirstSubmoduleID == NextSubmoduleID &&
FirstSelectorID == NextSelectorID &&
"Setting chain after writing has started.");
@@ -4432,19 +4664,23 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
+ FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros();
FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules();
FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
NextDeclID = FirstDeclID;
NextTypeID = FirstTypeID;
NextIdentID = FirstIdentID;
+ NextMacroID = FirstMacroID;
NextSelectorID = FirstSelectorID;
NextSubmoduleID = FirstSubmoduleID;
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
IdentifierIDs[II] = ID;
- if (II->hasMacroDefinition())
- DeserializedMacroNames.push_back(II);
+}
+
+void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
+ MacroIDs[MI] = ID;
}
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
@@ -4468,15 +4704,15 @@ void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinitions[MD] = ID;
}
-void ASTWriter::MacroVisible(IdentifierInfo *II) {
- DeserializedMacroNames.push_back(II);
-}
-
void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
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!");
@@ -4490,6 +4726,7 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
}
}
}
+
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
assert(!WritingAST && "Already writing the AST!");
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 602943b9ba58..74865657637c 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -416,7 +416,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
}
Record.push_back(D->isInstanceMethod());
Record.push_back(D->isVariadic());
- Record.push_back(D->isSynthesized());
+ Record.push_back(D->isPropertyAccessor());
Record.push_back(D->isDefined());
Record.push_back(D->IsOverriding);
@@ -606,6 +606,8 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
Writer.AddDeclRef(D->getSuperClass(), Record);
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
+ Record.push_back(D->hasNonZeroConstructors());
+ Record.push_back(D->hasDestructors());
Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers,
Record);
Code = serialization::DECL_OBJC_IMPLEMENTATION;
@@ -675,6 +677,8 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
+ Record.push_back(D->isConstexpr());
+
if (D->getInit()) {
Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
Writer.AddStmt(D->getInit());
@@ -705,6 +709,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
D->getInitStyle() == VarDecl::CInit &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
+ !D->isConstexpr() &&
!SpecInfo)
AbbrevToUse = Writer.getDeclVarAbbrev();
@@ -945,11 +950,16 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
- Record.push_back(D->size_overridden_methods());
- for (CXXMethodDecl::method_iterator
- I = D->begin_overridden_methods(), E = D->end_overridden_methods();
- I != E; ++I)
- Writer.AddDeclRef(*I, Record);
+ if (D->isCanonicalDecl()) {
+ Record.push_back(D->size_overridden_methods());
+ for (CXXMethodDecl::method_iterator
+ I = D->begin_overridden_methods(), E = D->end_overridden_methods();
+ I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ } else {
+ // We only need to record overridden methods once for the canonical decl.
+ Record.push_back(0);
+ }
Code = serialization::DECL_CXX_METHOD;
}
@@ -981,6 +991,7 @@ void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
void ASTDeclWriter::VisitImportDecl(ImportDecl *D) {
VisitDecl(D);
+ Record.push_back(Writer.getSubmoduleID(D->getImportedModule()));
ArrayRef<SourceLocation> IdentifierLocs = D->getIdentifierLocs();
Record.push_back(!IdentifierLocs.empty());
if (IdentifierLocs.empty()) {
@@ -1073,7 +1084,7 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Writer.AddDeclRef(&*I, Record);
}
- // InjectedClassNameType is computed, no need to write it.
+ Writer.AddTypeRef(D->getCommonPtr()->InjectedClassNameType, Record);
}
Code = serialization::DECL_CLASS_TEMPLATE;
}
@@ -1103,6 +1114,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
Record.push_back(D->getSpecializationKind());
+ Record.push_back(D->isCanonicalDecl());
if (D->isCanonicalDecl()) {
// When reading, we'll add it to the folding set of the following template.
@@ -1172,7 +1184,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// For an expanded parameter pack, record the number of expansion types here
- // so that it's easier for
+ // so that it's easier for deserialization to allocate the right amount of
+ // memory.
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionTypes());
@@ -1201,15 +1214,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
}
void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ // For an expanded parameter pack, record the number of expansion types here
+ // so that it's easier for deserialization to allocate the right amount of
+ // memory.
+ if (D->isExpandedParameterPack())
+ Record.push_back(D->getNumExpansionTemplateParameters());
+
VisitTemplateDecl(D);
// TemplateParmPosition.
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
- // Rest of TemplateTemplateParmDecl.
- Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
- Record.push_back(D->defaultArgumentWasInherited());
- Record.push_back(D->isParameterPack());
- Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+
+ if (D->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I)
+ Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I),
+ Record);
+ Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
+ } else {
+ // Rest of TemplateTemplateParmDecl.
+ Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
+ Record.push_back(D->defaultArgumentWasInherited());
+ Record.push_back(D->isParameterPack());
+ Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+ }
}
void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
@@ -1462,6 +1490,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
+ Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl
@@ -1540,6 +1569,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
+ Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
// Type Source Info
@@ -1603,7 +1633,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
//Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsWide
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind
CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
Abv = new BitCodeAbbrev();
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index f63388fa2fd1..7e8ce42d7caf 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -218,7 +218,7 @@ void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) {
Code = serialization::STMT_DECL;
}
-void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
+void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitStmt(S);
Record.push_back(S->getNumOutputs());
Record.push_back(S->getNumInputs());
@@ -227,7 +227,6 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Record.push_back(S->isVolatile());
Record.push_back(S->isSimple());
- Record.push_back(S->isMSAsm());
Writer.AddStmt(S->getAsmString());
// Outputs
@@ -246,14 +245,16 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
// Clobbers
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
- Writer.AddStmt(S->getClobber(I));
+ Writer.AddStmt(S->getClobberStringLiteral(I));
- Code = serialization::STMT_ASM;
+ Code = serialization::STMT_GCCASM;
}
void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
// FIXME: Statement writer not yet implemented for MS style inline asm.
VisitStmt(S);
+
+ Code = serialization::STMT_MSASM;
}
void ASTStmtWriter::VisitExpr(Expr *E) {
@@ -535,6 +536,7 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
Writer.AddStmt(E->getRHS());
Record.push_back(E->getOpcode()); // FIXME: stable encoding
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Record.push_back(E->isFPContractable());
Code = serialization::EXPR_BINARY_OPERATOR;
}
@@ -604,6 +606,8 @@ void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
+ // NOTE: only add the (possibly null) syntactic form.
+ // No need to serialize the isSemanticForm flag and the semantic form.
Writer.AddStmt(E->getSyntacticForm());
Writer.AddSourceLocation(E->getLBraceLoc(), Record);
Writer.AddSourceLocation(E->getRBraceLoc(), Record);
@@ -1054,6 +1058,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
Writer.AddSourceRange(E->Range, Record);
+ Record.push_back(E->isFPContractable());
Code = serialization::EXPR_CXX_OPERATOR_CALL;
}
@@ -1233,7 +1238,7 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
Writer.AddDeclRef(E->getOperatorDelete(), Record);
Writer.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo(), Record);
Writer.AddSourceRange(E->getTypeIdParens(), Record);
- Writer.AddSourceLocation(E->getStartLoc(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
Writer.AddSourceRange(E->getDirectInitRange(), Record);
for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
I != e; ++I)
@@ -1382,8 +1387,6 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
Record.push_back(E->requiresADL());
- if (E->requiresADL())
- Record.push_back(E->isStdAssociatedNamespace());
Record.push_back(E->isOverloaded());
Writer.AddDeclRef(E->getNamingClass(), Record);
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
@@ -1480,6 +1483,17 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK;
}
+void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumExpansions());
+ Writer.AddDeclRef(E->getParameterPack(), Record);
+ Writer.AddSourceLocation(E->getParameterPackLocation(), Record);
+ for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
+ I != End; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = serialization::EXPR_FUNCTION_PARM_PACK;
+}
+
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->Temporary);
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 02aed103f1bf..870d65489584 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -18,7 +18,6 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
@@ -32,11 +31,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP,
raw_ostream *OS)
: PP(PP), OutputFile(OutputFile), Module(Module),
isysroot(isysroot.str()), Out(OS),
- SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) {
- // Install a stat() listener to keep track of all of the stat()
- // calls.
- StatCalls = new MemorizeStatCalls();
- PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/false);
+ SemaPtr(0), Stream(Buffer), Writer(Stream) {
}
PCHGenerator::~PCHGenerator() {
@@ -48,7 +43,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
// Emit the PCH file
assert(SemaPtr && "No Sema?");
- Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, Module, isysroot);
+ Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
@@ -60,6 +55,10 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
Buffer.clear();
}
+PPMutationListener *PCHGenerator::GetPPMutationListener() {
+ return &Writer;
+}
+
ASTMutationListener *PCHGenerator::GetASTMutationListener() {
return &Writer;
}
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index ff241d3d4105..5e42ab4211fa 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -21,12 +21,15 @@ using namespace serialization;
using namespace reader;
ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
- : Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0),
+ : Kind(Kind), File(0), DirectlyImported(false),
+ Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(0),
- SLocFileOffsets(0), LocalNumIdentifiers(0),
+ LocalNumIdentifiers(0),
IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0),
- IdentifierLookupTable(0), BasePreprocessedEntityID(0),
+ IdentifierLookupTable(0),
+ LocalNumMacros(0), MacroOffsets(0),
+ BasePreprocessedEntityID(0),
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
@@ -35,9 +38,10 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- FileSortedDecls(0), RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
+ FileSortedDecls(0), NumFileSortedDecls(0),
+ RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
ObjCCategoriesMap(0), LocalNumObjCCategoriesInMap(0),
- LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
+ LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0)
{}
ModuleFile::~ModuleFile() {
@@ -89,6 +93,10 @@ void ModuleFile::dump() {
<< " Number of identifiers: " << LocalNumIdentifiers << '\n';
dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap);
+ llvm::errs() << " Base macro ID: " << BaseMacroID << '\n'
+ << " Number of macros: " << LocalNumMacros << '\n';
+ dumpLocalRemap("Macro ID local -> global map", MacroRemap);
+
llvm::errs() << " Base submodule ID: " << BaseSubmoduleID << '\n'
<< " Number of submodules: " << LocalNumSubmodules << '\n';
dumpLocalRemap("Submodule ID local -> global map", SubmoduleRemap);
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index ab364b7ebd2c..efe442101bb6 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -50,6 +50,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Allocate a new module.
ModuleFile *New = new ModuleFile(Type, Generation);
New->FileName = FileName.str();
+ New->File = Entry;
Chain.push_back(New);
NewModule = true;
ModuleEntry = New;
@@ -87,6 +88,45 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return std::make_pair(ModuleEntry, NewModule);
}
+namespace {
+ /// \brief Predicate that checks whether a module file occurs within
+ /// the given set.
+ class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> {
+ llvm::SmallPtrSet<ModuleFile *, 4> &Removed;
+
+ public:
+ IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed)
+ : Removed(Removed) { }
+
+ bool operator()(ModuleFile *MF) const {
+ return Removed.count(MF);
+ }
+ };
+}
+
+void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
+ if (first == last)
+ return;
+
+ // Collect the set of module file pointers that we'll be removing.
+ llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
+
+ // Remove any references to the now-destroyed modules.
+ IsInModuleFileSet checkInSet(victimSet);
+ for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
+ Chain[i]->ImportedBy.remove_if(checkInSet);
+ }
+
+ // Delete the modules and erase them from the various structures.
+ for (ModuleIterator victim = first; victim != last; ++victim) {
+ Modules.erase((*victim)->File);
+ delete *victim;
+ }
+
+ // Remove the modules from the chain.
+ Chain.erase(first, last);
+}
+
void ModuleManager::addInMemoryBuffer(StringRef FileName,
llvm::MemoryBuffer *Buffer) {
@@ -95,7 +135,7 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName,
InMemoryBuffers[Entry] = Buffer;
}
-ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { }
+ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { }
ModuleManager::~ModuleManager() {
for (unsigned i = 0, e = Chain.size(); i != e; ++i)
diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
deleted file mode 100644
index 84ea8c709dd9..000000000000
--- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines AdjustedReturnValueChecker, a simple check to see if the
-// return value of a function call is different than the one the caller thinks
-// it is.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.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"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AdjustedReturnValueChecker :
- public Checker< check::PostStmt<CallExpr> > {
-public:
- void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
-};
-}
-
-void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
- CheckerContext &C) const {
-
- // Get the result type of the call.
- QualType expectedResultTy = CE->getType();
-
- // Fetch the signature of the called function.
- ProgramStateRef state = C.getState();
- const LocationContext *LCtx = C.getLocationContext();
-
- SVal V = state->getSVal(CE, LCtx);
-
- if (V.isUnknown())
- return;
-
- // Casting to void? Discard the value.
- if (expectedResultTy->isVoidType()) {
- C.addTransition(state->BindExpr(CE, LCtx, UnknownVal()));
- return;
- }
-
- const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion();
- if (!callee)
- return;
-
- QualType actualResultTy;
-
- if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
- const FunctionDecl *FD = FT->getDecl();
- actualResultTy = FD->getResultType();
- }
- else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
- const BlockTextRegion *BR = BD->getCodeRegion();
- const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
- actualResultTy = FT->getResultType();
- }
-
- // Can this happen?
- if (actualResultTy.isNull())
- return;
-
- // For now, ignore references.
- if (actualResultTy->getAs<ReferenceType>())
- return;
-
-
- // Are they the same?
- if (expectedResultTy != actualResultTy) {
- // FIXME: Do more checking and actual emit an error. At least performing
- // the cast avoids some assertion failures elsewhere.
- SValBuilder &svalBuilder = C.getSValBuilder();
- V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
- C.addTransition(state->BindExpr(CE, LCtx, V));
- }
-}
-
-void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) {
- mgr.registerChecker<AdjustedReturnValueChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index b2ad18472e06..535d8eede46a 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -78,7 +78,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
new BugReport(*BT, BT->getDescription(), N);
report->addRange(LoadS->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index c6efe941ec21..457c870943dd 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -208,7 +208,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
break;
}
- checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode));
+ checkerContext.emitReport(new BugReport(*BT, os.str(), errorNode));
}
void RegionRawOffsetV2::dump() const {
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index c582cfc4a81b..81e8dd885a34 100644
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
@@ -105,9 +105,9 @@ void AttrNonNullChecker::checkPreCall(const CallEvent &Call,
// Highlight the range of the argument that was null.
R->addRange(Call.getArgSourceRange(idx));
if (const Expr *ArgE = Call.getArgExpr(idx))
- bugreporter::addTrackNullOrUndefValueVisitor(errorNode, ArgE, R);
+ bugreporter::trackNullOrUndefValue(errorNode, ArgE, *R);
// Emit the bug report.
- C.EmitReport(R);
+ C.emitReport(R);
}
// Always return. Either we cached out or we just emitted an error.
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 955e79ae4661..eba534e08f6b 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -117,7 +117,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
BugReport *R = new BugReport(*BT, os.str(), N);
R->addRange(msg.getArgSourceRange(Arg));
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -358,20 +358,20 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
//===----------------------------------------------------------------------===//
-// CFRetain/CFRelease checking for null arguments.
+// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
//===----------------------------------------------------------------------===//
namespace {
class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable OwningPtr<APIMisuse> BT;
- mutable IdentifierInfo *Retain, *Release;
+ mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
public:
- CFRetainReleaseChecker(): Retain(0), Release(0) {}
+ CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
@@ -392,12 +392,14 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
ASTContext &Ctx = C.getASTContext();
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
- BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
+ MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
+ BT.reset(
+ new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
}
- // Check if we called CFRetain/CFRelease.
+ // Check if we called CFRetain/CFRelease/CFMakeCollectable.
const IdentifierInfo *FuncII = FD->getIdentifier();
- if (!(FuncII == Retain || FuncII == Release))
+ if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
return;
// FIXME: The rest of this just checks that the argument is non-null.
@@ -426,14 +428,20 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
if (!N)
return;
- const char *description = (FuncII == Retain)
- ? "Null pointer argument in call to CFRetain"
- : "Null pointer argument in call to CFRelease";
+ const char *description;
+ if (FuncII == Retain)
+ description = "Null pointer argument in call to CFRetain";
+ else if (FuncII == Release)
+ description = "Null pointer argument in call to CFRelease";
+ else if (FuncII == MakeCollectable)
+ description = "Null pointer argument in call to CFMakeCollectable";
+ else
+ llvm_unreachable("impossible case");
BugReport *report = new BugReport(*BT, description, N);
report->addRange(Arg->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, Arg, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, Arg, *report);
+ C.emitReport(report);
return;
}
@@ -491,7 +499,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(msg.getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
@@ -644,7 +652,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
R->addRange(msg.getArgSourceRange(I));
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -716,6 +724,73 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
C.addTransition(State);
}
+namespace {
+/// \class ObjCNonNilReturnValueChecker
+/// \brief The checker restricts the return values of APIs known to
+/// never (or almost never) return 'nil'.
+class ObjCNonNilReturnValueChecker
+ : public Checker<check::PostObjCMessage> {
+ mutable bool Initialized;
+ mutable Selector ObjectAtIndex;
+ mutable Selector ObjectAtIndexedSubscript;
+
+public:
+ ObjCNonNilReturnValueChecker() : Initialized(false) {}
+ void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+};
+}
+
+static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
+ ProgramStateRef State,
+ CheckerContext &C) {
+ SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
+ if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
+ return State->assume(*DV, true);
+ return State;
+}
+
+void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
+ CheckerContext &C)
+ const {
+ ProgramStateRef State = C.getState();
+
+ if (!Initialized) {
+ ASTContext &Ctx = C.getASTContext();
+ ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
+ ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
+ }
+
+ // Check the receiver type.
+ if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
+
+ // Assume that object returned from '[self init]' or '[super init]' is not
+ // 'nil' if we are processing an inlined function/method.
+ //
+ // A defensive callee will (and should) check if the object returned by
+ // '[super init]' is 'nil' before doing it's own initialization. However,
+ // since 'nil' is rarely returned in practice, we should not warn when the
+ // caller to the defensive constructor uses the object in contexts where
+ // 'nil' is not accepted.
+ if (!C.inTopFrame() && M.getDecl() &&
+ M.getDecl()->getMethodFamily() == OMF_init &&
+ M.isReceiverSelfOrSuper()) {
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+
+ // Objects returned from
+ // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
+ // are never 'nil'.
+ FoundationClass Cl = findKnownClass(Interface);
+ if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
+ Selector Sel = M.getSelector();
+ if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
+ // Go ahead and assume the value is non-nil.
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+ }
+ }
+ C.addTransition(State);
+}
//===----------------------------------------------------------------------===//
// Check registration.
@@ -744,3 +819,7 @@ void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
void ento::registerObjCLoopChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCLoopChecker>();
}
+
+void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCNonNilReturnValueChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index a4fc396c3edc..92edefe7b170 100644
--- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -35,7 +35,7 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT)
BT.reset(new BuiltinBug("Assignment of a non-Boolean value"));
- C.EmitReport(new BugReport(*BT, BT->getDescription(), N));
+ C.emitReport(new BugReport(*BT, BT->getDescription(), N));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 509bc796fc3c..6ef022b60925 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -55,7 +55,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
// FIXME: Refactor into StoreManager itself?
MemRegionManager& RM = C.getStoreManager().getRegionManager();
const AllocaRegion* R =
- RM.getAllocaRegion(CE, C.getCurrentBlockCount(), C.getLocationContext());
+ RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
// Set the extent of the region in bytes. This enables us to use the
// SVal of the argument directly. If we save the extent in bits, we
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 7fe51d3a4ce3..8e455de3bf46 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -4,7 +4,6 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers
TARGET ClangSACheckers)
add_clang_library(clangStaticAnalyzerCheckers
- AdjustedReturnValueChecker.cpp
AnalyzerStatsChecker.cpp
ArrayBoundChecker.cpp
ArrayBoundCheckerV2.cpp
@@ -28,12 +27,15 @@ add_clang_library(clangStaticAnalyzerCheckers
DeadStoresChecker.cpp
DebugCheckers.cpp
DereferenceChecker.cpp
+ DirectIvarAssignment.cpp
DivZeroChecker.cpp
DynamicTypePropagation.cpp
ExprInspectionChecker.cpp
+ SimpleStreamChecker.cpp
FixedAddressChecker.cpp
GenericTaintChecker.cpp
IdempotentOperationChecker.cpp
+ IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
MacOSKeychainAPIChecker.cpp
MacOSXAPIChecker.cpp
@@ -43,10 +45,10 @@ add_clang_library(clangStaticAnalyzerCheckers
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
- OSAtomicChecker.cpp
ObjCAtSyncChecker.cpp
ObjCContainersASTChecker.cpp
ObjCContainersChecker.cpp
+ ObjCMissingSuperCallChecker.cpp
ObjCSelfInitChecker.cpp
ObjCUnusedIVarsChecker.cpp
PointerArithChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 483082a37f44..eae9ddfc05b9 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -188,21 +188,9 @@ public:
NonLoc right) const;
};
-class CStringLength {
-public:
- typedef llvm::ImmutableMap<const MemRegion *, SVal> EntryMap;
-};
} //end anonymous namespace
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<CStringLength>
- : public ProgramStatePartialTrait<CStringLength::EntryMap> {
- static void *GDMIndex() { return CStringChecker::getTag(); }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
//===----------------------------------------------------------------------===//
// Individual checks and utility methods.
@@ -252,8 +240,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(S->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, S, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, S, *report);
+ C.emitReport(report);
return NULL;
}
@@ -327,7 +315,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
// reference is outside the range.
report->addRange(S->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return NULL;
}
@@ -544,7 +532,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
report->addRange(First->getSourceRange());
report->addRange(Second->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
@@ -607,7 +595,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
// Generate a report for this bug.
BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N);
- C.EmitReport(report);
+ C.emitReport(report);
return NULL;
}
@@ -673,11 +661,11 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
}
// Otherwise, get a new symbol and update the state.
- unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
- MR, Ex, sizeTy, Count);
+ MR, Ex, sizeTy,
+ C.blockCount());
if (!hypothetical)
state = state->set<CStringLength>(MR, strLength);
@@ -714,7 +702,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
os.str(), N);
report->addRange(Ex->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
return UndefinedVal();
@@ -778,7 +766,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
os.str(), N);
report->addRange(Ex->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
return UndefinedVal();
@@ -826,15 +814,14 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
}
// Invalidate this region.
- unsigned Count = C.getCurrentBlockCount();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- return state->invalidateRegions(R, E, Count, LCtx);
+ return state->invalidateRegions(R, E, C.blockCount(), LCtx);
}
// If we have a non-region value by chance, just remove the binding.
// FIXME: is this necessary or correct? This handles the non-Region
// cases. Is it ever valid to store to these?
- return state->unbindLoc(*L);
+ return state->killBinding(*L);
}
bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
@@ -843,7 +830,7 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
switch (MR->getKind()) {
case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
@@ -957,9 +944,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
} else {
// If we don't know how much we copied, we can at least
// conjure a return value for later.
- unsigned Count = C.getCurrentBlockCount();
- SVal result =
- C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ SVal result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx,
+ C.blockCount());
state = state->BindExpr(CE, LCtx, result);
}
@@ -1093,8 +1079,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
state = CheckBufferAccess(C, state, Size, Left, Right);
if (state) {
// The return value is the comparison result, which we don't know.
- unsigned Count = C.getCurrentBlockCount();
- SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ SVal CmpV = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
state = state->BindExpr(CE, LCtx, CmpV);
C.addTransition(state);
}
@@ -1206,8 +1191,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// no guarantee the full string length will actually be returned.
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
- unsigned Count = C.getCurrentBlockCount();
- result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
NonLoc *resultNL = cast<NonLoc>(&result);
if (strLengthNL) {
@@ -1234,8 +1218,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
- unsigned Count = C.getCurrentBlockCount();
- result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
}
}
@@ -1612,8 +1595,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (returnEnd && Result.isUnknown()) {
- unsigned Count = C.getCurrentBlockCount();
- Result = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ Result = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
}
// Set the return value.
@@ -1770,8 +1752,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (!canComputeResult) {
// Conjure a symbolic value. It's the best we can do.
- unsigned Count = C.getCurrentBlockCount();
- SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ SVal resultVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
state = state->BindExpr(CE, LCtx, resultVal);
}
@@ -1885,7 +1866,7 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
}
bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
@@ -1895,7 +1876,7 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
@@ -1915,10 +1896,10 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
}
}
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
+ CStringLengthTy::Factory &F = state->get_context<CStringLength>();
// Then loop over the entries in the current state.
- for (CStringLength::EntryMap::iterator I = Entries.begin(),
+ for (CStringLengthTy::iterator I = Entries.begin(),
E = Entries.end(); I != E; ++I) {
const MemRegion *MR = I.getKey();
@@ -1945,9 +1926,9 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
void CStringChecker::checkLiveSymbols(ProgramStateRef state,
SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+ for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
@@ -1963,12 +1944,12 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
return;
ProgramStateRef state = C.getState();
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return;
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+ CStringLengthTy::Factory &F = state->get_context<CStringLength>();
+ for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
if (SymbolRef Sym = Len.getAsSymbol()) {
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index befc935d4f34..f1a3aacc7c4c 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -33,7 +33,6 @@ namespace {
class WalkAST: public StmtVisitor<WalkAST> {
BugReporter &BR;
AnalysisDeclContext* AC;
- ASTContext &ASTC;
/// Check if two expressions refer to the same declaration.
inline bool sameDecl(const Expr *A1, const Expr *A2) {
@@ -58,8 +57,8 @@ class WalkAST: public StmtVisitor<WalkAST> {
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD)
return false;
- return (CheckerContext::isCLibraryFunction(FD, "strlen", ASTC)
- && sameDecl(CE->getArg(0), WithArg));
+ return (CheckerContext::isCLibraryFunction(FD, "strlen") &&
+ sameDecl(CE->getArg(0), WithArg));
}
return false;
}
@@ -83,7 +82,7 @@ class WalkAST: public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br, AnalysisDeclContext* ac) :
- BR(br), AC(ac), ASTC(AC->getASTContext()) {
+ BR(br), AC(ac) {
}
// Statement visitor methods.
@@ -136,7 +135,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (!FD)
return;
- if (CheckerContext::isCLibraryFunction(FD, "strncat", ASTC)) {
+ if (CheckerContext::isCLibraryFunction(FD, "strncat")) {
if (containsBadStrncatPattern(CE)) {
const Expr *DstArg = CE->getArg(0);
const Expr *LenArg = CE->getArg(2);
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 5edcf09f1150..82bc1361acfe 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -75,13 +75,13 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
if (BadE) {
R->addRange(BadE->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, BadE, R);
+ bugreporter::trackNullOrUndefValue(N, BadE, *R);
}
- C.EmitReport(R);
+ C.emitReport(R);
}
-StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
- bool IsFirstArgument) {
+static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
+ bool IsFirstArgument) {
switch (Call.getKind()) {
case CE_ObjCMessage: {
const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
@@ -122,8 +122,8 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
BugReport *R = new BugReport(*BT, Desc, N);
R->addRange(argRange);
if (argEx)
- bugreporter::addTrackNullOrUndefValueVisitor(N, argEx, R);
- C.EmitReport(R);
+ bugreporter::trackNullOrUndefValue(N, argEx, *R);
+ C.emitReport(R);
}
return true;
}
@@ -207,7 +207,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
// FIXME: enhance track back for uninitialized value for arbitrary
// memregions
- C.EmitReport(R);
+ C.emitReport(R);
}
return true;
}
@@ -335,8 +335,8 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
if (const Expr *ReceiverE = ME->getInstanceReceiver())
- bugreporter::addTrackNullOrUndefValueVisitor(N, ReceiverE, R);
- C.EmitReport(R);
+ bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
+ C.emitReport(R);
}
return;
} else {
@@ -377,9 +377,9 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
report->addRange(ME->getReceiverRange());
// FIXME: This won't track "self" in messages to super.
if (const Expr *receiver = ME->getInstanceReceiver()) {
- bugreporter::addTrackNullOrUndefValueVisitor(N, receiver, report);
+ bugreporter::trackNullOrUndefValue(N, receiver, *report);
}
- C.EmitReport(report);
+ C.emitReport(report);
}
static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 2e184fbaf946..1cb8a8de7348 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -75,7 +75,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
BugReport *R = new BugReport(*BT, BT->getDescription(),
errorNode);
R->addRange(CE->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 1407638fcd69..d6d0e3c7b3b8 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -64,7 +64,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,
"errors or data corruption."));
BugReport *R = new BugReport(*BT,BT->getDescription(), N);
R->addRange(CE->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 7a2586557168..90872058af55 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -85,7 +85,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
Expr::NPC_ValueDependentIsNull)) {
// This is only a 'release' if the property kind is not
// 'assign'.
- return PD->getSetterKind() != ObjCPropertyDecl::Assign;;
+ return PD->getSetterKind() != ObjCPropertyDecl::Assign;
}
// Recurse to children.
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index b8b7c367969c..5cd61941841d 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -270,6 +270,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
// Emit the error. First figure out which DeclRefExpr in the condition
// referenced the compared variable.
+ assert(drInc->getDecl());
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
SmallVector<SourceRange, 2> ranges;
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index 0e9efaa5ade8..efaec2b3f1e3 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -25,6 +25,7 @@ using namespace ento;
// All checkers should be placed into anonymous namespace.
// We place the CheckerDocumentation inside ento namespace to make the
// it visible in doxygen.
+namespace clang {
namespace ento {
/// This checker documents the callback functions checkers can use to implement
@@ -33,8 +34,8 @@ namespace ento {
/// checking.
///
/// \sa CheckerContext
-class CheckerDocumentation : public Checker< check::PreStmt<DeclStmt>,
- check::PostStmt<CallExpr>,
+class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
+ check::PostStmt<DeclStmt>,
check::PreObjCMessage,
check::PostObjCMessage,
check::PreCall,
@@ -64,8 +65,8 @@ public:
/// See checkBranchCondition() callback for performing custom processing of
/// the branching statements.
///
- /// check::PreStmt<DeclStmt>
- void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {}
+ /// check::PreStmt<ReturnStmt>
+ void checkPreStmt(const ReturnStmt *DS, CheckerContext &C) const {}
/// \brief Post-visit the Statement.
///
@@ -74,8 +75,8 @@ public:
/// which does not include the control flow statements such as IfStmt. The
/// callback can be specialized to be called with any subclass of Stmt.
///
- /// check::PostStmt<CallExpr>
- void checkPostStmt(const CallExpr *DS, CheckerContext &C) const;
+ /// check::PostStmt<DeclStmt>
+ void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
/// \brief Pre-visit the Objective C message.
///
@@ -98,8 +99,8 @@ public:
/// behavior for functions and methods no matter how they are being invoked.
///
/// Note that this includes ALL cross-body invocations, so if you want to
- /// limit your checks to, say, function calls, you can either test for that
- /// or fall back to the explicit callback (i.e. check::PreStmt).
+ /// limit your checks to, say, function calls, you should test for that at the
+ /// beginning of your callback function.
///
/// check::PreCall
void checkPreCall(const CallEvent &Call, CheckerContext &C) const {}
@@ -151,9 +152,8 @@ public:
/// check::DeadSymbols
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const {}
- /// \brief Called when an end of path is reached in the ExplodedGraph.
- ///
- /// This callback should be used to check if the allocated resources are freed.
+ /// \brief Called when the analyzer core reaches the end of the top-level
+ /// function being analyzed.
///
/// check::EndPath
void checkEndPath(CheckerContext &Ctx) const {}
@@ -213,21 +213,35 @@ public:
/// check::LiveSymbols
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const {}
-
+ /// \brief Called to determine if the checker currently needs to know if when
+ /// contents of any regions change.
+ ///
+ /// Since it is not necessarily cheap to compute which regions are being
+ /// changed, this allows the analyzer core to skip the more expensive
+ /// #checkRegionChanges when no checkers are tracking any state.
bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; }
- /// \brief Allows tracking regions which get invalidated.
+ /// \brief Called when the contents of one or more regions change.
+ ///
+ /// This can occur in many different ways: an explicit bind, a blanket
+ /// invalidation of the region contents, or by passing a region to a function
+ /// call whose behavior the analyzer cannot model perfectly.
///
/// \param State The current program state.
/// \param Invalidated A set of all symbols potentially touched by the change.
/// \param ExplicitRegions The regions explicitly requested for invalidation.
- /// For example, in the case of a function call, these would be arguments.
- /// \param Regions The transitive closure of accessible regions,
- /// i.e. all regions that may have been touched by this change.
- /// \param Call The call expression wrapper if the regions are invalidated
- /// by a call, 0 otherwise.
- /// Note, in order to be notified, the checker should also implement the
- /// wantsRegionChangeUpdate callback.
+ /// For a function call, this would be the arguments. For a bind, this
+ /// would be the region being bound to.
+ /// \param Regions The transitive closure of regions accessible from,
+ /// \p ExplicitRegions, i.e. all regions that may have been touched
+ /// by this change. For a simple bind, this list will be the same as
+ /// \p ExplicitRegions, since a bind does not affect the contents of
+ /// anything accessible through the base region.
+ /// \param Call The opaque call triggering this invalidation. Will be 0 if the
+ /// change was not triggered by a call.
+ ///
+ /// Note that this callback will not be invoked unless
+ /// #wantsRegionChangeUpdate returns \c true.
///
/// check::RegionChanges
ProgramStateRef
@@ -256,9 +270,10 @@ public:
};
-void CheckerDocumentation::checkPostStmt(const CallExpr *DS,
+void CheckerDocumentation::checkPostStmt(const DeclStmt *DS,
CheckerContext &C) const {
return;
}
-} // end namespace
+} // end namespace ento
+} // end namespace clang
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 8110bd0e18c2..235e63306f04 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -13,33 +13,33 @@ include "clang/StaticAnalyzer/Checkers/CheckerBase.td"
// Packages.
//===----------------------------------------------------------------------===//
-def Experimental : Package<"experimental">;
+def Alpha : Package<"alpha">;
def Core : Package<"core">;
def CoreBuiltin : Package<"builtin">, InPackage<Core>;
def CoreUninitialized : Package<"uninitialized">, InPackage<Core>;
-def CoreExperimental : Package<"core">, InPackage<Experimental>, Hidden;
+def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
def Cplusplus : Package<"cplusplus">;
-def CplusplusExperimental : Package<"cplusplus">, InPackage<Experimental>, Hidden;
+def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden;
def DeadCode : Package<"deadcode">;
-def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden;
+def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
def Security : Package <"security">;
def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
-def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden;
-def Taint : Package<"taint">, InPackage<SecurityExperimental>, Hidden;
+def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
+def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden;
def Unix : Package<"unix">;
-def UnixExperimental : Package<"unix">, InPackage<Experimental>, Hidden;
+def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden;
def CString : Package<"cstring">, InPackage<Unix>, Hidden;
-def CStringExperimental : Package<"cstring">, InPackage<UnixExperimental>, Hidden;
+def CStringAlpha : Package<"cstring">, InPackage<UnixAlpha>, Hidden;
def OSX : Package<"osx">;
-def OSXExperimental : Package<"osx">, InPackage<Experimental>, Hidden;
+def OSXAlpha : Package<"osx">, InPackage<Alpha>, Hidden;
def Cocoa : Package<"cocoa">, InPackage<OSX>;
-def CocoaExperimental : Package<"cocoa">, InPackage<OSXExperimental>, Hidden;
+def CocoaAlpha : Package<"cocoa">, InPackage<OSXAlpha>, Hidden;
def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
def Containers : Package<"containers">, InPackage<CoreFoundation>;
@@ -60,10 +60,6 @@ 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 AdjustedReturnValueChecker : Checker<"AdjustedReturnValue">,
- HelpText<"Check to see if the return value of a function call is different than the caller expects (e.g., from calls through function pointers)">,
- DescFile<"AdjustedReturnValueChecker.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">;
@@ -90,7 +86,7 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
} // end "core"
-let ParentPackage = CoreExperimental in {
+let ParentPackage = CoreAlpha in {
def BoolAssignmentChecker : Checker<"BoolAssignment">,
HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
@@ -120,7 +116,7 @@ def SizeofPointerChecker : Checker<"SizeofPtr">,
HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
DescFile<"CheckSizeofPointer.cpp">;
-} // end "core.experimental"
+} // end "alpha.core"
//===----------------------------------------------------------------------===//
// Evaluate "builtin" functions.
@@ -170,13 +166,13 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
// C++ checkers.
//===----------------------------------------------------------------------===//
-let ParentPackage = CplusplusExperimental in {
+let ParentPackage = CplusplusAlpha in {
def VirtualCallChecker : Checker<"VirtualCall">,
HelpText<"Check virtual function calls during construction or destruction">,
DescFile<"VirtualCallChecker.cpp">;
-} // end: "cplusplus.experimental"
+} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
// Deadcode checkers.
@@ -189,7 +185,7 @@ def DeadStoresChecker : Checker<"DeadStores">,
DescFile<"DeadStoresChecker.cpp">;
} // end DeadCode
-let ParentPackage = DeadCodeExperimental in {
+let ParentPackage = DeadCodeAlpha in {
def IdempotentOperationChecker : Checker<"IdempotentOperations">,
HelpText<"Warn about idempotent operations">,
@@ -199,7 +195,7 @@ def UnreachableCodeChecker : Checker<"UnreachableCode">,
HelpText<"Check unreachable code">,
DescFile<"UnreachableCodeChecker.cpp">;
-} // end "deadcode.experimental"
+} // end "alpha.deadcode"
//===----------------------------------------------------------------------===//
// Security checkers.
@@ -237,7 +233,7 @@ let ParentPackage = Security in {
DescFile<"CheckSecuritySyntaxOnly.cpp">;
}
-let ParentPackage = SecurityExperimental in {
+let ParentPackage = SecurityAlpha in {
def ArrayBoundChecker : Checker<"ArrayBound">,
HelpText<"Warn about buffer overflows (older checker)">,
@@ -255,7 +251,7 @@ def MallocOverflowSecurityChecker : Checker<"MallocOverflow">,
HelpText<"Check for overflows in the arguments to malloc()">,
DescFile<"MallocOverflowSecurityChecker.cpp">;
-} // end "security.experimental"
+} // end "alpha.security"
//===----------------------------------------------------------------------===//
// Taint checkers.
@@ -267,7 +263,7 @@ def GenericTaintChecker : Checker<"TaintPropagation">,
HelpText<"Generate taint information used by other checkers">,
DescFile<"GenericTaintChecker.cpp">;
-} // end "experimental.security.taint"
+} // end "alpha.security.taint"
//===----------------------------------------------------------------------===//
// Unix API checkers.
@@ -289,7 +285,7 @@ def MallocSizeofChecker : Checker<"MallocSizeof">,
} // end "unix"
-let ParentPackage = UnixExperimental in {
+let ParentPackage = UnixAlpha in {
def ChrootChecker : Checker<"Chroot">,
HelpText<"Check improper use of chroot">,
@@ -307,7 +303,11 @@ def StreamChecker : Checker<"Stream">,
HelpText<"Check stream handling functions">,
DescFile<"StreamChecker.cpp">;
-} // end "unix.experimental"
+def SimpleStreamChecker : Checker<"SimpleStream">,
+ HelpText<"Check for misuses of stream APIs">,
+ DescFile<"SimpleStreamChecker.cpp">;
+
+} // end "alpha.unix"
let ParentPackage = CString in {
@@ -320,7 +320,7 @@ def CStringSyntaxChecker : Checker<"BadSizeArg">,
DescFile<"CStringSyntaxChecker.cpp">;
}
-let ParentPackage = CStringExperimental in {
+let ParentPackage = CStringAlpha in {
def CStringOutOfBounds : Checker<"OutOfBounds">,
HelpText<"Check for out-of-bounds access in string functions">,
@@ -346,11 +346,6 @@ def MacOSXAPIChecker : Checker<"API">,
HelpText<"Check for proper uses of various Mac OS X APIs">,
DescFile<"MacOSXAPIChecker.cpp">;
-def OSAtomicChecker : Checker<"AtomicCAS">,
- InPackage<OSX>,
- HelpText<"Evaluate calls to OSAtomic functions">,
- DescFile<"OSAtomicChecker.cpp">;
-
def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
InPackage<OSX>,
HelpText<"Check for proper uses of Secure Keychain APIs">,
@@ -397,6 +392,10 @@ def ObjCLoopChecker : Checker<"Loops">,
HelpText<"Improved modeling of loops using Cocoa collection types">,
DescFile<"BasicObjCFoundationChecks.cpp">;
+def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">,
+ HelpText<"Model the APIs that are guaranteed to return a non-nil value">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
def NSErrorChecker : Checker<"NSError">,
HelpText<"Check usage of NSError** parameters">,
DescFile<"NSErrorChecker.cpp">;
@@ -407,13 +406,25 @@ def RetainCountChecker : Checker<"RetainCount">,
} // end "osx.cocoa"
-let ParentPackage = CocoaExperimental in {
+let ParentPackage = CocoaAlpha in {
def ObjCDeallocChecker : Checker<"Dealloc">,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
DescFile<"CheckObjCDealloc.cpp">;
-} // end "cocoa.experimental"
+def IvarInvalidationChecker : Checker<"InstanceVariableInvalidation">,
+ HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
+ 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">,
+ DescFile<"DirectIvarAssignment.cpp">;
+
+def ObjCSuperCallChecker : Checker<"MissingSuperCall">,
+ HelpText<"Warn about Objective-C methods that lack a necessary call to super">,
+ DescFile<"ObjCMissingSuperCallChecker.cpp">;
+
+} // end "alpha.osx.cocoa"
let ParentPackage = CoreFoundation in {
@@ -422,7 +433,7 @@ def CFNumberCreateChecker : Checker<"CFNumber">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
- HelpText<"Check for null arguments to CFRetain/CFRelease">,
+ HelpText<"Check for null arguments to CFRetain/CFRelease/CFMakeCollectable">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def CFErrorChecker : Checker<"CFError">,
@@ -479,6 +490,10 @@ def CallGraphDumper : Checker<"DumpCallGraph">,
HelpText<"Display Call Graph">,
DescFile<"DebugCheckers.cpp">;
+def ConfigDumper : Checker<"ConfigDumper">,
+ HelpText<"Dump config table">,
+ DescFile<"DebugCheckers.cpp">;
+
def TraversalDumper : Checker<"DumpTraversal">,
HelpText<"Print branch conditions as they are traversed by the engine">,
DescFile<"TraversalChecker.cpp">;
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 30d060996ea7..c8856162fe89 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -147,7 +147,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
"after chroot"));
BugReport *R = new BugReport(*BT_BreakJail,
BT_BreakJail->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
return;
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 510e8cd8104b..59e03ecd5c61 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -13,22 +13,54 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace ento;
-namespace {
+namespace {
+
+/// A simple visitor to record what VarDecls occur in EH-handling code.
+class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
+public:
+ bool inEH;
+ llvm::DenseSet<const VarDecl *> &S;
+
+ bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ SaveAndRestore<bool> inFinally(inEH, true);
+ return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
+ }
+
+ bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ SaveAndRestore<bool> inCatch(inEH, true);
+ return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
+ }
+
+ bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
+ SaveAndRestore<bool> inCatch(inEH, true);
+ return TraverseStmt(S->getHandlerBlock());
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *DR) {
+ if (inEH)
+ if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
+ S.insert(D);
+ return true;
+ }
+
+ EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
+ inEH(false), S(S) {}
+};
// FIXME: Eventually migrate into its own file, and have it managed by
// AnalysisManager.
@@ -93,6 +125,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;
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
@@ -105,6 +138,23 @@ public:
virtual ~DeadStoreObs() {}
+ bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
+ if (Live.isLive(D))
+ return true;
+ // Lazily construct the set that records which VarDecls are in
+ // EH code.
+ if (!InEH.get()) {
+ InEH.reset(new llvm::DenseSet<const VarDecl *>());
+ EHCodeVisitor V(*InEH.get());
+ V.TraverseStmt(AC->getBody());
+ }
+ // Treat all VarDecls that occur in EH code as being "always live"
+ // when considering to suppress dead stores. Frequently stores
+ // are followed by reads in EH code, but we don't have the ability
+ // to analyze that yet.
+ return InEH->count(D);
+ }
+
void Report(const VarDecl *V, DeadStoreKind dsk,
PathDiagnosticLocation L, SourceRange R) {
if (Escaped.count(V))
@@ -159,7 +209,7 @@ public:
if (VD->getType()->getAs<ReferenceType>())
return;
- if (!Live.isLive(VD) &&
+ if (!isLive(Live, VD) &&
!(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) {
PathDiagnosticLocation ExLoc =
@@ -285,7 +335,7 @@ public:
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused'.
- if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) {
+ if (!isLive(Live, V) && V->getAttr<UnusedAttr>() == 0) {
// Special case: check for initializations with constants.
//
// e.g. : int x = 0;
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 34053cdad638..7ad9c59a1bb2 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -144,3 +144,38 @@ public:
void ento::registerCallGraphDumper(CheckerManager &mgr) {
mgr.registerChecker<CallGraphDumper>();
}
+
+
+//===----------------------------------------------------------------------===//
+// ConfigDumper
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
+public:
+ void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
+ AnalysisManager& mgr,
+ BugReporter &BR) const {
+
+ const AnalyzerOptions::ConfigTable &Config = mgr.options.Config;
+ AnalyzerOptions::ConfigTable::const_iterator I =
+ Config.begin(), E = Config.end();
+
+ std::vector<StringRef> Keys;
+ for (; I != E ; ++I) { Keys.push_back(I->getKey()); }
+ sort(Keys.begin(), Keys.end());
+
+ llvm::errs() << "[config]\n";
+ for (unsigned i = 0, n = Keys.size(); i < n ; ++i) {
+ StringRef Key = Keys[i];
+ I = Config.find(Key);
+ llvm::errs() << Key << " = " << I->second << '\n';
+ }
+ llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
+ }
+};
+}
+
+void ento::registerConfigDumper(CheckerManager &mgr) {
+ mgr.registerChecker<ConfigDumper>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index e98c131ce97d..3ace4be44804 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -39,7 +39,7 @@ public:
CheckerContext &C) const;
void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
- static const MemRegion *AddDerefSource(raw_ostream &os,
+ static void AddDerefSource(raw_ostream &os,
SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex, const ProgramState *state,
const LocationContext *LCtx,
@@ -47,7 +47,7 @@ public:
};
} // end anonymous namespace
-const MemRegion *
+void
DereferenceChecker::AddDerefSource(raw_ostream &os,
SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex,
@@ -55,7 +55,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
const LocationContext *LCtx,
bool loadedFrom) {
Ex = Ex->IgnoreParenLValueCasts();
- const MemRegion *sourceR = 0;
switch (Ex->getStmtClass()) {
default:
break;
@@ -65,7 +64,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
os << " (" << (loadedFrom ? "loaded from" : "from")
<< " variable '" << VD->getName() << "')";
Ranges.push_back(DR->getSourceRange());
- sourceR = state->getLValue(VD, LCtx).getAsRegion();
}
break;
}
@@ -78,7 +76,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
break;
}
}
- return sourceR;
}
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
@@ -94,6 +91,8 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
BT_null.reset(new BuiltinBug("Dereference of null pointer"));
SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
SmallVector<SourceRange, 2> Ranges;
// Walk through lvalue casts to get the original expression
@@ -101,8 +100,6 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
if (const Expr *expr = dyn_cast<Expr>(S))
S = expr->IgnoreParenLValueCasts();
- const MemRegion *sourceR = 0;
-
if (IsBind) {
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
if (BO->isAssignmentOp())
@@ -117,68 +114,55 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
switch (S->getStmtClass()) {
case Stmt::ArraySubscriptExprClass: {
- llvm::raw_svector_ostream os(buf);
os << "Array access";
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
- sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext());
+ AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
+ State.getPtr(), N->getLocationContext());
os << " results in a null pointer dereference";
break;
}
case Stmt::UnaryOperatorClass: {
- llvm::raw_svector_ostream os(buf);
os << "Dereference of null pointer";
const UnaryOperator *U = cast<UnaryOperator>(S);
- sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
- State.getPtr(), N->getLocationContext(), true);
+ AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
+ State.getPtr(), N->getLocationContext(), true);
break;
}
case Stmt::MemberExprClass: {
const MemberExpr *M = cast<MemberExpr>(S);
- if (M->isArrow()) {
- llvm::raw_svector_ostream os(buf);
+ if (M->isArrow() || bugreporter::isDeclRefExprToReference(M->getBase())) {
os << "Access to field '" << M->getMemberNameInfo()
<< "' results in a dereference of a null pointer";
- sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext(), true);
+ AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
+ State.getPtr(), N->getLocationContext(), true);
}
break;
}
case Stmt::ObjCIvarRefExprClass: {
const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
- if (const DeclRefExpr *DR =
- dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- llvm::raw_svector_ostream os(buf);
- os << "Instance variable access (via '" << VD->getName()
- << "') results in a null pointer dereference";
- }
- }
- Ranges.push_back(IV->getSourceRange());
+ os << "Access to instance variable '" << *IV->getDecl()
+ << "' results in a dereference of a null pointer";
+ AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
+ State.getPtr(), N->getLocationContext(), true);
break;
}
default:
break;
}
+ os.flush();
BugReport *report =
new BugReport(*BT_null,
buf.empty() ? BT_null->getDescription() : buf.str(),
N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N),
- report);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report);
for (SmallVectorImpl<SourceRange>::iterator
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
report->addRange(*I);
- if (sourceR) {
- report->markInteresting(sourceR);
- report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR)));
- }
-
- C.EmitReport(report);
+ C.emitReport(report);
}
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
@@ -191,11 +175,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDerefExpr(N),
- report);
- report->disablePathPruning();
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N),
+ *report);
+ C.emitReport(report);
}
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
new file mode 100644
index 000000000000..dc90b67e20fa
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -0,0 +1,180 @@
+//=- DirectIvarAssignment.cpp - Check rules on ObjC properties -*- C++ ----*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Check that Objective C properties follow the following rules:
+// - The property should be set with the setter, not though a direct
+// assignment.
+//
+//===----------------------------------------------------------------------===//
+
+#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/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class DirectIvarAssignment :
+ public Checker<check::ASTDecl<ObjCImplementationDecl> > {
+
+ typedef llvm::DenseMap<const ObjCIvarDecl*,
+ const ObjCPropertyDecl*> IvarToPropertyMapTy;
+
+ /// A helper class, which walks the AST and locates all assignments to ivars
+ /// in the given function.
+ class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
+ const IvarToPropertyMapTy &IvarToPropMap;
+ const ObjCMethodDecl *MD;
+ const ObjCInterfaceDecl *InterfD;
+ BugReporter &BR;
+ LocationOrAnalysisDeclContext DCtx;
+
+ public:
+ MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD,
+ const ObjCInterfaceDecl *InID,
+ BugReporter &InBR, AnalysisDeclContext *InDCtx)
+ : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), DCtx(InDCtx) {}
+
+ void VisitStmt(const Stmt *S) { VisitChildren(S); }
+
+ void VisitBinaryOperator(const BinaryOperator *BO);
+
+ void VisitChildren(const Stmt *S) {
+ for (Stmt::const_child_range I = S->children(); I; ++I)
+ if (*I)
+ this->Visit(*I);
+ }
+ };
+
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const;
+};
+
+static const ObjCIvarDecl *findPropertyBackingIvar(const ObjCPropertyDecl *PD,
+ const ObjCInterfaceDecl *InterD,
+ ASTContext &Ctx) {
+ // Check for synthesized ivars.
+ ObjCIvarDecl *ID = PD->getPropertyIvarDecl();
+ if (ID)
+ return ID;
+
+ ObjCInterfaceDecl *NonConstInterD = const_cast<ObjCInterfaceDecl*>(InterD);
+
+ // Check for existing "_PropName".
+ ID = NonConstInterD->lookupInstanceVariable(PD->getDefaultSynthIvarName(Ctx));
+ if (ID)
+ return ID;
+
+ // Check for existing "PropName".
+ IdentifierInfo *PropIdent = PD->getIdentifier();
+ ID = NonConstInterD->lookupInstanceVariable(PropIdent);
+
+ return ID;
+}
+
+void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
+ AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ const ObjCInterfaceDecl *InterD = D->getClassInterface();
+
+
+ IvarToPropertyMapTy IvarToPropMap;
+
+ // Find all properties for this class.
+ for (ObjCInterfaceDecl::prop_iterator I = InterD->prop_begin(),
+ E = InterD->prop_end(); I != E; ++I) {
+ ObjCPropertyDecl *PD = *I;
+
+ // Find the corresponding IVar.
+ const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD,
+ Mgr.getASTContext());
+
+ if (!ID)
+ continue;
+
+ // Store the IVar to property mapping.
+ IvarToPropMap[ID] = PD;
+ }
+
+ if (IvarToPropMap.empty())
+ return;
+
+ for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
+ E = D->instmeth_end(); I != E; ++I) {
+
+ 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)
+ continue;
+
+ const Stmt *Body = M->getBody();
+ assert(Body);
+
+ MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, DCtx);
+ MC.VisitStmt(Body);
+ }
+}
+
+void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
+ const BinaryOperator *BO) {
+ if (!BO->isAssignmentOp())
+ return;
+
+ const ObjCIvarRefExpr *IvarRef =
+ dyn_cast<ObjCIvarRefExpr>(BO->getLHS()->IgnoreParenCasts());
+
+ if (!IvarRef)
+ return;
+
+ if (const ObjCIvarDecl *D = IvarRef->getDecl()) {
+ IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D);
+ if (I != IvarToPropMap.end()) {
+ const ObjCPropertyDecl *PD = I->second;
+
+ ObjCMethodDecl *GetterMethod =
+ InterfD->getInstanceMethod(PD->getGetterName());
+ ObjCMethodDecl *SetterMethod =
+ InterfD->getInstanceMethod(PD->getSetterName());
+
+ if (SetterMethod && SetterMethod->getCanonicalDecl() == MD)
+ return;
+
+ if (GetterMethod && GetterMethod->getCanonicalDecl() == MD)
+ return;
+
+ BR.EmitBasicReport(MD,
+ "Property access",
+ categories::CoreFoundationObjectiveC,
+ "Direct assignment to an instance variable backing a property; "
+ "use the setter instead", PathDiagnosticLocation(IvarRef,
+ BR.getSourceManager(),
+ DCtx));
+ }
+ }
+}
+}
+
+void ento::registerDirectIvarAssignment(CheckerManager &mgr) {
+ mgr.registerChecker<DirectIvarAssignment>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index dcf6a8603ec7..76fb3f2b288e 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -39,13 +39,9 @@ void DivZeroChecker::reportBug(const char *Msg,
if (!BT)
BT.reset(new BuiltinBug("Division by zero"));
- BugReport *R =
- new BugReport(*BT, Msg, N);
-
- bugreporter::addTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDenomExpr(N),
- R);
- C.EmitReport(R);
+ BugReport *R = new BugReport(*BT, Msg, N);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
+ C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index b636efbe35a1..b0a4bc67485e 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -83,14 +83,14 @@ void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
// C++11 [class.cdtor]p4 (see above)
+ if (!Dtor->isBaseDestructor())
+ return;
const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
if (!Target)
return;
- // FIXME: getRuntimeDefinition() can be expensive. It would be better to do
- // this when we are entering the stack frame for the destructor.
- const Decl *D = Dtor->getRuntimeDefinition().getDecl();
+ const Decl *D = Dtor->getDecl();
if (!D)
return;
@@ -105,8 +105,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
// Get the returned value if it's a region.
- SVal Result = C.getSVal(Call.getOriginExpr());
- const MemRegion *RetReg = Result.getAsRegion();
+ const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
if (!RetReg)
return;
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 7acf223e63d6..e7e316281faa 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -93,7 +93,7 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
BT.reset(new BugType("Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
@@ -113,7 +113,7 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
BT.reset(new BugType("Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index a1f2f3b2ba98..7fde68923124 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -58,7 +58,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
"environments or platforms."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index afb862cd6c9a..a9e02173c3a9 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -192,13 +192,7 @@ const char GenericTaintChecker::MsgTaintedBufferSize[] =
/// to the call post-visit. The values are unsigned integers, which are either
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
/// points to data, which should be tainted on return.
-namespace { struct TaintArgsOnPostVisit{}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<TaintArgsOnPostVisit>
- : public ProgramStatePartialTrait<llvm::ImmutableSet<unsigned> > {
- static void *GDMIndex() { return GenericTaintChecker::getTag(); }
-};
-}}
+REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
GenericTaintChecker::TaintPropagationRule
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
@@ -337,7 +331,7 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
// Depending on what was tainted at pre-visit, we determined a set of
// arguments which should be tainted after the function returns. These are
// stored in the state as TaintArgsOnPostVisit set.
- llvm::ImmutableSet<unsigned> TaintArgs = State->get<TaintArgsOnPostVisit>();
+ TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
if (TaintArgs.isEmpty())
return false;
@@ -653,7 +647,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
initBugType();
BugReport *report = new BugReport(*BT, Msg, N);
report->addRange(E->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return true;
}
return false;
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 9d0b83f40b34..ffbbb8b68d8a 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -430,7 +430,7 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS);
}
- BR.EmitReport(report);
+ BR.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
new file mode 100644
index 000000000000..bf256cd9fa45
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -0,0 +1,550 @@
+//=- IvarInvalidationChecker.cpp - -*- C++ -------------------------------*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker implements annotation driven invalidation checking. If a class
+// contains a method annotated with 'objc_instance_variable_invalidator',
+// - (void) foo
+// __attribute__((annotate("objc_instance_variable_invalidator")));
+// all the "ivalidatable" instance variables of this class should be
+// invalidated. We call an instance variable ivalidatable if it is an object of
+// a class which contains an invalidation method. There could be multiple
+// methods annotated with such annotations per class, either one can be used
+// to invalidate the ivar. An ivar or property are considered to be
+// invalidated if they are being assigned 'nil' or an invalidation method has
+// been called on them. An invalidation method should either invalidate all
+// the ivars or call another invalidation method (on self).
+//
+//===----------------------------------------------------------------------===//
+
+#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/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/DenseMap.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;
+ typedef llvm::DenseMap<const ObjCMethodDecl*,
+ const ObjCIvarDecl*> MethToIvarMapTy;
+ typedef llvm::DenseMap<const ObjCPropertyDecl*,
+ const ObjCIvarDecl*> PropToIvarMapTy;
+ typedef llvm::DenseMap<const ObjCIvarDecl*,
+ const ObjCPropertyDecl*> IvarToPropMapTy;
+
+
+ struct IvarInfo {
+ /// Has the ivar been invalidated?
+ bool IsInvalidated;
+
+ /// The methods which can be used to invalidate the ivar.
+ MethodSet InvalidationMethods;
+
+ IvarInfo() : IsInvalidated(false) {}
+ void addInvalidationMethod(const ObjCMethodDecl *MD) {
+ InvalidationMethods.insert(MD);
+ }
+
+ bool needsInvalidation() const {
+ return !InvalidationMethods.empty();
+ }
+
+ void markInvalidated() {
+ IsInvalidated = true;
+ }
+
+ bool markInvalidated(const ObjCMethodDecl *MD) {
+ if (IsInvalidated)
+ return true;
+ for (MethodSet::iterator I = InvalidationMethods.begin(),
+ E = InvalidationMethods.end(); I != E; ++I) {
+ if (*I == MD) {
+ IsInvalidated = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool isInvalidated() const {
+ return IsInvalidated;
+ }
+ };
+
+ typedef llvm::DenseMap<const ObjCIvarDecl*, IvarInfo> IvarSet;
+
+ /// Statement visitor, which walks the method body and flags the ivars
+ /// referenced in it (either directly or via property).
+ class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
+ /// The set of Ivars which need to be invalidated.
+ IvarSet &IVars;
+
+ /// Flag is set as the result of a message send to another
+ /// invalidation method.
+ bool &CalledAnotherInvalidationMethod;
+
+ /// Property setter to ivar mapping.
+ const MethToIvarMapTy &PropertySetterToIvarMap;
+
+ /// Property getter to ivar mapping.
+ const MethToIvarMapTy &PropertyGetterToIvarMap;
+
+ /// Property to ivar mapping.
+ const PropToIvarMapTy &PropertyToIvarMap;
+
+ /// The invalidation method being currently processed.
+ const ObjCMethodDecl *InvalidationMethod;
+
+ ASTContext &Ctx;
+
+ /// Peel off parens, casts, OpaqueValueExpr, and PseudoObjectExpr.
+ const Expr *peel(const Expr *E) const;
+
+ /// Does this expression represent zero: '0'?
+ bool isZero(const Expr *E) const;
+
+ /// Mark the given ivar as invalidated.
+ void markInvalidated(const ObjCIvarDecl *Iv);
+
+ /// Checks if IvarRef refers to the tracked IVar, if yes, marks it as
+ /// invalidated.
+ void checkObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef);
+
+ /// Checks if ObjCPropertyRefExpr refers to the tracked IVar, if yes, marks
+ /// it as invalidated.
+ void checkObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA);
+
+ /// Checks if ObjCMessageExpr refers to (is a getter for) the tracked IVar,
+ /// if yes, marks it as invalidated.
+ void checkObjCMessageExpr(const ObjCMessageExpr *ME);
+
+ /// Checks if the Expr refers to an ivar, if yes, marks it as invalidated.
+ void check(const Expr *E);
+
+ public:
+ MethodCrawler(IvarSet &InIVars,
+ bool &InCalledAnotherInvalidationMethod,
+ const MethToIvarMapTy &InPropertySetterToIvarMap,
+ const MethToIvarMapTy &InPropertyGetterToIvarMap,
+ const PropToIvarMapTy &InPropertyToIvarMap,
+ ASTContext &InCtx)
+ : IVars(InIVars),
+ CalledAnotherInvalidationMethod(InCalledAnotherInvalidationMethod),
+ PropertySetterToIvarMap(InPropertySetterToIvarMap),
+ PropertyGetterToIvarMap(InPropertyGetterToIvarMap),
+ PropertyToIvarMap(InPropertyToIvarMap),
+ InvalidationMethod(0),
+ Ctx(InCtx) {}
+
+ void VisitStmt(const Stmt *S) { VisitChildren(S); }
+
+ void VisitBinaryOperator(const BinaryOperator *BO);
+
+ void VisitObjCMessageExpr(const ObjCMessageExpr *ME);
+
+ void VisitChildren(const Stmt *S) {
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ if (CalledAnotherInvalidationMethod)
+ return;
+ }
+ }
+ };
+
+ /// Check if the any of the methods inside the interface are annotated with
+ /// the invalidation annotation, update the IvarInfo accordingly.
+ static void containsInvalidationMethod(const ObjCContainerDecl *D,
+ IvarInfo &Out);
+
+ /// 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);
+
+ /// Given the property declaration, and the list of tracked ivars, finds
+ /// the ivar backing the property when possible. Returns '0' when no such
+ /// ivar could be found.
+ static const ObjCIvarDecl *findPropertyBackingIvar(
+ const ObjCPropertyDecl *Prop,
+ const ObjCInterfaceDecl *InterfaceD,
+ IvarSet &TrackedIvars);
+
+public:
+ void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const;
+
+ // TODO: We are currently ignoring the ivars coming from class extensions.
+};
+
+static bool isInvalidationMethod(const ObjCMethodDecl *M) {
+ for (specific_attr_iterator<AnnotateAttr>
+ AI = M->specific_attr_begin<AnnotateAttr>(),
+ AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
+ const AnnotateAttr *Ann = *AI;
+ if (Ann->getAnnotation() == "objc_instance_variable_invalidator")
+ return true;
+ }
+ return false;
+}
+
+void IvarInvalidationChecker::containsInvalidationMethod(
+ const ObjCContainerDecl *D, IvarInfo &OutInfo) {
+
+ // TODO: Cache the results.
+
+ if (!D)
+ return;
+
+ // 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))
+ 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)) {
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = InterfaceD->protocol_begin(),
+ E = InterfaceD->protocol_end(); I != E; ++I) {
+ containsInvalidationMethod(*I, OutInfo);
+ }
+ containsInvalidationMethod(InterfaceD->getSuperClass(), OutInfo);
+ return;
+ }
+
+ // If protocol, check all parent protocols.
+ if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) {
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = ProtD->protocol_begin(),
+ E = ProtD->protocol_end(); I != E; ++I) {
+ containsInvalidationMethod(*I, OutInfo);
+ }
+ return;
+ }
+
+ llvm_unreachable("One of the casts above should have succeeded.");
+}
+
+bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
+ IvarSet &TrackedIvars) {
+ QualType IvQTy = Iv->getType();
+ const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
+ if (!IvTy)
+ return false;
+ const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl();
+
+ IvarInfo Info;
+ containsInvalidationMethod(IvInterf, Info);
+ if (Info.needsInvalidation()) {
+ TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info;
+ return true;
+ }
+ return false;
+}
+
+const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
+ const ObjCPropertyDecl *Prop,
+ const ObjCInterfaceDecl *InterfaceD,
+ IvarSet &TrackedIvars) {
+ const ObjCIvarDecl *IvarD = 0;
+
+ // Lookup for the synthesized case.
+ IvarD = Prop->getPropertyIvarDecl();
+ if (IvarD) {
+ if (TrackedIvars.count(IvarD)) {
+ return IvarD;
+ }
+ // If the ivar is synthesized we still want to track it.
+ if (trackIvar(IvarD, TrackedIvars))
+ return IvarD;
+ }
+
+ // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars.
+ StringRef PropName = Prop->getIdentifier()->getName();
+ for (IvarSet::const_iterator I = TrackedIvars.begin(),
+ E = TrackedIvars.end(); I != E; ++I) {
+ const ObjCIvarDecl *Iv = I->first;
+ StringRef IvarName = Iv->getName();
+
+ if (IvarName == PropName)
+ return Iv;
+
+ SmallString<128> PropNameWithUnderscore;
+ {
+ llvm::raw_svector_ostream os(PropNameWithUnderscore);
+ os << '_' << PropName;
+ }
+ if (IvarName == PropNameWithUnderscore.str())
+ return Iv;
+ }
+
+ // Note, this is a possible source of false positives. We could look at the
+ // getter implementation to find the ivar when its name is not derived from
+ // the property name.
+ return 0;
+}
+
+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;
+
+ // Collect all ivars that need cleanup.
+ IvarSet Ivars;
+ const ObjCInterfaceDecl *InterfaceD = D->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);
+
+ // Construct Property/Property Accessor to Ivar maps to assist checking if an
+ // ivar which is backing a property has been reset.
+ MethToIvarMapTy PropSetterToIvarMap;
+ MethToIvarMapTy PropGetterToIvarMap;
+ PropToIvarMapTy PropertyToIvarMap;
+ IvarToPropMapTy IvarToPopertyMap;
+
+ ObjCInterfaceDecl::PropertyMap PropMap;
+ InterfaceD->collectPropertiesToImplement(PropMap);
+
+ 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) {
+ continue;
+ }
+
+ // Store the mappings.
+ PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
+ PropertyToIvarMap[PD] = ID;
+ IvarToPopertyMap[ID] = PD;
+
+ // Find the setter and the getter.
+ const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl();
+ if (SetterD) {
+ SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl());
+ PropSetterToIvarMap[SetterD] = ID;
+ }
+
+ const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl();
+ if (GetterD) {
+ GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl());
+ PropGetterToIvarMap[GetterD] = ID;
+ }
+ }
+
+
+ // 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 (CalledAnotherInvalidationMethod)
+ 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";
+ }
+
+ BR.EmitBasicReport(D,
+ "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ IvarDecLocation);
+ }
+ }
+}
+
+void IvarInvalidationChecker::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();
+ }
+}
+
+const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
+ E = E->IgnoreParenCasts();
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ E = POE->getSyntacticForm()->IgnoreParenCasts();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ E = OVE->getSourceExpr()->IgnoreParenCasts();
+ return E;
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr(
+ const ObjCIvarRefExpr *IvarRef) {
+ if (const Decl *D = IvarRef->getDecl())
+ markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
+ const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (MD) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD);
+ if (IvI != PropertyGetterToIvarMap.end())
+ markInvalidated(IvI->second);
+ }
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
+ const ObjCPropertyRefExpr *PA) {
+
+ if (PA->isExplicitProperty()) {
+ const ObjCPropertyDecl *PD = PA->getExplicitProperty();
+ if (PD) {
+ PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
+ PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD);
+ if (IvI != PropertyToIvarMap.end())
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+
+ if (PA->isImplicitProperty()) {
+ const ObjCMethodDecl *MD = PA->getImplicitPropertySetter();
+ if (MD) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD);
+ if (IvI != PropertyGetterToIvarMap.end())
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+}
+
+bool IvarInvalidationChecker::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) {
+ E = peel(E);
+
+ if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
+ checkObjCIvarRefExpr(IvarRef);
+ return;
+ }
+
+ if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ checkObjCPropertyRefExpr(PropRef);
+ return;
+ }
+
+ if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
+ checkObjCMessageExpr(MsgExpr);
+ return;
+ }
+}
+
+void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
+ const BinaryOperator *BO) {
+ VisitStmt(BO);
+
+ if (BO->getOpcode() != BO_Assign)
+ return;
+
+ // Do we assign zero?
+ if (!isZero(BO->getRHS()))
+ return;
+
+ // Check the variable we are assigning to.
+ check(BO->getLHS());
+}
+
+void IvarInvalidationChecker::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->isObjCSelfExpr()) {
+ CalledAnotherInvalidationMethod = true;
+ return;
+ }
+
+ // Check if we call a setter and set the property to 'nil'.
+ if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD);
+ if (IvI != PropertySetterToIvarMap.end()) {
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+
+ // Check if we call the 'invalidation' routine on the ivar.
+ if (Receiver) {
+ InvalidationMethod = MD;
+ check(Receiver->IgnoreParenCasts());
+ InvalidationMethod = 0;
+ }
+
+ VisitStmt(ME);
+}
+}
+
+// Register the checker.
+void ento::registerIvarInvalidationChecker(CheckerManager &mgr) {
+ mgr.registerChecker<IvarInvalidationChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 969f2ddeb4ca..76f20b6e2e51 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -158,16 +158,9 @@ private:
/// ProgramState traits to store the currently allocated (and not yet freed)
/// symbols. This is a map from the allocated content symbol to the
/// corresponding AllocationState.
-typedef llvm::ImmutableMap<SymbolRef,
- MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy;
-
-namespace { struct AllocatedData {}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<AllocatedData>
- : public ProgramStatePartialTrait<AllocatedSetTy > {
- static void *GDMIndex() { static int index = 0; return &index; }
-};
-}}
+REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData,
+ SymbolRef,
+ MacOSKeychainAPIChecker::AllocationState)
static bool isEnclosingFunctionParam(const Expr *E) {
E = E->IgnoreParenCasts();
@@ -282,7 +275,7 @@ void MacOSKeychainAPIChecker::
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
Report->addRange(ArgExpr->getSourceRange());
markInteresting(Report, AP);
- C.EmitReport(Report);
+ C.emitReport(Report);
}
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
@@ -323,7 +316,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
Report->addVisitor(new SecKeychainBugVisitor(V));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
- C.EmitReport(Report);
+ C.emitReport(Report);
}
}
return;
@@ -376,7 +369,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
Report->addRange(ArgExpr->getSourceRange());
if (AS)
Report->markInteresting(AS->Region);
- C.EmitReport(Report);
+ C.emitReport(Report);
return;
}
@@ -440,7 +433,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
- C.EmitReport(Report);
+ C.emitReport(Report);
return;
}
@@ -571,13 +564,13 @@ BugReport *MacOSKeychainAPIChecker::
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- AllocatedSetTy ASet = State->get<AllocatedData>();
+ AllocatedDataTy ASet = State->get<AllocatedData>();
if (ASet.isEmpty())
return;
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
+ for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
if (SR.isLive(I->first))
continue;
@@ -585,7 +578,9 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
State = State->remove<AllocatedData>(I->first);
// If the allocated symbol is null or if the allocation call might have
// returned an error, do not report.
- if (State->getSymVal(I->first) ||
+ 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));
@@ -602,7 +597,7 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
// Generate the error reports.
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
I != E; ++I) {
- C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
+ C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
}
// Generate the new, cleaned up state.
@@ -617,7 +612,7 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
if (C.getLocationContext()->getParent() != 0)
return;
- AllocatedSetTy AS = state->get<AllocatedData>();
+ AllocatedDataTy AS = state->get<AllocatedData>();
if (AS.isEmpty())
return;
@@ -625,12 +620,14 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
// found here, so report it.
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
+ 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.
- if (state->getSymVal(I.getKey()) ||
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (AllocFailed.isConstrainedTrue() ||
definitelyReturnedError(I->second.Region, state,
C.getSValBuilder())) {
continue;
@@ -650,7 +647,7 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
// Generate the error reports.
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
I != E; ++I) {
- C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
+ C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
}
C.addTransition(state, N);
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index cfdb55df730d..467b8b1d815c 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -70,6 +70,16 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
"Mac OS X API"));
+ // 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.
+ // _dispatch_once is then a function which then calls the real dispatch_once.
+ // Users do not care; they just want the warning at the top-level call.
+ if (CE->getLocStart().isMacroID()) {
+ StringRef TrimmedFName = FName.ltrim("_");
+ if (TrimmedFName != FName)
+ FName = TrimmedFName;
+ }
+
SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << FName << "' uses";
@@ -84,7 +94,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
//===----------------------------------------------------------------------===//
@@ -99,7 +109,9 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
SubChecker SC =
llvm::StringSwitch<SubChecker>(Name)
- .Cases("dispatch_once", "dispatch_once_f",
+ .Cases("dispatch_once",
+ "_dispatch_once",
+ "dispatch_once_f",
&MacOSXAPIChecker::CheckDispatchOnce)
.Default(NULL);
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index dfcedf640821..caf70ca3706f 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include <climits>
using namespace clang;
@@ -70,17 +71,31 @@ public:
}
};
+enum ReallocPairKind {
+ RPToBeFreedAfterFailure,
+ // The symbol has been freed when reallocation failed.
+ RPIsFreeOnFailure,
+ // The symbol does not need to be freed after reallocation fails.
+ RPDoNotTrackAfterFailure
+};
+
+/// \class ReallocPair
+/// \brief Stores information about the symbol being reallocated by a call to
+/// 'realloc' to allow modeling failed reallocation later in the path.
struct ReallocPair {
+ // \brief The symbol which realloc reallocated.
SymbolRef ReallocatedSym;
- bool IsFreeOnFailure;
- ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
+ ReallocPairKind Kind;
+
+ ReallocPair(SymbolRef S, ReallocPairKind K) :
+ ReallocatedSym(S), Kind(K) {}
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(IsFreeOnFailure);
+ ID.AddInteger(Kind);
ID.AddPointer(ReallocatedSym);
}
bool operator==(const ReallocPair &X) const {
return ReallocatedSym == X.ReallocatedSym &&
- IsFreeOnFailure == X.IsFreeOnFailure;
+ Kind == X.Kind;
}
};
@@ -92,7 +107,7 @@ class MallocChecker : public Checker<check::DeadSymbols,
check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
check::PostStmt<BlockExpr>,
- check::PreObjCMessage,
+ check::PostObjCMessage,
check::Location,
check::Bind,
eval::Assume,
@@ -120,7 +135,7 @@ public:
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkPreObjCMessage(const ObjCMethodCall &Call, 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;
@@ -177,11 +192,15 @@ private:
const OwnershipAttr* Att) const;
ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, unsigned Num,
- bool Hold) const;
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure = false) const;
ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg,
const Expr *ParentExpr,
- ProgramStateRef state,
- bool Hold) const;
+ ProgramStateRef State,
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure = false) const;
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
bool FreesMemOnFailure) const;
@@ -301,13 +320,14 @@ private:
: StackHintGeneratorForSymbol(S, M) {}
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) {
+ // Printed parameters start at 1, not 0.
+ ++ArgIndex;
+
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << "Reallocation of ";
- // Printed parameters start at 1, not 0.
- printOrdinal(++ArgIndex, os);
- os << " parameter failed";
+ os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
+ << " parameter failed";
return os.str();
}
@@ -320,25 +340,12 @@ private:
};
} // end anonymous namespace
-typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap;
-class RegionState {};
-class ReallocPairs {};
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<RegionState>
- : public ProgramStatePartialTrait<RegionStateTy> {
- static void *GDMIndex() { static int x; return &x; }
- };
+REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
+REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
- template <>
- struct ProgramStateTrait<ReallocPairs>
- : public ProgramStatePartialTrait<ReallocMap> {
- static void *GDMIndex() { static int x; return &x; }
- };
-}
-}
+// A map from the freed symbol to the symbol representing the return value of
+// the free function.
+REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)
namespace {
class StopTrackingCallback : public SymbolVisitor {
@@ -426,11 +433,15 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const
}
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
+ if (C.wasInlined)
+ return;
+
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
ProgramStateRef State = C.getState();
+ bool ReleasedAllocatedMemory = false;
if (FD->getKind() == Decl::Function) {
initIdentifierInfo(C.getASTContext());
@@ -447,7 +458,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
} else if (FunI == II_calloc) {
State = CallocMem(C, CE);
} else if (FunI == II_free) {
- State = FreeMemAux(C, CE, State, 0, false);
+ State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup) {
State = MallocUpdateRefState(C, CE, State);
} else if (FunI == II_strndup) {
@@ -487,21 +498,26 @@ static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
return false;
}
-void MallocChecker::checkPreObjCMessage(const ObjCMethodCall &Call,
- CheckerContext &C) const {
+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;
- C.addTransition(FreeMemAux(C, Call.getArgExpr(argIdx),
- Call.getOriginExpr(), C.getState(), true));
+ ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(argIdx),
+ Call.getOriginExpr(), C.getState(), true,
+ ReleasedAllocatedMemory,
+ /* RetNullOnFailure*/ true);
+
+ C.addTransition(State);
}
}
@@ -526,7 +542,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
// 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
// side effects other than what we model here.
- unsigned Count = C.getCurrentBlockCount();
+ unsigned Count = C.blockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
@@ -584,11 +600,13 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
return 0;
ProgramStateRef State = C.getState();
+ bool ReleasedAllocated = false;
for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
I != E; ++I) {
ProgramStateRef StateI = FreeMemAux(C, CE, State, *I,
- Att->getOwnKind() == OwnershipAttr::Holds);
+ Att->getOwnKind() == OwnershipAttr::Holds,
+ ReleasedAllocated);
if (StateI)
State = StateI;
}
@@ -599,20 +617,40 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const CallExpr *CE,
ProgramStateRef state,
unsigned Num,
- bool Hold) const {
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure) const {
if (CE->getNumArgs() < (Num + 1))
return 0;
- return FreeMemAux(C, CE->getArg(Num), CE, state, Hold);
+ return FreeMemAux(C, CE->getArg(Num), CE, state, Hold,
+ ReleasedAllocated, ReturnsNullOnFailure);
+}
+
+/// 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) {
+ const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
+ if (Ret) {
+ assert(*Ret && "We should not store the null return symbol");
+ ConstraintManager &CMgr = State->getConstraintManager();
+ ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret);
+ RetStatusSymbol = *Ret;
+ return FreeFailed.isConstrainedTrue();
+ }
+ return false;
}
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const Expr *ArgExpr,
const Expr *ParentExpr,
- ProgramStateRef state,
- bool Hold) const {
+ ProgramStateRef State,
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure) const {
- SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
+ SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
if (!isa<DefinedOrUnknownSVal>(ArgVal))
return 0;
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
@@ -623,7 +661,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// The explicit NULL case, no operation is performed.
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = state->assume(location);
+ llvm::tie(notNullState, nullState) = State->assume(location);
if (nullState && !notNullState)
return 0;
@@ -672,10 +710,14 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
return 0;
SymbolRef Sym = SR->getSymbol();
- const RefState *RS = state->get<RegionState>(Sym);
+ const RefState *RS = State->get<RegionState>(Sym);
+ SymbolRef PreviousRetStatusSymbol = 0;
// Check double free.
- if (RS && (RS->isReleased() || RS->isRelinquished())) {
+ if (RS &&
+ (RS->isReleased() || RS->isRelinquished()) &&
+ !didPreviousFreeFail(State, Sym, PreviousRetStatusSymbol)) {
+
if (ExplodedNode *N = C.generateSink()) {
if (!BT_DoubleFree)
BT_DoubleFree.reset(
@@ -685,16 +727,34 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
"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);
+ C.emitReport(R);
}
return 0;
}
+ ReleasedAllocated = (RS != 0);
+
+ // Clean out the info on previous call to free return info.
+ State = State->remove<FreeReturnValue>(Sym);
+
+ // Keep track of the return value. If it is NULL, we will know that free
+ // failed.
+ if (ReturnsNullOnFailure) {
+ SVal RetVal = C.getSVal(ParentExpr);
+ SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
+ if (RetStatusSymbol) {
+ C.getSymbolManager().addSymbolDependency(Sym, RetStatusSymbol);
+ State = State->set<FreeReturnValue>(Sym, RetStatusSymbol);
+ }
+ }
+
// Normal free.
if (Hold)
- return state->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr));
- return state->set<RegionState>(Sym, RefState::getReleased(ParentExpr));
+ return State->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr));
+ return State->set<RegionState>(Sym, RefState::getReleased(ParentExpr));
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -714,7 +774,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
const MemRegion *MR) {
switch (MR->getKind()) {
case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
@@ -819,7 +879,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
R->markInteresting(MR);
R->addRange(range);
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -886,9 +946,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
if (!FromPtr || !ToPtr)
return 0;
+ bool ReleasedAllocated = false;
+
// If the size is 0, free the memory.
if (SizeIsZero)
- if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){
+ if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0,
+ false, ReleasedAllocated)){
// The semantics of the return value are:
// If size was equal to 0, either NULL or a pointer suitable to be passed
// to free() is returned. We just free the input pointer and do not add
@@ -897,14 +960,25 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
}
// Default behavior.
- if (ProgramStateRef stateFree = FreeMemAux(C, CE, state, 0, false)) {
- // FIXME: We should copy the content of the original buffer.
+ if (ProgramStateRef stateFree =
+ FreeMemAux(C, CE, state, 0, false, ReleasedAllocated)) {
+
ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
UnknownVal(), stateFree);
if (!stateRealloc)
return 0;
+
+ ReallocPairKind Kind = RPToBeFreedAfterFailure;
+ if (FreesOnFail)
+ Kind = RPIsFreeOnFailure;
+ else if (!ReleasedAllocated)
+ Kind = RPDoNotTrackAfterFailure;
+
+ // Record the info about the reallocated symbol so that we could properly
+ // process failed reallocation.
stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
- ReallocPair(FromPtr, FreesOnFail));
+ ReallocPair(FromPtr, Kind));
+ // The reallocated symbol should stay alive for as long as the new symbol.
C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
return stateRealloc;
}
@@ -1004,7 +1078,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym, true));
- C.EmitReport(R);
+ C.emitReport(R);
}
void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
@@ -1017,14 +1091,11 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
RegionStateTy RS = state->get<RegionState>();
RegionStateTy::Factory &F = state->get_context<RegionState>();
- bool generateReport = false;
llvm::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()) {
- generateReport = true;
+ if (I->second.isAllocated())
Errors.push_back(I->first);
- }
// Remove the dead symbol from the map.
RS = F.remove(RS, I->first);
@@ -1032,24 +1103,34 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
// Cleanup the Realloc Pairs Map.
- ReallocMap RP = state->get<ReallocPairs>();
- for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ ReallocPairsTy RP = state->get<ReallocPairs>();
+ for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
if (SymReaper.isDead(I->first) ||
SymReaper.isDead(I->second.ReallocatedSym)) {
state = state->remove<ReallocPairs>(I->first);
}
}
- // Generate leak node.
- static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
- ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
+ // Cleanup the FreeReturnValue Map.
+ FreeReturnValueTy FR = state->get<FreeReturnValue>();
+ for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) {
+ if (SymReaper.isDead(I->first) ||
+ SymReaper.isDead(I->second)) {
+ state = state->remove<FreeReturnValue>(I->first);
+ }
+ }
- if (generateReport) {
+ // Generate leak node.
+ ExplodedNode *N = C.getPredecessor();
+ if (!Errors.empty()) {
+ static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
+ N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
for (llvm::SmallVector<SymbolRef, 2>::iterator
- I = Errors.begin(), E = Errors.end(); I != E; ++I) {
+ I = Errors.begin(), E = Errors.end(); I != E; ++I) {
reportLeak(*I, N, C);
}
}
+
C.addTransition(state->set<RegionState>(RS), N);
}
@@ -1182,7 +1263,7 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
R->addRange(S->getSourceRange());
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym));
- C.EmitReport(R);
+ C.emitReport(R);
return true;
}
}
@@ -1249,28 +1330,36 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
bool Assumption) const {
RegionStateTy RS = state->get<RegionState>();
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
- // If the symbol is assumed to NULL or another constant, this will
- // return an APSInt*.
- if (state->getSymVal(I.getKey()))
+ // If the symbol is assumed to be NULL, remove it from consideration.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (AllocFailed.isConstrainedTrue())
state = state->remove<RegionState>(I.getKey());
}
// Realloc returns 0 when reallocation fails, which means that we should
// restore the state of the pointer being reallocated.
- ReallocMap RP = state->get<ReallocPairs>();
- for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
- // If the symbol is assumed to NULL or another constant, this will
- // return an APSInt*.
- if (state->getSymVal(I.getKey())) {
- SymbolRef ReallocSym = I.getData().ReallocatedSym;
- const RefState *RS = state->get<RegionState>(ReallocSym);
- if (RS) {
- if (RS->isReleased() && ! I.getData().IsFreeOnFailure)
+ ReallocPairsTy RP = state->get<ReallocPairs>();
+ for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ // If the symbol is assumed to be NULL, remove it from consideration.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (!AllocFailed.isConstrainedTrue())
+ continue;
+
+ SymbolRef ReallocSym = I.getData().ReallocatedSym;
+ if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
+ if (RS->isReleased()) {
+ if (I.getData().Kind == RPToBeFreedAfterFailure)
state = state->set<RegionState>(ReallocSym,
- RefState::getAllocated(RS->getStmt()));
+ RefState::getAllocated(RS->getStmt()));
+ else if (I.getData().Kind == RPDoNotTrackAfterFailure)
+ state = state->remove<RegionState>(ReallocSym);
+ else
+ assert(I.getData().Kind == RPIsFreeOnFailure);
}
- state = state->remove<ReallocPairs>(I.getKey());
}
+ state = state->remove<ReallocPairs>(I.getKey());
}
return state;
@@ -1463,10 +1552,10 @@ MallocChecker::checkRegionChanges(ProgramStateRef State,
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
ProgramStateRef prevState) {
- ReallocMap currMap = currState->get<ReallocPairs>();
- ReallocMap prevMap = prevState->get<ReallocPairs>();
+ ReallocPairsTy currMap = currState->get<ReallocPairs>();
+ ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
- for (ReallocMap::iterator I = prevMap.begin(), E = prevMap.end();
+ for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end();
I != E; ++I) {
SymbolRef sym = I.getKey();
if (!currMap.lookup(sym))
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index 6292a4725128..fb40f222b846 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -146,9 +146,9 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
if (const PointerType *ptrA = A->getAs<PointerType>())
if (const PointerType *ptrB = B->getAs<PointerType>()) {
- A = ptrA->getPointeeType();
- B = ptrB->getPointeeType();
- continue;
+ A = ptrA->getPointeeType();
+ B = ptrB->getPointeeType();
+ continue;
}
break;
@@ -157,6 +157,18 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
return false;
}
+static bool compatibleWithArrayType(ASTContext &C, QualType PT, QualType T) {
+ // Ex: 'int a[10][2]' is compatible with 'int', 'int[2]', 'int[10][2]'.
+ while (const ArrayType *AT = T->getAsArrayTypeUnsafe()) {
+ QualType ElemType = AT->getElementType();
+ if (typesCompatible(C, PT, AT->getElementType()))
+ return true;
+ T = ElemType;
+ }
+
+ return false;
+}
+
class MallocSizeofChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
@@ -184,38 +196,49 @@ public:
continue;
QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument();
- if (!typesCompatible(BR.getContext(), PointeeType, SizeofType)) {
- const TypeSourceInfo *TSI = 0;
- if (i->CastedExprParent.is<const VarDecl *>()) {
- TSI =
+
+ if (typesCompatible(BR.getContext(), PointeeType, SizeofType))
+ continue;
+
+ // If the argument to sizeof is an array, the result could be a
+ // pointer to any array element.
+ if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType))
+ continue;
+
+ const TypeSourceInfo *TSI = 0;
+ if (i->CastedExprParent.is<const VarDecl *>()) {
+ TSI =
i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo();
- } else {
- TSI = i->ExplicitCastType;
- }
-
- SmallString<64> buf;
- llvm::raw_svector_ostream OS(buf);
-
- OS << "Result of '"
- << i->AllocCall->getDirectCallee()->getIdentifier()->getName()
- << "' is converted to a pointer of type '"
- << PointeeType.getAsString() << "', which is incompatible with "
- << "sizeof operand type '" << SizeofType.getAsString() << "'";
- llvm::SmallVector<SourceRange, 4> Ranges;
- Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
- Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
- if (TSI)
- Ranges.push_back(TSI->getTypeLoc().getSourceRange());
-
- PathDiagnosticLocation L =
+ } else {
+ TSI = i->ExplicitCastType;
+ }
+
+ SmallString<64> buf;
+ llvm::raw_svector_ostream OS(buf);
+
+ OS << "Result of ";
+ const FunctionDecl *Callee = i->AllocCall->getDirectCallee();
+ if (Callee && Callee->getIdentifier())
+ OS << '\'' << Callee->getIdentifier()->getName() << '\'';
+ else
+ OS << "call";
+ OS << " is converted to a pointer of type '"
+ << PointeeType.getAsString() << "', which is incompatible with "
+ << "sizeof operand type '" << SizeofType.getAsString() << "'";
+ llvm::SmallVector<SourceRange, 4> Ranges;
+ Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
+ Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
+ if (TSI)
+ Ranges.push_back(TSI->getTypeLoc().getSourceRange());
+
+ PathDiagnosticLocation L =
PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(),
- BR.getSourceManager(), ADC);
+ BR.getSourceManager(), ADC);
- BR.EmitBasicReport(D, "Allocator sizeof operand mismatch",
- categories::UnixAPI,
- OS.str(),
- L, Ranges.data(), Ranges.size());
- }
+ BR.EmitBasicReport(D, "Allocator sizeof operand mismatch",
+ categories::UnixAPI,
+ OS.str(),
+ L, Ranges.data(), Ranges.size());
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index aad3b0f5f277..3331bc8a9a8d 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -71,7 +71,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BugReport *Report = new BugReport(*BT, "Use -drain instead of -release when "
"using NSAutoreleasePool and garbage collection", N);
Report->addRange(msg.getSourceRange());
- C.EmitReport(Report);
+ C.emitReport(Report);
}
void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index f826573c9ecb..7a66ec3a934f 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -163,23 +163,9 @@ public:
};
}
-namespace { struct NSErrorOut {}; }
-namespace { struct CFErrorOut {}; }
-
typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag;
-
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<NSErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
- template <>
- struct ProgramStateTrait<CFErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
-}
-}
+REGISTER_TRAIT_WITH_PROGRAMSTATE(NSErrorOut, ErrorOutFlag)
+REGISTER_TRAIT_WITH_PROGRAMSTATE(CFErrorOut, ErrorOutFlag)
template <typename T>
static bool hasFlag(SVal val, ProgramStateRef state) {
@@ -285,7 +271,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
bug = new CFErrorDerefBug();
BugReport *report = new BugReport(*bug, os.str(),
event.SinkNode);
- BR.EmitReport(report);
+ BR.emitReport(report);
}
static bool IsNSError(QualType T, IdentifierInfo *II) {
diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
deleted file mode 100644
index 7b724d2be9b7..000000000000
--- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This checker evaluates OSAtomic functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.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;
-
-namespace {
-
-class OSAtomicChecker : public Checker<eval::InlineCall> {
-public:
- bool inlineCall(const CallExpr *CE, ExprEngine &Eng,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) const;
-
-private:
- bool evalOSAtomicCompareAndSwap(const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) const;
-};
-}
-
-static StringRef getCalleeName(ProgramStateRef State,
- const CallExpr *CE,
- const LocationContext *LCtx) {
- const Expr *Callee = CE->getCallee();
- SVal L = State->getSVal(Callee, LCtx);
- const FunctionDecl *funDecl = L.getAsFunctionDecl();
- if (!funDecl)
- return StringRef();
- IdentifierInfo *funI = funDecl->getIdentifier();
- if (!funI)
- return StringRef();
- return funI->getName();
-}
-
-bool OSAtomicChecker::inlineCall(const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) const {
- StringRef FName = getCalleeName(Pred->getState(),
- CE, Pred->getLocationContext());
- if (FName.empty())
- return false;
-
- // Check for compare and swap.
- if (FName.startswith("OSAtomicCompareAndSwap") ||
- FName.startswith("objc_atomicCompareAndSwap"))
- return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
-
- // FIXME: Other atomics.
- return false;
-}
-
-bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) const {
- // Not enough arguments to match OSAtomicCompareAndSwap?
- if (CE->getNumArgs() != 3)
- return false;
-
- ASTContext &Ctx = Eng.getContext();
- const Expr *oldValueExpr = CE->getArg(0);
- QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
-
- const Expr *newValueExpr = CE->getArg(1);
- QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
-
- // Do the types of 'oldValue' and 'newValue' match?
- if (oldValueType != newValueType)
- return false;
-
- const Expr *theValueExpr = CE->getArg(2);
- const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
-
- // theValueType not a pointer?
- if (!theValueType)
- return false;
-
- QualType theValueTypePointee =
- Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
-
- // The pointee must match newValueType and oldValueType.
- if (theValueTypePointee != newValueType)
- return false;
-
- static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
- static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
-
- // Load 'theValue'.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr, LCtx);
- // Here we should use the value type of the region as the load type, because
- // we are simulating the semantics of the function, not the semantics of
- // passing argument. So the type of theValue expr is not we are loading.
- // But usually the type of the varregion is not the type we want either,
- // we still need to do a CastRetrievedVal in store manager. So actually this
- // LoadTy specifying can be omitted. But we put it here to emphasize the
- // semantics.
- QualType LoadTy;
- if (const TypedValueRegion *TR =
- dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
- LoadTy = TR->getValueType();
- }
- Eng.evalLoad(Tmp, CE, theValueExpr, Pred,
- state, location, &OSAtomicLoadTag, LoadTy);
-
- if (Tmp.empty()) {
- // If no nodes were generated, other checkers must have generated sinks.
- // We return an empty Dst.
- return true;
- }
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
- I != E; ++I) {
-
- ExplodedNode *N = *I;
- ProgramStateRef stateLoad = N->getState();
-
- // Use direct bindings from the environment since we are forcing a load
- // from a location that the Environment would typically not be used
- // to bind a value.
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true);
-
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx);
-
- // FIXME: Issue an error.
- if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
- return false;
- }
-
- DefinedOrUnknownSVal theValueVal =
- cast<DefinedOrUnknownSVal>(theValueVal_untested);
- DefinedOrUnknownSVal oldValueVal =
- cast<DefinedOrUnknownSVal>(oldValueVal_untested);
-
- SValBuilder &svalBuilder = Eng.getSValBuilder();
-
- // Perform the comparison.
- DefinedOrUnknownSVal Cmp =
- svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
-
- ProgramStateRef stateEqual = stateLoad->assume(Cmp, true);
-
- // Were they equal?
- if (stateEqual) {
- // Perform the store.
- ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr, LCtx);
-
- // Handle implicit value casts.
- if (const TypedValueRegion *R =
- dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
- val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
- }
-
- Eng.evalStore(TmpStore, CE, theValueExpr, N,
- stateEqual, location, val, &OSAtomicStoreTag);
-
- if (TmpStore.empty()) {
- // If no nodes were generated, other checkers must have generated sinks.
- // We return an empty Dst.
- return true;
- }
-
- StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext());
- // Now bind the result of the comparison.
- for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
- E2 = TmpStore.end(); I2 != E2; ++I2) {
- ExplodedNode *predNew = *I2;
- ProgramStateRef stateNew = predNew->getState();
- // Check for 'void' return type if we have a bogus function prototype.
- SVal Res = UnknownVal();
- QualType T = CE->getType();
- if (!T->isVoidType())
- Res = Eng.getSValBuilder().makeTruthVal(true, T);
- B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res),
- false, this);
- }
- }
-
- // Were they not equal?
- if (ProgramStateRef stateNotEqual = stateLoad->assume(Cmp, false)) {
- // Check for 'void' return type if we have a bogus function prototype.
- SVal Res = UnknownVal();
- QualType T = CE->getType();
- if (!T->isVoidType())
- Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
- StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());
- B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res),
- false, this);
- }
- }
-
- return true;
-}
-
-void ento::registerOSAtomicChecker(CheckerManager &mgr) {
- mgr.registerChecker<OSAtomicChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 4cc92ce9e958..9d84f52f934e 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -18,7 +18,6 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -50,8 +49,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
"for @synchronized"));
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, Ex, *report);
+ C.emitReport(report);
}
return;
}
@@ -73,9 +72,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
"(no synchronization will occur)"));
BugReport *report =
new BugReport(*BT_null, BT_null->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report);
+ bugreporter::trackNullOrUndefValue(N, Ex, *report);
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index f2929c03cc0b..63a84805e73e 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -31,8 +31,6 @@ class WalkAST : public StmtVisitor<WalkAST> {
ASTContext &ASTC;
uint64_t PtrWidth;
- static const unsigned InvalidArgIndex = UINT_MAX;
-
/// Check if the type has pointer size (very conservative).
inline bool isPointerSize(const Type *T) {
if (!T)
@@ -102,16 +100,18 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
return;
const Expr *Arg = 0;
- unsigned ArgNum = InvalidArgIndex;
+ unsigned ArgNum;
if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
+ if (CE->getNumArgs() != 4)
+ return;
ArgNum = 1;
Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
if (hasPointerToPointerSizedType(Arg))
return;
- }
-
- if (Arg == 0 && Name.equals("CFDictionaryCreate")) {
+ } else if (Name.equals("CFDictionaryCreate")) {
+ if (CE->getNumArgs() != 6)
+ return;
// Check first argument.
ArgNum = 1;
Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
@@ -125,17 +125,18 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
}
}
- if (ArgNum != InvalidArgIndex) {
+ if (Arg) {
assert(ArgNum == 1 || ArgNum == 2);
- SmallString<256> BufName;
+ SmallString<64> BufName;
llvm::raw_svector_ostream OsName(BufName);
- assert(ArgNum == 1 || ArgNum == 2);
OsName << " Invalid use of '" << Name << "'" ;
SmallString<256> Buf;
llvm::raw_svector_ostream Os(Buf);
- Os << " The "<< ((ArgNum == 1) ? "first" : "second") << " argument to '"
+ // Use "second" and "third" since users will expect 1-based indexing
+ // for parameter names when mentioned in prose.
+ Os << " The "<< ((ArgNum == 1) ? "second" : "third") << " argument to '"
<< Name << "' must be a C array of pointer-sized values, not '"
<< Arg->getType().getAsString() << "'";
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index 2ab49ed12a14..999c994cb1c6 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -55,16 +55,8 @@ public:
};
} // end anonymous namespace
-// ProgramState trait - a map from array symbol to it's state.
-typedef llvm::ImmutableMap<SymbolRef, DefinedSVal> ArraySizeM;
-
-namespace { struct ArraySizeMap {}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<ArraySizeMap>
- : public ProgramStatePartialTrait<ArraySizeM > {
- static void *GDMIndex() { return ObjCContainersChecker::getTag(); }
-};
-}}
+// ProgramState trait - a map from array symbol to its state.
+REGISTER_MAP_WITH_PROGRAMSTATE(ArraySizeMap, SymbolRef, DefinedSVal)
void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size,
CheckerContext &C) const {
@@ -146,7 +138,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
initBugType();
BugReport *R = new BugReport(*BT, "Index is out of bounds", N);
R->addRange(IdxExpr->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
return;
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
new file mode 100644
index 000000000000..e906e8aa3016
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -0,0 +1,203 @@
+//==- ObjCMissingSuperCallChecker.cpp - Check missing super-calls in ObjC --==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a ObjCMissingSuperCallChecker, a checker that
+// analyzes a UIViewController implementation to determine if it
+// correctly calls super in the methods where this is mandatory.
+//
+//===----------------------------------------------------------------------===//
+
+#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/RecursiveASTVisitor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallSet.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;
+}
+
+//===----------------------------------------------------------------------===//
+// FindSuperCallVisitor - Identify specific calls to the superclass.
+//===----------------------------------------------------------------------===//
+
+class FindSuperCallVisitor : public RecursiveASTVisitor<FindSuperCallVisitor> {
+public:
+ explicit FindSuperCallVisitor(Selector S) : DoesCallSuper(false), Sel(S) {}
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (E->getSelector() == Sel)
+ if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance)
+ DoesCallSuper = true;
+
+ // Recurse if we didn't find the super call yet.
+ return !DoesCallSuper;
+ }
+
+ bool DoesCallSuper;
+
+private:
+ Selector Sel;
+};
+
+//===----------------------------------------------------------------------===//
+// ObjCSuperCallChecker
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ObjCSuperCallChecker : public Checker<
+ check::ASTDecl<ObjCImplementationDecl> > {
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr,
+ BugReporter &BR) const;
+};
+}
+
+void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
+ AnalysisManager &Mgr,
+ 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);
+
+ // 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];
+
+ // 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(),
+ E = D->instmeth_end();
+ I != E; ++I) {
+ Selector S = (*I)->getSelector();
+ // Find out whether this is a selector that we want to check.
+ if (!Selectors.count(S))
+ continue;
+
+ ObjCMethodDecl *MD = *I;
+
+ // Check if the method calls its superclass implementation.
+ if (MD->getBody())
+ {
+ FindSuperCallVisitor Visitor(S);
+ Visitor.TraverseDecl(MD);
+
+ // It doesn't call super, emit a diagnostic.
+ if (!Visitor.DoesCallSuper) {
+ PathDiagnosticLocation DLoc =
+ PathDiagnosticLocation::createEnd(MD->getBody(),
+ BR.getSourceManager(),
+ Mgr.getAnalysisDeclContext(D));
+
+ const char *Name = "Missing call to superclass";
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream os(Buf);
+
+ os << "The '" << S.getAsString()
+ << "' instance method in UIViewController subclass '" << *D
+ << "' is missing a [super " << S.getAsString() << "] call";
+
+ BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
+ os.str(), DLoc);
+ }
+ }
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Check registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<ObjCSuperCallChecker>();
+}
+
+
+/*
+ ToDo list for expanding this check in the future, the list is not exhaustive.
+ There are also cases where calling super is suggested but not "mandatory".
+ In addition to be able to check the classes and methods below, architectural
+ 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)
+
+UIViewController subclasses
+- loadView (should *never* call super)
+- transitionFromViewController:toViewController:
+ duration:options:animations:completion: (is multi-arg)
+
+UICollectionViewController subclasses
+- loadView (take care because UIViewController subclasses should NOT call super
+ in loadView, but UICollectionViewController subclasses should)
+
+NSObject subclasses
+- doesNotRecognizeSelector (it only has to call super if it doesn't throw)
+
+UIPopoverBackgroundView subclasses (some of those are class methods)
+- arrowDirection (should *never* call super)
+- arrowOffset (should *never* call super)
+- arrowBase (should *never* call super)
+- arrowHeight (should *never* call super)
+- contentViewInsets (should *never* call super)
+
+UITextSelectionRect subclasses (some of those are properties)
+- rect (should *never* call super)
+- range (should *never* call super)
+- writingDirection (should *never* call super)
+- isVertical (should *never* call super)
+- containsStart (should *never* call super)
+- containsEnd (should *never* call super)
+*/
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index be45da1be066..98d2a85ace36 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -72,6 +72,8 @@ public:
void checkPreCall(const CallEvent &CE, CheckerContext &C) const;
void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
+ void printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const;
};
} // end anonymous namespace
@@ -97,31 +99,14 @@ enum SelfFlagEnum {
};
}
-typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
-namespace { struct CalledInit {}; }
-namespace { struct PreCallSelfFlags {}; }
-
-namespace clang {
-namespace ento {
- template<>
- struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
- template <>
- struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
-
- /// \brief A call receiving a reference to 'self' invalidates the object that
- /// 'self' contains. This keeps the "self flags" assigned to the 'self'
- /// object before the call so we can assign them to the new object that 'self'
- /// points to after the call.
- template <>
- struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(SelfFlag, SymbolRef, unsigned)
+REGISTER_TRAIT_WITH_PROGRAMSTATE(CalledInit, bool)
+
+/// \brief A call receiving a reference to 'self' invalidates the object that
+/// 'self' contains. This keeps the "self flags" assigned to the 'self'
+/// object before the call so we can assign them to the new object that 'self'
+/// points to after the call.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(PreCallSelfFlags, unsigned)
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) {
if (SymbolRef sym = val.getAsSymbol())
@@ -138,7 +123,8 @@ static void addSelfFlag(ProgramStateRef state, SVal val,
SelfFlagEnum flag, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
if (SymbolRef sym = val.getAsSymbol())
- C.addTransition(state->set<SelfFlag>(sym, getSelfFlags(val, C) | flag));
+ state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag);
+ C.addTransition(state);
}
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
@@ -176,7 +162,7 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
BugReport *report =
new BugReport(*new InitSelfBug(), errorStr, N);
- C.EmitReport(report);
+ C.emitReport(report);
}
void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
@@ -305,13 +291,12 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
// returns 'self'. So assign the flags, which were set on 'self' to the
// return value.
// EX: self = performMoreInitialization(self)
- const Expr *CallExpr = CE.getOriginExpr();
- if (CallExpr)
- addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()),
- prevFlags, C);
+ addSelfFlag(state, CE.getReturnValue(), prevFlags, C);
return;
}
}
+
+ C.addTransition(state);
}
void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
@@ -346,6 +331,53 @@ void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
}
}
+void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
+ SelfFlagTy FlagMap = State->get<SelfFlag>();
+ bool DidCallInit = State->get<CalledInit>();
+ SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get<PreCallSelfFlags>();
+
+ if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
+ return;
+
+ Out << Sep << NL << "ObjCSelfInitChecker:" << NL;
+
+ if (DidCallInit)
+ Out << " An init method has been called." << NL;
+
+ if (PreCallFlags != SelfFlag_None) {
+ if (PreCallFlags & SelfFlag_Self) {
+ Out << " An argument of the current call came from the 'self' variable."
+ << NL;
+ }
+ if (PreCallFlags & SelfFlag_InitRes) {
+ Out << " An argument of the current call came from an init method."
+ << NL;
+ }
+ }
+
+ Out << NL;
+ for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end();
+ I != E; ++I) {
+ Out << I->first << " : ";
+
+ if (I->second == SelfFlag_None)
+ Out << "none";
+
+ if (I->second & SelfFlag_Self)
+ Out << "self variable";
+
+ if (I->second & SelfFlag_InitRes) {
+ if (I->second != SelfFlag_InitRes)
+ Out << " | ";
+ Out << "result of init method";
+ }
+
+ Out << NL;
+ }
+}
+
+
// FIXME: A callback should disable checkers at the start of functions.
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
if (!ND)
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index fe4845bd8894..b5d9959b8531 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -59,7 +59,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
"dangerous."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index fa5c6a30a683..47da87f0bcc6 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -67,7 +67,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
"the same memory chunk may cause incorrect result."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 2d018ef9264d..d9b638469525 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -43,15 +43,7 @@ public:
} // end anonymous namespace
// GDM Entry for tracking lock state.
-namespace { class LockSet {}; }
-namespace clang {
-namespace ento {
-template <> struct ProgramStateTrait<LockSet> :
- public ProgramStatePartialTrait<llvm::ImmutableList<const MemRegion*> > {
- static void *GDMIndex() { static int x = 0; return &x; }
-};
-} // end of ento (ProgramState) namespace
-} // end clang namespace
+REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
@@ -118,7 +110,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
"This lock has already "
"been acquired", N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
@@ -163,7 +155,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
- llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>();
+ LockSetTy LS = state->get<LockSet>();
// FIXME: Better analysis requires IPA for wrappers.
// FIXME: check for double unlocks
@@ -183,7 +175,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
"Possible lock order "
"reversal", N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 3c00d9915b4a..304051c1394c 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -40,24 +40,6 @@ using namespace clang;
using namespace ento;
using llvm::StrInStrNoCase;
-namespace {
-/// Wrapper around different kinds of node builder, so that helper functions
-/// can have a common interface.
-class GenericNodeBuilderRefCount {
- CheckerContext *C;
- const ProgramPointTag *tag;
-public:
- GenericNodeBuilderRefCount(CheckerContext &c,
- const ProgramPointTag *t = 0)
- : C(&c), tag(t){}
-
- ExplodedNode *MakeNode(ProgramStateRef state, ExplodedNode *Pred,
- bool MarkAsSink = false) {
- return C->addTransition(state, Pred, tag, MarkAsSink);
- }
-};
-} // end anonymous namespace
-
//===----------------------------------------------------------------------===//
// Primitives used for constructing summaries for function/method calls.
//===----------------------------------------------------------------------===//
@@ -66,9 +48,23 @@ public:
/// particular argument.
enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg,
DecRefBridgedTransfered,
- DecRefAndStopTracking, DecRefMsgAndStopTracking,
IncRefMsg, IncRef, MakeCollectable, MayEscape,
- NewAutoreleasePool, StopTracking };
+ NewAutoreleasePool,
+
+ // Stop tracking the argument - the effect of the call is
+ // unknown.
+ StopTracking,
+
+ // In some cases, we obtain a better summary for this checker
+ // by looking at the call site than by inlining the function.
+ // Signifies that we should stop tracking the symbol even if
+ // the function is inlined.
+ StopTrackingHard,
+
+ // The function decrements the reference count and the checker
+ // should stop tracking the argument.
+ DecRefAndStopTrackingHard, DecRefMsgAndStopTrackingHard
+ };
namespace llvm {
template <> struct FoldingSetTrait<ArgEffect> {
@@ -90,7 +86,13 @@ class RetEffect {
public:
enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol,
NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
- OwnedWhenTrackedReceiver };
+ OwnedWhenTrackedReceiver,
+ // Treat this function as returning a non-tracked symbol even if
+ // the function has been inlined. This is used where the call
+ // site summary is more presise than the summary indirectly produced
+ // by inlining the function
+ NoRetHard
+ };
enum ObjKind { CF, ObjC, AnyObj };
@@ -133,6 +135,9 @@ public:
static RetEffect MakeNoRet() {
return RetEffect(NoRet);
}
+ static RetEffect MakeNoRetHard() {
+ return RetEffect(NoRetHard);
+ }
void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned) K);
@@ -337,20 +342,7 @@ void RefVal::print(raw_ostream &Out) const {
// RefBindings - State used to track object reference counts.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<RefBindings>
- : public ProgramStatePartialTrait<RefBindings> {
- static void *GDMIndex() {
- static int RefBIndex = 0;
- return &RefBIndex;
- }
-};
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
static inline const RefVal *getRefBinding(ProgramStateRef State,
SymbolRef Sym) {
@@ -893,7 +885,7 @@ static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) {
return FName.find("MakeCollectable") != StringRef::npos;
}
-static ArgEffect getStopTrackingEquivalent(ArgEffect E) {
+static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
switch (E) {
case DoNothing:
case Autorelease:
@@ -904,13 +896,14 @@ static ArgEffect getStopTrackingEquivalent(ArgEffect E) {
case MayEscape:
case NewAutoreleasePool:
case StopTracking:
- return StopTracking;
+ case StopTrackingHard:
+ return StopTrackingHard;
case DecRef:
- case DecRefAndStopTracking:
- return DecRefAndStopTracking;
+ case DecRefAndStopTrackingHard:
+ return DecRefAndStopTrackingHard;
case DecRefMsg:
- case DecRefMsgAndStopTracking:
- return DecRefMsgAndStopTracking;
+ case DecRefMsgAndStopTrackingHard:
+ return DecRefMsgAndStopTrackingHard;
case Dealloc:
return Dealloc;
}
@@ -921,33 +914,65 @@ static ArgEffect getStopTrackingEquivalent(ArgEffect E) {
void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
const CallEvent &Call) {
if (Call.hasNonZeroCallbackArg()) {
- ArgEffect RecEffect = getStopTrackingEquivalent(S->getReceiverEffect());
- ArgEffect DefEffect = getStopTrackingEquivalent(S->getDefaultArgEffect());
+ ArgEffect RecEffect =
+ getStopTrackingHardEquivalent(S->getReceiverEffect());
+ ArgEffect DefEffect =
+ getStopTrackingHardEquivalent(S->getDefaultArgEffect());
ArgEffects CustomArgEffects = S->getArgEffects();
for (ArgEffects::iterator I = CustomArgEffects.begin(),
E = CustomArgEffects.end();
I != E; ++I) {
- ArgEffect Translated = getStopTrackingEquivalent(I->second);
+ ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
if (Translated != DefEffect)
ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
}
- RetEffect RE = RetEffect::MakeNoRet();
+ RetEffect RE = RetEffect::MakeNoRetHard();
// Special cases where the callback argument CANNOT free the return value.
// This can generally only happen if we know that the callback will only be
// called when the return value is already being deallocated.
if (const FunctionCall *FC = dyn_cast<FunctionCall>(&Call)) {
- IdentifierInfo *Name = FC->getDecl()->getIdentifier();
-
- // This callback frees the associated buffer.
- if (Name->isStr("CGBitmapContextCreateWithData"))
- RE = S->getRetEffect();
+ if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
+ // When the CGBitmapContext is deallocated, the callback here will free
+ // the associated data buffer.
+ if (Name->isStr("CGBitmapContextCreateWithData"))
+ RE = S->getRetEffect();
+ }
}
S = getPersistentSummary(RE, RecEffect, DefEffect);
}
+
+ // Special case '[super init];' and '[self init];'
+ //
+ // Even though calling '[super init]' without assigning the result to self
+ // and checking if the parent returns 'nil' is a bad pattern, it is common.
+ // Additionally, our Self Init checker already warns about it. To avoid
+ // overwhelming the user with messages from both checkers, we model the case
+ // of '[super init]' in cases when it is not consumed by another expression
+ // as if the call preserves the value of 'self'; essentially, assuming it can
+ // never fail and return 'nil'.
+ // Note, we don't want to just stop tracking the value since we want the
+ // RetainCount checker to report leaks and use-after-free if SelfInit checker
+ // is turned off.
+ if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) {
+ if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) {
+
+ // Check if the message is not consumed, we know it will not be used in
+ // an assignment, ex: "self = [super init]".
+ const Expr *ME = MC->getOriginExpr();
+ const LocationContext *LCtx = MC->getLocationContext();
+ ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap();
+ if (!PM.isConsumedExpr(ME)) {
+ RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
+ ModifiableSummaryTemplate->setReceiverEffect(DoNothing);
+ ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
+ }
+ }
+
+ }
}
const RetainSummary *
@@ -1036,6 +1061,8 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
// The headers on OS X 10.8 use cf_consumed/ns_returns_retained,
// but we can fully model NSMakeCollectable ourselves.
AllowAnnotations = false;
+ } else if (FName == "CFPlugInInstanceCreate") {
+ S = getPersistentSummary(RetEffect::MakeNoRet());
} else if (FName == "IOBSDNameMatching" ||
FName == "IOServiceMatching" ||
FName == "IOServiceNameMatching" ||
@@ -1108,6 +1135,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
break;
if (RetTy->isPointerType()) {
+ if (FD->getAttr<CFAuditedTransferAttr>()) {
+ S = getCFCreateGetRuleSummary(FD);
+ break;
+ }
+
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
@@ -1347,22 +1379,6 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const RetainSummary *
RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy) {
-
- if (MD) {
- // Scan the method decl for 'void*' arguments. These should be treated
- // as 'StopTracking' because they are often used with delegates.
- // Delegates are a frequent form of false positives with the retain
- // count checker.
- unsigned i = 0;
- for (ObjCMethodDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I, ++i)
- if (const ParmVarDecl *PD = *I) {
- QualType Ty = Ctx.getCanonicalType(PD->getType());
- if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy)
- ScratchArgs = AF.add(ScratchArgs, i, StopTracking);
- }
- }
-
// Any special effects?
ArgEffect ReceiverEff = DoNothing;
RetEffect ResultEff = RetEffect::MakeNoRet();
@@ -1441,9 +1457,9 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
StringRef Slot = S.getNameForSlot(i);
if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) {
if (ResultEff == ObjCInitRetE)
- ResultEff = RetEffect::MakeNoRet();
+ ResultEff = RetEffect::MakeNoRetHard();
else
- ReceiverEff = StopTracking;
+ ReceiverEff = StopTrackingHard;
}
}
}
@@ -2174,6 +2190,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
// If allocation happened in a function different from the leak node context,
// do not report the binding.
+ assert(N && "Could not find allocation node");
if (N->getLocationContext() != LeakContext) {
FirstBinding = 0;
}
@@ -2229,27 +2246,36 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
// Get the retain count.
const RefVal* RV = getRefBinding(EndN->getState(), Sym);
+ assert(RV);
if (RV->getKind() == RefVal::ErrorLeakReturned) {
// FIXME: Per comments in rdar://6320065, "create" only applies to CF
// objects. Only "copy", "alloc", "retain" and "new" transfer ownership
// to the caller for NS objects.
const Decl *D = &EndN->getCodeDecl();
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- os << " is returned from a method whose name ('"
- << MD->getSelector().getAsString()
- << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
- " This violates the naming convention rules"
- " given in the Memory Management Guide for Cocoa";
- }
+
+ os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
+ : " is returned from a function ");
+
+ if (D->getAttr<CFReturnsNotRetainedAttr>())
+ os << "that is annotated as CF_RETURNS_NOT_RETAINED";
+ else if (D->getAttr<NSReturnsNotRetainedAttr>())
+ os << "that is annotated as NS_RETURNS_NOT_RETAINED";
else {
- const FunctionDecl *FD = cast<FunctionDecl>(D);
- os << " is returned from a function whose name ('"
- << *FD
- << "') does not contain 'Copy' or 'Create'. This violates the naming"
- " convention rules given in the Memory Management Guide for Core"
- " Foundation";
- }
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ os << "whose name ('" << MD->getSelector().getAsString()
+ << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
+ " This violates the naming convention rules"
+ " given in the Memory Management Guide for Cocoa";
+ }
+ else {
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
+ os << "whose name ('" << *FD
+ << "') does not contain 'Copy' or 'Create'. This violates the naming"
+ " convention rules given in the Memory Management Guide for Core"
+ " Foundation";
+ }
+ }
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
@@ -2474,6 +2500,10 @@ public:
void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
CheckerContext &C) const;
+ void processSummaryOfInlined(const RetainSummary &Summ,
+ const CallEvent &Call,
+ CheckerContext &C) const;
+
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
@@ -2499,8 +2529,8 @@ public:
void checkEndPath(CheckerContext &C) const;
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
- RefVal V, ArgEffect E, RefVal::Kind &hasErr,
- CheckerContext &C) const;
+ RefVal V, ArgEffect E, RefVal::Kind &hasErr,
+ CheckerContext &C) const;
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
RefVal::Kind ErrorKind, SymbolRef Sym,
@@ -2515,13 +2545,12 @@ public:
SmallVectorImpl<SymbolRef> &Leaked) const;
std::pair<ExplodedNode *, ProgramStateRef >
- handleAutoreleaseCounts(ProgramStateRef state,
- GenericNodeBuilderRefCount Bd, ExplodedNode *Pred,
- CheckerContext &Ctx, SymbolRef Sym, RefVal V) const;
+ handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
+ const ProgramPointTag *Tag, CheckerContext &Ctx,
+ SymbolRef Sym, RefVal V) const;
ExplodedNode *processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
- GenericNodeBuilderRefCount &Builder,
CheckerContext &Ctx,
ExplodedNode *Pred = 0) const;
};
@@ -2685,11 +2714,13 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
void RetainCountChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- if (C.wasInlined)
- return;
-
RetainSummaryManager &Summaries = getSummaryManager(C);
const RetainSummary *Summ = Summaries.getSummary(Call, C.getState());
+
+ if (C.wasInlined) {
+ processSummaryOfInlined(*Summ, Call, C);
+ return;
+ }
checkSummary(*Summ, Call, C);
}
@@ -2721,6 +2752,45 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
return RetTy;
}
+// We don't always get the exact modeling of the function with regards to the
+// retain count checker even when the function is inlined. For example, we need
+// to stop tracking the symbols which were marked with StopTrackingHard.
+void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
+ const CallEvent &CallOrMsg,
+ CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
+
+ // Evaluate the effect of the arguments.
+ for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
+ if (Summ.getArg(idx) == StopTrackingHard) {
+ SVal V = CallOrMsg.getArgSVal(idx);
+ if (SymbolRef Sym = V.getAsLocSymbol()) {
+ state = removeRefBinding(state, Sym);
+ }
+ }
+ }
+
+ // Evaluate the effect on the message receiver.
+ const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg);
+ if (MsgInvocation) {
+ if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
+ if (Summ.getReceiverEffect() == StopTrackingHard) {
+ state = removeRefBinding(state, Sym);
+ }
+ }
+ }
+
+ // Consult the summary for the return value.
+ RetEffect RE = Summ.getRetEffect();
+ if (RE.getKind() == RetEffect::NoRetHard) {
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
+ if (Sym)
+ state = removeRefBinding(state, Sym);
+ }
+
+ C.addTransition(state);
+}
+
void RetainCountChecker::checkSummary(const RetainSummary &Summ,
const CallEvent &CallOrMsg,
CheckerContext &C) const {
@@ -2755,7 +2825,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
if (const RefVal *T = getRefBinding(state, Sym)) {
ReceiverIsTracked = true;
state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(),
- hasErr, C);
+ hasErr, C);
if (hasErr) {
ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
ErrorSym = Sym;
@@ -2786,13 +2856,13 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
llvm_unreachable("Unhandled RetEffect.");
case RetEffect::NoRet:
+ case RetEffect::NoRetHard:
// No work necessary.
break;
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
- SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
- C.getLocationContext()).getAsSymbol();
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (!Sym)
break;
@@ -2811,10 +2881,10 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
- SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol();
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (!Sym)
break;
-
+ assert(Ex);
// Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
QualType ResultTy = GetReturnType(Ex, C.getASTContext());
state = setRefBinding(state, Sym, RefVal::makeNotOwned(RE.getObjKind(),
@@ -2864,8 +2934,8 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case DecRefMsg:
E = IgnoreRetainMsg ? DoNothing : DecRef;
break;
- case DecRefMsgAndStopTracking:
- E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTracking;
+ case DecRefMsgAndStopTrackingHard:
+ E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTrackingHard;
break;
case MakeCollectable:
E = C.isObjCGCEnabled() ? DecRef : DoNothing;
@@ -2886,7 +2956,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case DecRefMsg:
case IncRefMsg:
case MakeCollectable:
- case DecRefMsgAndStopTracking:
+ case DecRefMsgAndStopTrackingHard:
llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted");
case Dealloc:
@@ -2935,6 +3005,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
break;
case StopTracking:
+ case StopTrackingHard:
return removeRefBinding(state, sym);
case IncRef:
@@ -2955,7 +3026,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case DecRef:
case DecRefBridgedTransfered:
- case DecRefAndStopTracking:
+ case DecRefAndStopTrackingHard:
switch (V.getKind()) {
default:
// case 'RefVal::Released' handled above.
@@ -2966,7 +3037,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
if (V.getCount() == 1)
V = V ^ (E == DecRefBridgedTransfered ?
RefVal::NotOwned : RefVal::Released);
- else if (E == DecRefAndStopTracking)
+ else if (E == DecRefAndStopTrackingHard)
return removeRefBinding(state, sym);
V = V - 1;
@@ -2974,7 +3045,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case RefVal::NotOwned:
if (V.getCount() > 0) {
- if (E == DecRefAndStopTracking)
+ if (E == DecRefAndStopTrackingHard)
return removeRefBinding(state, sym);
V = V - 1;
} else {
@@ -3035,7 +3106,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
C.isObjCGCEnabled(), SummaryLog,
N, Sym);
report->addRange(ErrorRange);
- C.EmitReport(report);
+ C.emitReport(report);
}
//===----------------------------------------------------------------------===//
@@ -3090,8 +3161,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
if (RetVal.isUnknown()) {
// If the receiver is unknown, conjure a return value.
SValBuilder &SVB = C.getSValBuilder();
- unsigned Count = C.getCurrentBlockCount();
- RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);
+ RetVal = SVB.conjureSymbolVal(0, CE, LCtx, ResultTy, C.blockCount());
}
state = state->BindExpr(CE, LCtx, RetVal, false);
@@ -3105,8 +3175,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
Binding = getRefBinding(state, Sym);
// Invalidate the argument region.
- unsigned Count = C.getCurrentBlockCount();
- state = state->invalidateRegions(ArgRegion, CE, Count, LCtx);
+ state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx);
// Restore the refcount status of the argument.
if (Binding)
@@ -3121,12 +3190,6 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Handle return statements.
//===----------------------------------------------------------------------===//
-// Return true if the current LocationContext has no caller context.
-static bool inTopFrame(CheckerContext &C) {
- const LocationContext *LC = C.getLocationContext();
- return LC->getParent() == 0;
-}
-
void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
CheckerContext &C) const {
@@ -3135,7 +3198,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// better checking even for inlined calls, and see if they match
// with their expected semantics (e.g., the method should return a retained
// object, etc.).
- if (!inTopFrame(C))
+ if (!C.inTopFrame())
return;
const Expr *RetE = S->getRetValue();
@@ -3196,8 +3259,8 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// Update the autorelease counts.
static SimpleProgramPointTag
AutoreleaseTag("RetainCountChecker : Autorelease");
- GenericNodeBuilderRefCount Bd(C, &AutoreleaseTag);
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C, Sym, X);
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag,
+ C, Sym, X);
// Did we cache out?
if (!Pred)
@@ -3267,7 +3330,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled),
LOpts, GCEnabled, SummaryLog,
N, Sym, C);
- C.EmitReport(report);
+ C.emitReport(report);
}
}
}
@@ -3288,7 +3351,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
new CFRefReport(*returnNotOwnedForOwned,
C.getASTContext().getLangOpts(),
C.isObjCGCEnabled(), SummaryLog, N, Sym);
- C.EmitReport(report);
+ C.emitReport(report);
}
}
}
@@ -3354,18 +3417,19 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
// too bad since the number of symbols we will track in practice are
// probably small and evalAssume is only called at branches and a few
// other places.
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
if (B.isEmpty())
return state;
bool changed = false;
- RefBindings::Factory &RefBFactory = state->get_context<RefBindings>();
+ RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- // Check if the symbol is null (or equal to any constant).
- // If this is the case, stop tracking the symbol.
- if (state->getSymVal(I.getKey())) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ // Check if the symbol is null stop tracking the symbol.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (AllocFailed.isConstrainedTrue()) {
changed = true;
B = RefBFactory.remove(B, I.getKey());
}
@@ -3410,8 +3474,8 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state,
std::pair<ExplodedNode *, ProgramStateRef >
RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
- GenericNodeBuilderRefCount Bd,
ExplodedNode *Pred,
+ const ProgramPointTag *Tag,
CheckerContext &Ctx,
SymbolRef Sym, RefVal V) const {
unsigned ACnt = V.getAutoreleaseCount();
@@ -3440,7 +3504,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
V.setAutoreleaseCount(0);
}
state = setRefBinding(state, Sym, V);
- ExplodedNode *N = Bd.MakeNode(state, Pred);
+ ExplodedNode *N = Ctx.addTransition(state, Pred, Tag);
if (N == 0)
state = 0;
return std::make_pair(N, state);
@@ -3451,7 +3515,8 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
V = V ^ RefVal::ErrorOverAutorelease;
state = setRefBinding(state, Sym, V);
- if (ExplodedNode *N = Bd.MakeNode(state, Pred, true)) {
+ ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
+ if (N) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << "Object over-autoreleased: object was sent -autorelease ";
@@ -3466,7 +3531,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
CFRefReport *report =
new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false,
SummaryLog, N, Sym, os.str());
- Ctx.EmitReport(report);
+ Ctx.emitReport(report);
}
return std::make_pair((ExplodedNode *)0, (ProgramStateRef )0);
@@ -3492,14 +3557,13 @@ RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
ExplodedNode *
RetainCountChecker::processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
- GenericNodeBuilderRefCount &Builder,
CheckerContext &Ctx,
ExplodedNode *Pred) const {
if (Leaked.empty())
return Pred;
// Generate an intermediate node representing the leak point.
- ExplodedNode *N = Builder.MakeNode(state, Pred);
+ ExplodedNode *N = Ctx.addTransition(state, Pred);
if (N) {
for (SmallVectorImpl<SymbolRef>::iterator
@@ -3513,7 +3577,7 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled,
SummaryLog, N, *I, Ctx);
- Ctx.EmitReport(report);
+ Ctx.emitReport(report);
}
}
@@ -3522,13 +3586,12 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
- GenericNodeBuilderRefCount Bd(Ctx);
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
ExplodedNode *Pred = Ctx.getPredecessor();
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Ctx,
- I->first, I->second);
+ 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);
if (!state)
return;
}
@@ -3543,10 +3606,10 @@ void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
B = state->get<RefBindings>();
SmallVector<SymbolRef, 10> Leaked;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I)
state = handleSymbolDeath(state, I->first, I->second, Leaked);
- processLeaks(state, Leaked, Bd, Ctx, Pred);
+ processLeaks(state, Leaked, Ctx, Pred);
}
const ProgramPointTag *
@@ -3567,7 +3630,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ExplodedNode *Pred = C.getPredecessor();
ProgramStateRef state = C.getState();
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
// Update counts from autorelease pools
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
@@ -3576,8 +3639,8 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (const RefVal *T = B.lookup(Sym)){
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
- GenericNodeBuilderRefCount Bd(C, getDeadSymbolTag(Sym));
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C,
+ const ProgramPointTag *Tag = getDeadSymbolTag(Sym);
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, Tag, C,
Sym, *T);
if (!state)
return;
@@ -3593,17 +3656,14 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
state = handleSymbolDeath(state, *I, *T, Leaked);
}
- {
- GenericNodeBuilderRefCount Bd(C, this);
- Pred = processLeaks(state, Leaked, Bd, C, Pred);
- }
+ Pred = processLeaks(state, Leaked, C, Pred);
// Did we cache out?
if (!Pred)
return;
// Now generate a new node that nukes the old bindings.
- RefBindings::Factory &F = state->get_context<RefBindings>();
+ RefBindingsTy::Factory &F = state->get_context<RefBindings>();
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I)
@@ -3616,12 +3676,12 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const {
- RefBindings B = State->get<RefBindings>();
+ RefBindingsTy B = State->get<RefBindings>();
if (!B.isEmpty())
Out << Sep << NL;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
Out << I->first << " : ";
I->second.print(Out);
Out << NL;
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 6e565932d556..f3560aad8de2 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -82,7 +82,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
new BugReport(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index ca2a55d1e7bb..37ec1aa7bea0 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -16,6 +16,7 @@
#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"
@@ -41,6 +42,19 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
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();
+ // }
+ const StackFrameContext *SFC = C.getStackFrame();
+ QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl());
+ if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void))
+ return;
+
ExplodedNode *N = C.generateSink();
if (!N)
@@ -53,11 +67,10 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
BugReport *report =
new BugReport(*BT, BT->getDescription(), N);
- report->disablePathPruning();
report->addRange(RetE->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, RetE, report);
+ bugreporter::trackNullOrUndefValue(N, RetE, *report);
- C.EmitReport(report);
+ C.emitReport(report);
}
void ento::registerReturnUndefChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
new file mode 100644
index 000000000000..ee055adf6e4d
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -0,0 +1,348 @@
+//===-- SimpleStreamChecker.cpp -----------------------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for proper use of fopen/fclose APIs.
+// - If a file has been closed with fclose, it should not be accessed again.
+// Accessing a closed file results in undefined behavior.
+// - If a file was opened with fopen, it must be closed with fclose before
+// the execution ends. Failing to do so results in a resource leak.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+typedef llvm::SmallVector<SymbolRef, 2> SymbolVector;
+
+struct StreamState {
+private:
+ enum Kind { Opened, Closed } K;
+ StreamState(Kind InK) : K(InK) { }
+
+public:
+ bool isOpened() const { return K == Opened; }
+ bool isClosed() const { return K == Closed; }
+
+ static StreamState getOpened() { return StreamState(Opened); }
+ static StreamState getClosed() { return StreamState(Closed); }
+
+ bool operator==(const StreamState &X) const {
+ return K == X.K;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ }
+};
+
+class SimpleStreamChecker : public Checker<check::PostCall,
+ check::PreCall,
+ check::DeadSymbols,
+ check::Bind,
+ check::RegionChanges> {
+
+ mutable IdentifierInfo *IIfopen, *IIfclose;
+
+ OwningPtr<BugType> DoubleCloseBugType;
+ OwningPtr<BugType> LeakBugType;
+
+ void initIdentifierInfo(ASTContext &Ctx) const;
+
+ void reportDoubleClose(SymbolRef FileDescSym,
+ const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void reportLeaks(SymbolVector LeakedStreams,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const;
+
+ bool guaranteedNotToCloseFile(const CallEvent &Call) const;
+
+public:
+ SimpleStreamChecker();
+
+ /// Process fopen.
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ /// Process fclose.
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+ 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;
+ }
+};
+
+} // end anonymous namespace
+
+/// The state of the checker is a map from tracked stream symbols to their
+/// state. Let's store it in the ProgramState.
+REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
+
+namespace {
+class StopTrackingCallback : public SymbolVisitor {
+ ProgramStateRef state;
+public:
+ StopTrackingCallback(ProgramStateRef st) : state(st) {}
+ ProgramStateRef getState() const { return state; }
+
+ bool VisitSymbol(SymbolRef sym) {
+ state = state->remove<StreamMap>(sym);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+
+SimpleStreamChecker::SimpleStreamChecker() : IIfopen(0), IIfclose(0) {
+ // Initialize the bug types.
+ DoubleCloseBugType.reset(new BugType("Double fclose",
+ "Unix Stream API Error"));
+
+ LeakBugType.reset(new BugType("Resource Leak",
+ "Unix Stream API Error"));
+ // Sinks are higher importance bugs as well as calls to assert() or exit(0).
+ LeakBugType->setSuppressOnSink(true);
+}
+
+void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ initIdentifierInfo(C.getASTContext());
+
+ if (!Call.isGlobalCFunction())
+ return;
+
+ if (Call.getCalleeIdentifier() != IIfopen)
+ return;
+
+ // Get the symbolic value corresponding to the file handle.
+ SymbolRef FileDesc = Call.getReturnValue().getAsSymbol();
+ if (!FileDesc)
+ return;
+
+ // Generate the next transition (an edge in the exploded graph).
+ ProgramStateRef State = C.getState();
+ State = State->set<StreamMap>(FileDesc, StreamState::getOpened());
+ C.addTransition(State);
+}
+
+void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ initIdentifierInfo(C.getASTContext());
+
+ if (!Call.isGlobalCFunction())
+ return;
+
+ if (Call.getCalleeIdentifier() != IIfclose)
+ return;
+
+ if (Call.getNumArgs() != 1)
+ return;
+
+ // Get the symbolic value corresponding to the file handle.
+ SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol();
+ if (!FileDesc)
+ return;
+
+ // Check if the stream has already been closed.
+ ProgramStateRef State = C.getState();
+ const StreamState *SS = State->get<StreamMap>(FileDesc);
+ if (SS && SS->isClosed()) {
+ reportDoubleClose(FileDesc, Call, C);
+ return;
+ }
+
+ // Generate the next transition, in which the stream is closed.
+ State = State->set<StreamMap>(FileDesc, StreamState::getClosed());
+ C.addTransition(State);
+}
+
+static bool isLeaked(SymbolRef Sym, const StreamState &SS,
+ bool IsSymDead, ProgramStateRef State) {
+ if (IsSymDead && SS.isOpened()) {
+ // If a symbol is NULL, assume that fopen failed on this path.
+ // A symbol should only be considered leaked if it is non-null.
+ ConstraintManager &CMgr = State->getConstraintManager();
+ ConditionTruthVal OpenFailed = CMgr.isNull(State, Sym);
+ return !OpenFailed.isConstrainedTrue();
+ }
+ return false;
+}
+
+void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolVector LeakedStreams;
+ StreamMapTy TrackedStreams = State->get<StreamMap>();
+ for (StreamMapTy::iterator I = TrackedStreams.begin(),
+ E = TrackedStreams.end(); I != E; ++I) {
+ SymbolRef Sym = I->first;
+ bool IsSymDead = SymReaper.isDead(Sym);
+
+ // Collect leaked symbols.
+ if (isLeaked(Sym, I->second, IsSymDead, State))
+ LeakedStreams.push_back(Sym);
+
+ // Remove the dead symbol from the streams map.
+ if (IsSymDead)
+ State = State->remove<StreamMap>(Sym);
+ }
+
+ ExplodedNode *N = C.addTransition(State);
+ reportLeaks(LeakedStreams, C, N);
+}
+
+void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ // We reached a bug, stop exploring the path here by generating a sink.
+ ExplodedNode *ErrNode = C.generateSink();
+ // If we've already reached this node on another path, return.
+ if (!ErrNode)
+ return;
+
+ // Generate the report.
+ BugReport *R = new BugReport(*DoubleCloseBugType,
+ "Closing a previously closed file stream", ErrNode);
+ R->addRange(Call.getSourceRange());
+ R->markInteresting(FileDescSym);
+ C.emitReport(R);
+}
+
+void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ // Attach bug reports to the leak node.
+ // TODO: Identify the leaked file descriptor.
+ for (llvm::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);
+ R->markInteresting(*I);
+ C.emitReport(R);
+ }
+}
+
+// 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())
+ return false;
+
+ // Handle cases where we know a buffer's /address/ can escape.
+ if (Call.argumentsMayEscape())
+ return false;
+
+ // Note, even though fclose closes the file, we do not list it here
+ // since the checker is modeling the call.
+
+ return true;
+}
+
+// If the symbol we are tracking is invalidated, 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())
+ 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;
+ // The symbol escaped. Optimistically, assume that the corresponding file
+ // handle will be closed somewhere else.
+ State = State->remove<StreamMap>(sym);
+ }
+ return State;
+}
+
+void SimpleStreamChecker::initIdentifierInfo(ASTContext &Ctx) const {
+ if (IIfopen)
+ return;
+ IIfopen = &Ctx.Idents.get("fopen");
+ IIfclose = &Ctx.Idents.get("fclose");
+}
+
+void ento::registerSimpleStreamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<SimpleStreamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 54cf5690c9ea..0c2f26683745 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -109,7 +109,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
if (range.isValid())
report->addRange(range);
- C.EmitReport(report);
+ C.emitReport(report);
}
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
@@ -118,8 +118,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
-
- SVal V = C.getState()->getSVal(RetE, C.getLocationContext());
+ RetE = RetE->IgnoreParens();
+
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal V = C.getState()->getSVal(RetE, LCtx);
const MemRegion *R = V.getAsRegion();
if (!R)
@@ -132,8 +134,9 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
return;
// Return stack memory in an ancestor stack frame is fine.
- const StackFrameContext *SFC = SS->getStackFrame();
- if (SFC != C.getLocationContext()->getCurrentStackFrame())
+ const StackFrameContext *CurFrame = LCtx->getCurrentStackFrame();
+ const StackFrameContext *MemFrame = SS->getStackFrame();
+ if (MemFrame != CurFrame)
return;
// Automatic reference counting automatically copies blocks.
@@ -141,6 +144,14 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
isa<BlockDataRegion>(R))
return;
+ // Returning a record by value is fine. (In this case, the returned
+ // expression will be a copy-constructor, possibly wrapped in an
+ // ExprWithCleanups node.)
+ if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
+ RetE = Cleanup->getSubExpr();
+ if (isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType())
+ return;
+
EmitStackError(C, R, RetE);
}
@@ -221,7 +232,7 @@ void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
if (range.isValid())
report->addRange(range);
- Ctx.EmitReport(report);
+ Ctx.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 731dd66b460b..c06ba7c304e6 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -104,15 +104,8 @@ private:
} // end anonymous namespace
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<StreamState>
- : public ProgramStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
- static void *GDMIndex() { static int x; return &x; }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
+
bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const FunctionDecl *FD = C.getCalleeDecl(CE);
@@ -219,11 +212,11 @@ void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef state = C.getState();
- unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, LCtx, Count));
+ cast<DefinedSVal>(svalBuilder.conjureSymbolVal(0, CE, LCtx,
+ C.blockCount()));
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
@@ -235,9 +228,9 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
if (SymbolRef Sym = RetVal.getAsSymbol()) {
// if RetVal is not NULL, set the symbol's state to Opened.
stateNotNull =
- stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE));
+ stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE));
stateNull =
- stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));
+ stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));
C.addTransition(stateNotNull);
C.addTransition(stateNull);
@@ -287,7 +280,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
"SEEK_SET, SEEK_END, or SEEK_CUR."));
BugReport *R = new BugReport(*BT_illegalwhence,
BT_illegalwhence->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -363,7 +356,7 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
BT_nullfp.reset(new BuiltinBug("NULL stream pointer",
"Stream pointer might be NULL."));
BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
return 0;
}
@@ -378,7 +371,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
if (!Sym)
return state;
- const StreamState *SS = state->get<StreamState>(Sym);
+ const StreamState *SS = state->get<StreamMap>(Sym);
// If the file stream is not tracked, return.
if (!SS)
@@ -395,22 +388,24 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
" closed. Cause undefined behaviour."));
BugReport *R = new BugReport(*BT_doubleclose,
BT_doubleclose->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
return NULL;
}
// Close the File Descriptor.
- return state->set<StreamState>(Sym, StreamState::getClosed(CE));
+ return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
}
void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const {
+ // TODO: Clean up the state.
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
ProgramStateRef state = C.getState();
- const StreamState *SS = state->get<StreamState>(Sym);
+ const StreamState *SS = state->get<StreamMap>(Sym);
+ // TODO: Shouldn't we have a continue here?
if (!SS)
return;
@@ -422,7 +417,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
"Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
@@ -430,10 +425,9 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
- typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
- SymMap M = state->get<StreamState>();
+ StreamMapTy M = state->get<StreamMap>();
- for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ for (StreamMapTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
StreamState SS = I->second;
if (SS.isOpened()) {
ExplodedNode *N = Ctx.addTransition(state);
@@ -443,7 +437,7 @@ void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
"Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
- Ctx.EmitReport(R);
+ Ctx.emitReport(R);
}
}
}
@@ -460,12 +454,12 @@ void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
if (!Sym)
return;
- const StreamState *SS = state->get<StreamState>(Sym);
+ const StreamState *SS = state->get<StreamMap>(Sym);
if(!SS)
return;
if (SS->isOpened())
- state = state->set<StreamState>(Sym, StreamState::getEscaped(S));
+ state = state->set<StreamMap>(Sym, StreamState::getEscaped(S));
C.addTransition(state);
}
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 113368254d67..382be8475bb8 100644
--- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -52,7 +52,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E,
initBugType();
BugReport *report = new BugReport(*BT, "tainted",N);
report->addRange(E->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 70a33c76db0c..70e141e574cd 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -99,11 +99,10 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
// Emit the bug report.
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, R);
+ bugreporter::trackNullOrUndefValue(N, Ex, *R);
R->addRange(Ex->getSourceRange());
- R->disablePathPruning();
- Ctx.EmitReport(R);
+ Ctx.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 675b38a5df26..30ccffaab055 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -96,7 +96,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR));
R->disablePathPruning();
// need location of block
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index e220499d73f4..415bab57287e 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -76,13 +76,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
BugReport *report = new BugReport(*BT, OS.str(), N);
if (Ex) {
report->addRange(Ex->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report);
+ bugreporter::trackNullOrUndefValue(N, Ex, *report);
}
else
- bugreporter::addTrackNullOrUndefValueVisitor(N, B, report);
+ bugreporter::trackNullOrUndefValue(N, B, *report);
- report->disablePathPruning();
- C.EmitReport(report);
+ C.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index 6ae3c1875fbf..b3a83e8e9179 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -42,8 +42,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
// Generate a report for this bug.
BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addRange(A->getIdx()->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, A->getIdx(), R);
- C.EmitReport(R);
+ bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 14a884e01b64..410010a335c3 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -78,10 +78,9 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
BugReport *R = new BugReport(*BT, str, N);
if (ex) {
R->addRange(ex->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, ex, R);
+ bugreporter::trackNullOrUndefValue(N, ex, *R);
}
- R->disablePathPruning();
- C.EmitReport(R);
+ C.emitReport(R);
}
void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index d35455c2191b..171e15b85ae7 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -41,6 +41,7 @@ public:
void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
@@ -138,7 +139,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
"Call to 'open' requires a third argument when "
"the 'O_CREAT' flag is set", N);
report->addRange(oflagsEx->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
@@ -183,11 +184,12 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
//===----------------------------------------------------------------------===//
-// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0
+// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
+// with allocation size 0
//===----------------------------------------------------------------------===//
// FIXME: Eventually these should be rolled into the MallocChecker, but right now
// they're more basic and valuable for widespread use.
@@ -224,8 +226,8 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
BugReport *report = new BugReport(*BT_mallocZero, os.str(), N);
report->addRange(arg->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, arg, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, arg, *report);
+ C.emitReport(report);
return true;
}
@@ -307,6 +309,11 @@ void UnixAPIChecker::CheckReallocZero(CheckerContext &C,
BasicAllocationCheck(C, CE, 2, 1, "realloc");
}
+void UnixAPIChecker::CheckReallocfZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 2, 1, "reallocf");
+}
+
void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
const CallExpr *CE) const {
BasicAllocationCheck(C, CE, 1, 0, "alloca");
@@ -339,6 +346,7 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
.Case("calloc", &UnixAPIChecker::CheckCallocZero)
.Case("malloc", &UnixAPIChecker::CheckMallocZero)
.Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
.Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
.Case("valloc", &UnixAPIChecker::CheckVallocZero)
.Default(NULL);
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index fab4adf3e0e2..58f9ec0f9b9b 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -69,8 +69,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(SizeE->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, SizeE, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, SizeE, *report);
+ C.emitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index efeba17a62ba..011d4c09a23f 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -20,33 +20,19 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- unsigned maxnodes, unsigned maxvisit,
- bool vizdot, bool vizubi,
- AnalysisPurgeMode purge,
- bool eager, bool trim,
- bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool eagerlyTrimEGraph,
- AnalysisIPAMode ipa,
- unsigned inlineMaxStack,
- unsigned inlineMaxFunctionSize,
- AnalysisInliningMode IMode,
- bool NoRetry)
- : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, /*addInitializers=*/true),
- Ctx(ctx), Diags(diags), LangOpts(lang),
+ AnalyzerOptions &Options)
+ : AnaCtxMgr(Options.UnoptimizedCFG,
+ /*AddImplicitDtors=*/true,
+ /*AddInitializers=*/true,
+ Options.includeTemporaryDtorsInCFG(),
+ Options.shouldSynthesizeBodies()),
+ Ctx(ctx),
+ Diags(diags),
+ LangOpts(lang),
PathConsumers(PDC),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- CheckerMgr(checkerMgr),
- MaxNodes(maxnodes), MaxVisit(maxvisit),
- VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim),
- EagerlyTrimEGraph(eagerlyTrimEGraph),
- IPAMode(ipa),
- InlineMaxStackDepth(inlineMaxStack),
- InlineMaxFunctionSize(inlineMaxFunctionSize),
- InliningMode(IMode),
- NoRetryExhausted(NoRetry)
-{
+ CheckerMgr(checkerMgr),
+ options(Options) {
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
new file mode 100644
index 000000000000..da88589c8696
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -0,0 +1,138 @@
+//===-- AnalyzerOptions.cpp - Analysis Engine Options -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains special accessors for analyzer configuration options
+// with string representations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace llvm;
+
+bool
+AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
+ if (IPAMode < Inlining)
+ return false;
+
+ if (!CXXMemberInliningMode) {
+ static const char *ModeKey = "c++-inlining";
+
+ StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
+ "methods").getValue());
+
+ CXXInlineableMemberKind &MutableMode =
+ const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
+
+ MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr)
+ .Case("constructors", CIMK_Constructors)
+ .Case("destructors", CIMK_Destructors)
+ .Case("none", CIMK_None)
+ .Case("methods", CIMK_MemberFunctions)
+ .Default(CXXInlineableMemberKind());
+
+ if (!MutableMode) {
+ // FIXME: We should emit a warning here about an unknown inlining kind,
+ // but the AnalyzerOptions doesn't have access to a diagnostic engine.
+ MutableMode = CIMK_None;
+ }
+ }
+
+ return CXXMemberInliningMode >= K;
+}
+
+static StringRef toString(bool b) { return b ? "true" : "false"; }
+
+bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
+ // FIXME: We should emit a warning here if the value is something other than
+ // "true", "false", or the empty string (meaning the default value),
+ // but the AnalyzerOptions doesn't have access to a diagnostic engine.
+ StringRef V(Config.GetOrCreateValue(Name, toString(DefaultVal)).getValue());
+ return llvm::StringSwitch<bool>(V)
+ .Case("true", true)
+ .Case("false", false)
+ .Default(DefaultVal);
+}
+
+bool AnalyzerOptions::getBooleanOption(llvm::Optional<bool> &V,
+ StringRef Name,
+ bool DefaultVal) {
+ if (!V.hasValue())
+ V = getBooleanOption(Name, DefaultVal);
+ return V.getValue();
+}
+
+bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
+ return getBooleanOption(IncludeTemporaryDtorsInCFG,
+ "cfg-temporary-dtors",
+ /* Default = */ false);
+}
+
+bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
+ return getBooleanOption(InlineCXXStandardLibrary,
+ "c++-stdlib-inlining",
+ /*Default=*/true);
+}
+
+bool AnalyzerOptions::mayInlineTemplateFunctions() {
+ return getBooleanOption(InlineTemplateFunctions,
+ "c++-template-inlining",
+ /*Default=*/true);
+}
+
+bool AnalyzerOptions::mayInlineObjCMethod() {
+ return getBooleanOption(ObjCInliningMode,
+ "objc-inlining",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::shouldPruneNullReturnPaths() {
+ return getBooleanOption(PruneNullReturnPaths,
+ "suppress-null-return-paths",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
+ return getBooleanOption(AvoidSuppressingNullArgumentPaths,
+ "avoid-suppressing-null-argument-paths",
+ /* Default = */ false);
+}
+
+int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
+ llvm::SmallString<10> StrBuf;
+ llvm::raw_svector_ostream OS(StrBuf);
+ OS << DefaultVal;
+
+ StringRef V(Config.GetOrCreateValue(Name, OS.str()).getValue());
+ int Res = DefaultVal;
+ bool b = V.getAsInteger(10, Res);
+ assert(!b && "analyzer-config option should be numeric");
+ (void) b;
+ return Res;
+}
+
+unsigned AnalyzerOptions::getAlwaysInlineSize() {
+ if (!AlwaysInlineSize.hasValue())
+ AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
+ return AlwaysInlineSize.getValue();
+}
+
+unsigned AnalyzerOptions::getGraphTrimInterval() {
+ if (!GraphTrimInterval.hasValue())
+ GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
+ return GraphTrimInterval.getValue();
+}
+
+bool AnalyzerOptions::shouldSynthesizeBodies() {
+ return getBooleanOption("faux-bodies", true);
+}
diff --git a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
deleted file mode 100644
index 8897756a92d9..000000000000
--- a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-//== BasicConstraintManager.cpp - Manage basic constraints.------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines BasicConstraintManager, a class that tracks simple
-// equality and inequality constraints on symbolic values of ProgramState.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SimpleConstraintManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-
-namespace { class ConstNotEq {}; }
-namespace { class ConstEq {}; }
-
-typedef llvm::ImmutableMap<SymbolRef,ProgramState::IntSetTy> ConstNotEqTy;
-typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
-
-static int ConstEqIndex = 0;
-static int ConstNotEqIndex = 0;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<ConstNotEq> :
- public ProgramStatePartialTrait<ConstNotEqTy> {
- static inline void *GDMIndex() { return &ConstNotEqIndex; }
-};
-
-template<>
-struct ProgramStateTrait<ConstEq> : public ProgramStatePartialTrait<ConstEqTy> {
- static inline void *GDMIndex() { return &ConstEqIndex; }
-};
-}
-}
-
-namespace {
-// BasicConstraintManager only tracks equality and inequality constraints of
-// constants and integer variables.
-class BasicConstraintManager
- : public SimpleConstraintManager {
- ProgramState::IntSetTy::Factory ISetFactory;
-public:
- BasicConstraintManager(ProgramStateManager &statemgr, SubEngine &subengine)
- : SimpleConstraintManager(subengine, statemgr.getBasicVals()),
- ISetFactory(statemgr.getAllocator()) {}
-
- ProgramStateRef assumeSymEquality(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment,
- bool Assumption);
-
- ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- return assumeSymEquality(State, Sym, V, Adjustment, false);
- }
-
- ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- return assumeSymEquality(State, Sym, V, Adjustment, true);
- }
-
- ProgramStateRef assumeSymLT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef assumeSymGT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef assumeSymGE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef assumeSymLE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef AddEQ(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V);
-
- ProgramStateRef AddNE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V);
-
- const llvm::APSInt* getSymVal(ProgramStateRef state,
- SymbolRef sym) const;
-
- bool isNotEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const;
-
- bool isEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const;
-
- ProgramStateRef removeDeadBindings(ProgramStateRef state,
- SymbolReaper& SymReaper);
-
- bool performTest(llvm::APSInt SymVal, llvm::APSInt Adjustment,
- BinaryOperator::Opcode Op, llvm::APSInt ComparisonVal);
-
- void print(ProgramStateRef state,
- raw_ostream &Out,
- const char* nl,
- const char *sep);
-};
-
-} // end anonymous namespace
-
-ConstraintManager*
-ento::CreateBasicConstraintManager(ProgramStateManager& statemgr,
- SubEngine &subengine) {
- return new BasicConstraintManager(statemgr, subengine);
-}
-
-// FIXME: This is a more general utility and should live somewhere else.
-bool BasicConstraintManager::performTest(llvm::APSInt SymVal,
- llvm::APSInt Adjustment,
- BinaryOperator::Opcode Op,
- llvm::APSInt ComparisonVal) {
- APSIntType Type(Adjustment);
- Type.apply(SymVal);
- Type.apply(ComparisonVal);
- SymVal += Adjustment;
-
- assert(BinaryOperator::isComparisonOp(Op));
- BasicValueFactory &BVF = getBasicVals();
- const llvm::APSInt *Result = BVF.evalAPSInt(Op, SymVal, ComparisonVal);
- assert(Result && "Comparisons should always have valid results.");
-
- return Result->getBoolValue();
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymEquality(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment,
- bool Assumption) {
- // Before we do any real work, see if the value can even show up.
- APSIntType AdjustmentType(Adjustment);
- if (AdjustmentType.testInRange(V) != APSIntType::RTR_Within)
- return Assumption ? NULL : State;
-
- // Get the symbol type.
- BasicValueFactory &BVF = getBasicVals();
- ASTContext &Ctx = BVF.getContext();
- APSIntType SymbolType = BVF.getAPSIntType(Sym->getType(Ctx));
-
- // First, see if the adjusted value is within range for the symbol.
- llvm::APSInt Adjusted = AdjustmentType.convert(V) - Adjustment;
- if (SymbolType.testInRange(Adjusted) != APSIntType::RTR_Within)
- return Assumption ? NULL : State;
-
- // Now we can do things properly in the symbol space.
- SymbolType.apply(Adjusted);
-
- // Second, determine if sym == X, where X+Adjustment != V.
- if (const llvm::APSInt *X = getSymVal(State, Sym)) {
- bool IsFeasible = (*X == Adjusted);
- return (IsFeasible == Assumption) ? State : NULL;
- }
-
- // Third, determine if we already know sym+Adjustment != V.
- if (isNotEqual(State, Sym, Adjusted))
- return Assumption ? NULL : State;
-
- // If we reach here, sym is not a constant and we don't know if it is != V.
- // Make the correct assumption.
- if (Assumption)
- return AddEQ(State, Sym, Adjusted);
- else
- return AddNE(State, Sym, Adjusted);
-}
-
-// The logic for these will be handled in another ConstraintManager.
-// Approximate it here anyway by handling some edge cases.
-ProgramStateRef
-BasicConstraintManager::assumeSymLT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- if (V > ComparisonType.convert(Max)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Is 'V' the smallest possible value, or out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- if (V <= ComparisonType.convert(Min)) {
- // sym cannot be any value less than 'V'. This path is infeasible.
- return NULL;
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj < V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_LT, V);
- return isFeasible ? state : NULL;
- }
-
- // FIXME: For now have assuming x < y be the same as assuming sym != V;
- return assumeSymNE(state, sym, V, Adjustment);
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymGT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' the largest possible value, or out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- if (V >= ComparisonType.convert(Max)) {
- // sym cannot be any value greater than 'V'. This path is infeasible.
- return NULL;
- }
-
- // Is 'V' out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- if (V < ComparisonType.convert(Min)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj > V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_GT, V);
- return isFeasible ? state : NULL;
- }
-
- // FIXME: For now have assuming x > y be the same as assuming sym != V;
- return assumeSymNE(state, sym, V, Adjustment);
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymGE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' the largest possible value, or out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- ComparisonType.apply(Max);
-
- if (V > Max) {
- // sym cannot be any value greater than 'V'. This path is infeasible.
- return NULL;
- } else if (V == Max) {
- // If the path is feasible then as a consequence we know that
- // 'sym+Adjustment == V' because there are no larger values.
- // Add this constraint.
- return assumeSymEQ(state, sym, V, Adjustment);
- }
-
- // Is 'V' out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- if (V < ComparisonType.convert(Min)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_GE, V);
- return isFeasible ? state : NULL;
- }
-
- return state;
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymLE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- if (V > ComparisonType.convert(Max)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Is 'V' the smallest possible value, or out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- ComparisonType.apply(Min);
-
- if (V < Min) {
- // sym cannot be any value less than 'V'. This path is infeasible.
- return NULL;
- } else if (V == Min) {
- // If the path is feasible then as a consequence we know that
- // 'sym+Adjustment == V' because there are no smaller values.
- // Add this constraint.
- return assumeSymEQ(state, sym, V, Adjustment);
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_LE, V);
- return isFeasible ? state : NULL;
- }
-
- return state;
-}
-
-ProgramStateRef BasicConstraintManager::AddEQ(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) {
- // Now that we have an actual value, we can throw out the NE-set.
- // Create a new state with the old bindings replaced.
- state = state->remove<ConstNotEq>(sym);
- return state->set<ConstEq>(sym, &getBasicVals().getValue(V));
-}
-
-ProgramStateRef BasicConstraintManager::AddNE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) {
-
- // First, retrieve the NE-set associated with the given symbol.
- ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
- ProgramState::IntSetTy S = T ? *T : ISetFactory.getEmptySet();
-
- // Now add V to the NE set.
- S = ISetFactory.add(S, &getBasicVals().getValue(V));
-
- // Create a new state with the old binding replaced.
- return state->set<ConstNotEq>(sym, S);
-}
-
-const llvm::APSInt* BasicConstraintManager::getSymVal(ProgramStateRef state,
- SymbolRef sym) const {
- const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
- return T ? *T : NULL;
-}
-
-bool BasicConstraintManager::isNotEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const {
-
- // Retrieve the NE-set associated with the given symbol.
- const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
-
- // See if V is present in the NE-set.
- return T ? T->contains(&getBasicVals().getValue(V)) : false;
-}
-
-bool BasicConstraintManager::isEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const {
- // Retrieve the EQ-set associated with the given symbol.
- const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
- // See if V is present in the EQ-set.
- return T ? **T == V : false;
-}
-
-/// Scan all symbols referenced by the constraints. If the symbol is not alive
-/// as marked in LSymbols, mark it as dead in DSymbols.
-ProgramStateRef
-BasicConstraintManager::removeDeadBindings(ProgramStateRef state,
- SymbolReaper& SymReaper) {
-
- ConstEqTy CE = state->get<ConstEq>();
- ConstEqTy::Factory& CEFactory = state->get_context<ConstEq>();
-
- for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
- SymbolRef sym = I.getKey();
- if (SymReaper.maybeDead(sym))
- CE = CEFactory.remove(CE, sym);
- }
- state = state->set<ConstEq>(CE);
-
- ConstNotEqTy CNE = state->get<ConstNotEq>();
- ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>();
-
- for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
- SymbolRef sym = I.getKey();
- if (SymReaper.maybeDead(sym))
- CNE = CNEFactory.remove(CNE, sym);
- }
-
- return state->set<ConstNotEq>(CNE);
-}
-
-void BasicConstraintManager::print(ProgramStateRef state,
- raw_ostream &Out,
- const char* nl, const char *sep) {
- // Print equality constraints.
-
- ConstEqTy CE = state->get<ConstEq>();
-
- if (!CE.isEmpty()) {
- Out << nl << sep << "'==' constraints:";
- for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
- Out << nl << " $" << I.getKey() << " : " << *I.getData();
- }
-
- // Print != constraints.
-
- ConstNotEqTy CNE = state->get<ConstNotEq>();
-
- if (!CNE.isEmpty()) {
- Out << nl << sep << "'!=' constraints:";
-
- for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
- Out << nl << " $" << I.getKey() << " : ";
- bool isFirst = true;
-
- ProgramState::IntSetTy::iterator J = I.getData().begin(),
- EJ = I.getData().end();
-
- for ( ; J != EJ; ++J) {
- if (isFirst) isFirst = false;
- else Out << ", ";
-
- Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream.
- }
- }
- }
-}
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 20c73612c481..a6c400f3704d 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -101,11 +101,7 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) {
- unsigned bits = Ctx.getTypeSize(T);
- llvm::APSInt V(bits,
- T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T));
- V = X;
- return getValue(V);
+ return getValue(getAPSIntType(T).getValue(X));
}
const CompoundValData*
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 571baecd729d..c898d65a5f95 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -118,10 +118,82 @@ GetCurrentOrNextStmt(const ExplodedNode *N) {
// Diagnostic cleanup.
//===----------------------------------------------------------------------===//
+static PathDiagnosticEventPiece *
+eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
+ PathDiagnosticEventPiece *Y) {
+ // Prefer diagnostics that come from ConditionBRVisitor over
+ // those that came from TrackConstraintBRVisitor.
+ const void *tagPreferred = ConditionBRVisitor::getTag();
+ const void *tagLesser = TrackConstraintBRVisitor::getTag();
+
+ if (X->getLocation() != Y->getLocation())
+ return 0;
+
+ if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
+ return X;
+
+ if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
+ return Y;
+
+ return 0;
+}
+
+/// An optimization pass over PathPieces that removes redundant diagnostics
+/// generated by both ConditionBRVisitor and TrackConstraintBRVisitor. Both
+/// BugReporterVisitors use different methods to generate diagnostics, with
+/// one capable of emitting diagnostics in some cases but not in others. This
+/// can lead to redundant diagnostic pieces at the same point in a path.
+static void removeRedundantMsgs(PathPieces &path) {
+ unsigned N = path.size();
+ if (N < 2)
+ return;
+ // NOTE: this loop intentionally is not using an iterator. Instead, we
+ // are streaming the path and modifying it in place. This is done by
+ // grabbing the front, processing it, and if we decide to keep it append
+ // it to the end of the path. The entire path is processed in this way.
+ for (unsigned i = 0; i < N; ++i) {
+ IntrusiveRefCntPtr<PathDiagnosticPiece> piece(path.front());
+ path.pop_front();
+
+ switch (piece->getKind()) {
+ case clang::ento::PathDiagnosticPiece::Call:
+ removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path);
+ break;
+ case clang::ento::PathDiagnosticPiece::Macro:
+ removeRedundantMsgs(cast<PathDiagnosticMacroPiece>(piece)->subPieces);
+ break;
+ case clang::ento::PathDiagnosticPiece::ControlFlow:
+ break;
+ case clang::ento::PathDiagnosticPiece::Event: {
+ if (i == N-1)
+ break;
+
+ if (PathDiagnosticEventPiece *nextEvent =
+ dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) {
+ PathDiagnosticEventPiece *event =
+ cast<PathDiagnosticEventPiece>(piece);
+ // Check to see if we should keep one of the two pieces. If we
+ // come up with a preference, record which piece to keep, and consume
+ // another piece from the path.
+ if (PathDiagnosticEventPiece *pieceToKeep =
+ eventsDescribeSameCondition(event, nextEvent)) {
+ piece = pieceToKeep;
+ path.pop_front();
+ ++i;
+ }
+ }
+ break;
+ }
+ }
+ path.push_back(piece);
+ }
+}
+
/// 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.
-static bool RemoveUneededCalls(PathPieces &pieces) {
+bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
+ PathDiagnosticCallPiece *CallWithLoc) {
bool containsSomethingInteresting = false;
const unsigned N = pieces.size();
@@ -131,30 +203,49 @@ static bool RemoveUneededCalls(PathPieces &pieces) {
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
pieces.pop_front();
+ // Throw away pieces with invalid locations.
+ if (piece->getKind() != PathDiagnosticPiece::Call &&
+ piece->getLocation().asLocation().isInvalid())
+ continue;
+
switch (piece->getKind()) {
case PathDiagnosticPiece::Call: {
PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
+ // Check if the location context is interesting.
+ assert(LocationContextMap.count(call));
+ if (R->isInteresting(LocationContextMap[call])) {
+ containsSomethingInteresting = true;
+ break;
+ }
// Recursively clean out the subclass. Keep this call around if
// it contains any informative diagnostics.
- if (!RemoveUneededCalls(call->path))
+ PathDiagnosticCallPiece *NewCallWithLoc =
+ call->getLocation().asLocation().isValid()
+ ? call : CallWithLoc;
+
+ if (!RemoveUneededCalls(call->path, R, NewCallWithLoc))
continue;
+
+ if (NewCallWithLoc == CallWithLoc && CallWithLoc) {
+ call->callEnter = CallWithLoc->callEnter;
+ }
+
containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::Macro: {
PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
- if (!RemoveUneededCalls(macro->subPieces))
+ if (!RemoveUneededCalls(macro->subPieces, R))
continue;
containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::Event: {
PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece);
+
// We never throw away an event, but we do throw it away wholesale
// as part of a path if we throw the entire path away.
- if (event->isPrunable())
- continue;
- containsSomethingInteresting = true;
+ containsSomethingInteresting |= !event->isPrunable();
break;
}
case PathDiagnosticPiece::ControlFlow:
@@ -382,6 +473,35 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
}
//===----------------------------------------------------------------------===//
+// "Visitors only" path diagnostic generation algorithm.
+//===----------------------------------------------------------------------===//
+static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode *N,
+ ArrayRef<BugReporterVisitor *> visitors) {
+ // All path generation skips the very first node (the error node).
+ // This is because there is special handling for the end-of-path note.
+ N = N->getFirstPred();
+ if (!N)
+ return true;
+
+ BugReport *R = PDB.getBugReport();
+ while (const ExplodedNode *Pred = N->getFirstPred()) {
+ for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
+ E = visitors.end();
+ I != E; ++I) {
+ // Visit all the node pairs, but throw the path pieces away.
+ PathDiagnosticPiece *Piece = (*I)->VisitNode(N, Pred, PDB, *R);
+ delete Piece;
+ }
+
+ N = Pred;
+ }
+
+ return R->isValid();
+}
+
+//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*> StackDiagPair;
@@ -412,7 +532,7 @@ static void updateStackPiecesWithMessage(PathDiagnosticPiece *P,
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
-static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
+static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
ArrayRef<BugReporterVisitor *> visitors) {
@@ -430,55 +550,60 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
NextNode = GetPredecessorNode(N);
ProgramPoint P = N->getLocation();
-
- if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
- PathDiagnosticCallPiece *C =
- PathDiagnosticCallPiece::construct(N, *CE, SMgr);
- PD.getActivePath().push_front(C);
- PD.pushActivePath(&C->path);
- CallStack.push_back(StackDiagPair(C, N));
- continue;
- }
-
- if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
- // Flush all locations, and pop the active path.
- bool VisitedEntireCall = PD.isWithinCall();
- PD.popActivePath();
-
- // Either we just added a bunch of stuff to the top-level path, or
- // we have a previous CallExitEnd. If the former, it means that the
- // path terminated within a function call. We must then take the
- // current contents of the active path and place it within
- // a new PathDiagnosticCallPiece.
- PathDiagnosticCallPiece *C;
- if (VisitedEntireCall) {
- C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
- } else {
- const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+
+ do {
+ if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+ PathDiagnosticCallPiece *C =
+ PathDiagnosticCallPiece::construct(N, *CE, SMgr);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ PD.getActivePath().push_front(C);
+ PD.pushActivePath(&C->path);
+ CallStack.push_back(StackDiagPair(C, N));
+ break;
}
- C->setCallee(*CE, SMgr);
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
+ if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ // Flush all locations, and pop the active path.
+ bool VisitedEntireCall = PD.isWithinCall();
+ PD.popActivePath();
+
+ // Either we just added a bunch of stuff to the top-level path, or
+ // we have a previous CallExitEnd. If the former, it means that the
+ // path terminated within a function call. We must then take the
+ // current contents of the active path and place it within
+ // a new PathDiagnosticCallPiece.
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ }
+
+ C->setCallee(*CE, SMgr);
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ break;
}
- continue;
- }
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- const CFGBlock *Src = BE->getSrc();
- const CFGBlock *Dst = BE->getDst();
- const Stmt *T = Src->getTerminator();
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const CFGBlock *Src = BE->getSrc();
+ const CFGBlock *Dst = BE->getDst();
+ const Stmt *T = Src->getTerminator();
- if (!T)
- continue;
+ if (!T)
+ break;
- PathDiagnosticLocation Start =
- PathDiagnosticLocation::createBegin(T, SMgr,
- N->getLocationContext());
+ PathDiagnosticLocation Start =
+ PathDiagnosticLocation::createBegin(T, SMgr,
+ N->getLocationContext());
- switch (T->getStmtClass()) {
+ switch (T->getStmtClass()) {
default:
break;
@@ -487,16 +612,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
const Stmt *S = GetNextStmt(N);
if (!S)
- continue;
+ break;
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
os << "Control jumps to line "
- << End.asLocation().getExpansionLineNumber();
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ << End.asLocation().getExpansionLineNumber();
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
break;
}
@@ -509,52 +634,52 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticLocation End(S, SMgr, LC);
switch (S->getStmtClass()) {
- default:
- os << "No cases match in the switch statement. "
- "Control jumps to line "
- << End.asLocation().getExpansionLineNumber();
- break;
- case Stmt::DefaultStmtClass:
- os << "Control jumps to the 'default' case at line "
- << End.asLocation().getExpansionLineNumber();
- break;
-
- case Stmt::CaseStmtClass: {
- os << "Control jumps to 'case ";
- const CaseStmt *Case = cast<CaseStmt>(S);
- const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
-
- // Determine if it is an enum.
- bool GetRawInt = true;
-
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
- // FIXME: Maybe this should be an assertion. Are there cases
- // were it is not an EnumConstantDecl?
- const EnumConstantDecl *D =
+ default:
+ os << "No cases match in the switch statement. "
+ "Control jumps to line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
+ case Stmt::DefaultStmtClass:
+ os << "Control jumps to the 'default' case at line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
+
+ case Stmt::CaseStmtClass: {
+ os << "Control jumps to 'case ";
+ const CaseStmt *Case = cast<CaseStmt>(S);
+ const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
+
+ // Determine if it is an enum.
+ bool GetRawInt = true;
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
+ // FIXME: Maybe this should be an assertion. Are there cases
+ // were it is not an EnumConstantDecl?
+ const EnumConstantDecl *D =
dyn_cast<EnumConstantDecl>(DR->getDecl());
- if (D) {
- GetRawInt = false;
- os << *D;
- }
+ if (D) {
+ GetRawInt = false;
+ os << *D;
}
+ }
- if (GetRawInt)
- os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
+ if (GetRawInt)
+ os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
- os << ":' at line "
- << End.asLocation().getExpansionLineNumber();
- break;
- }
+ os << ":' at line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
}
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ }
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
os << "'Default' branch taken. ";
const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
break;
@@ -565,12 +690,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
break;
}
- // Determine control-flow for ternary '?'.
+ // Determine control-flow for ternary '?'.
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
std::string sbuf;
@@ -587,12 +712,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
break;
}
- // Determine control-flow for short-circuited '&&' and '||'.
+ // Determine control-flow for short-circuited '&&' and '||'.
case Stmt::BinaryOperatorClass: {
if (!PDB.supportsLogicalOpControlFlow())
break;
@@ -609,16 +734,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "false";
PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
- PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
os << "true";
PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
}
else {
@@ -629,16 +754,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "false";
PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
os << "true";
PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
- PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
}
@@ -656,8 +781,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
@@ -665,8 +790,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is false. Exiting loop"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Loop condition is false. Exiting loop"));
}
break;
@@ -683,16 +808,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is true. Entering loop body"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Loop condition is true. Entering loop body"));
}
break;
@@ -705,16 +830,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
End = PDB.getEnclosingStmtLocation(S);
if (*(Src->succ_begin()+1) == Dst)
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking false branch"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Taking false branch"));
else
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking true branch"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Taking true branch"));
break;
}
+ }
}
- }
+ } while(0);
if (NextNode) {
// Add diagnostic pieces from custom visitors.
@@ -730,9 +856,13 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
}
+ if (!PDB.getBugReport()->isValid())
+ return false;
+
// After constructing the full PathDiagnostic, do a pass over it to compact
// PathDiagnosticPieces that occur within a macro.
CompactPathDiagnostic(PD.getMutablePieces(), PDB.getSourceManager());
+ return true;
}
//===----------------------------------------------------------------------===//
@@ -944,6 +1074,11 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc);
const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc);
+ if (PrevLocClean.asLocation().isInvalid()) {
+ PrevLoc = NewLoc;
+ return;
+ }
+
if (NewLocClean.asLocation() == PrevLocClean.asLocation())
return;
@@ -1133,7 +1268,7 @@ static void reversePropagateInterestingSymbols(BugReport &R,
}
}
-static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
ArrayRef<BugReporterVisitor *> visitors) {
@@ -1166,6 +1301,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SM);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
EB.addEdge(C->callReturn, true);
EB.flushLocations();
@@ -1202,6 +1339,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
} else {
const Decl *Caller = CE->getLocationContext()->getDecl();
C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
}
C->setCallee(*CE, SM);
@@ -1234,20 +1373,15 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
}
}
- const CFGBlock &Blk = *BE->getSrc();
- const Stmt *Term = Blk.getTerminator();
-
// Are we jumping to the head of a loop? Add a special diagnostic.
- if (const Stmt *Loop = BE->getDst()->getLoopTarget()) {
+ if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
PathDiagnosticLocation L(Loop, SM, PDB.LC);
const CompoundStmt *CS = NULL;
- if (!Term) {
- if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(FS->getBody());
- else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(WS->getBody());
- }
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(FS->getBody());
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(WS->getBody());
PathDiagnosticEventPiece *p =
new PathDiagnosticEventPiece(L,
@@ -1263,15 +1397,16 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(BL);
}
}
-
- if (Term)
+
+ if (const Stmt *Term = BE->getSrc()->getTerminator())
EB.addContext(Term);
break;
}
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- if (const CFGStmt *S = BE->getFirstElement().getAs<CFGStmt>()) {
+ CFGElement First = BE->getFirstElement();
+ if (const CFGStmt *S = First.getAs<CFGStmt>()) {
const Stmt *stmt = S->getStmt();
if (IsControlFlowExpr(stmt)) {
// Add the proper context for '&&', '||', and '?'.
@@ -1306,6 +1441,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
}
}
}
+
+ return PDB.getBugReport()->isValid();
}
//===----------------------------------------------------------------------===//
@@ -1414,6 +1551,12 @@ void BugReport::markInteresting(SVal V) {
markInteresting(V.getAsSymbol());
}
+void BugReport::markInteresting(const LocationContext *LC) {
+ if (!LC)
+ return;
+ InterestingLocationContexts.insert(LC);
+}
+
bool BugReport::isInteresting(SVal V) {
return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol());
}
@@ -1438,6 +1581,12 @@ bool BugReport::isInteresting(const MemRegion *R) {
return false;
}
+bool BugReport::isInteresting(const LocationContext *LC) {
+ if (!LC)
+ return false;
+ return InterestingLocationContexts.count(LC);
+}
+
void BugReport::lazyInitializeInterestingSets() {
if (interestingSymbols.empty()) {
interestingSymbols.push_back(new Symbols());
@@ -1823,17 +1972,27 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
path.push_back(*I);
}
-void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
+bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticConsumer &PC,
ArrayRef<BugReport *> &bugReports) {
-
assert(!bugReports.empty());
+
+ bool HasValid = false;
SmallVector<const ExplodedNode *, 10> 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 {
+ errorNodes.push_back(0);
+ }
}
+ // If all the reports have been marked invalid, 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*>,
@@ -1844,6 +2003,7 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
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);
@@ -1870,36 +2030,53 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
visitors.push_back((*I)->clone());
// Clear out the active path from any previous work.
- PD.getActivePath().clear();
+ PD.resetPath();
originalReportConfigToken = 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) {
- if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
- assert (!LastPiece &&
- "There can only be one final piece in a diagnostic.");
- LastPiece = Piece;
+ if (PDB.getGenerationScheme() != PathDiagnosticConsumer::None) {
+ PathDiagnosticPiece *LastPiece = 0;
+ for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
+ I != E; ++I) {
+ if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
+ assert (!LastPiece &&
+ "There can only be one final piece in a diagnostic.");
+ LastPiece = Piece;
+ }
}
+ if (!LastPiece)
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ if (LastPiece)
+ PD.setEndOfPath(LastPiece);
+ else
+ return false;
}
- if (!LastPiece)
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
- if (LastPiece)
- PD.getActivePath().push_back(LastPiece);
- else
- return;
switch (PDB.getGenerationScheme()) {
case PathDiagnosticConsumer::Extensive:
- GenerateExtensivePathDiagnostic(PD, PDB, N, visitors);
+ 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:
- GenerateMinimalPathDiagnostic(PD, PDB, N, visitors);
+ 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);
+ }
break;
case PathDiagnosticConsumer::None:
- llvm_unreachable("PathDiagnosticConsumer::None should never appear here");
+ 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);
+ }
+ break;
}
// Clean up the visitors we used.
@@ -1910,18 +2087,26 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
} while(finalReportConfigToken != originalReportConfigToken);
// Finally, prune the diagnostic path of uninteresting stuff.
- if (R->shouldPrunePath()) {
- bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces());
- assert(hasSomethingInteresting);
- (void) hasSomethingInteresting;
+ if (!PD.path.empty()) {
+ // Remove messages that are basically the same.
+ removeRedundantMsgs(PD.getMutablePieces());
+
+ if (R->shouldPrunePath()) {
+ bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces(),
+ R);
+ assert(hasSomethingInteresting);
+ (void) hasSomethingInteresting;
+ }
}
+
+ return true;
}
void BugReporter::Register(BugType *BT) {
BugTypes = F.add(BugTypes, BT);
}
-void BugReporter::EmitReport(BugReport* R) {
+void BugReporter::emitReport(BugReport* R) {
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
@@ -2078,17 +2263,17 @@ void BugReporter::FlushReport(BugReport *exampleReport,
OwningPtr<PathDiagnostic>
D(new PathDiagnostic(exampleReport->getDeclWithIssue(),
exampleReport->getBugType().getName(),
- PD.useVerboseDescription()
- ? exampleReport->getDescription()
- : exampleReport->getShortDescription(),
+ exampleReport->getDescription(),
+ exampleReport->getShortDescription(/*Fallback=*/false),
BT.getCategory()));
// Generate the full path diagnostic, using the generation scheme
- // specified by the PathDiagnosticConsumer.
- if (PD.getGenerationScheme() != PathDiagnosticConsumer::None) {
- if (!bugReports.empty())
- GeneratePathDiagnostic(*D.get(), PD, bugReports);
- }
+ // specified by the PathDiagnosticConsumer. Note that we have to generate
+ // path diagnostics even for consumers which do not support paths, because
+ // the BugReporterVisitors may mark this bug as a false positive.
+ if (!bugReports.empty())
+ if (!generatePathDiagnostic(*D.get(), PD, bugReports))
+ return;
// If the path is empty, generate a single step path with the location
// of the issue.
@@ -2100,7 +2285,7 @@ void BugReporter::FlushReport(BugReport *exampleReport,
llvm::tie(Beg, End) = exampleReport->getRanges();
for ( ; Beg != End; ++Beg)
piece->addRange(*Beg);
- D->getActivePath().push_back(piece);
+ D->setEndOfPath(piece);
}
// Get the meta data.
@@ -2124,7 +2309,7 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
BugReport *R = new BugReport(*BT, str, Loc);
R->setDeclWithIssue(DeclWithIssue);
for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
- EmitReport(R);
+ emitReport(R);
}
BugType *BugReporter::getBugTypeForName(StringRef name,
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index e7295878fa6f..328e8a650df1 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -17,10 +17,13 @@
#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 "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace ento;
@@ -29,10 +32,24 @@ using namespace ento;
// Utility functions.
//===----------------------------------------------------------------------===//
+bool bugreporter::isDeclRefExprToReference(const Expr *E) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ return DRE->getDecl()->getType()->isReferenceType();
+ }
+ return false;
+}
+
const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ const PostStmt *Loc = N->getLocationAs<PostStmt>();
+ if (!Loc)
+ return 0;
+
+ const Expr *S = dyn_cast<Expr>(Loc->getStmt());
+ if (!S)
+ return 0;
+ S = S->IgnoreParenCasts();
while (true) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
@@ -45,7 +62,12 @@ const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
return U->getSubExpr()->IgnoreParenCasts();
}
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
- return ME->getBase()->IgnoreParenCasts();
+ if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
+ return ME->getBase()->IgnoreParenCasts();
+ }
+ }
+ else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(S)) {
+ return IvarRef->getBase()->IgnoreParenCasts();
}
else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
return AE->getBase();
@@ -103,6 +125,228 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
}
+namespace {
+/// Emits an extra note at the return statement of an interesting stack frame.
+///
+/// The returned value is marked as an interesting value, and if it's null,
+/// adds a visitor to track where it became null.
+///
+/// This visitor is intended to be used when another visitor discovers that an
+/// interesting value comes from an inlined function call.
+class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> {
+ const StackFrameContext *StackFrame;
+ enum {
+ Initial,
+ MaybeSuppress,
+ Satisfied
+ } Mode;
+
+public:
+ ReturnVisitor(const StackFrameContext *Frame)
+ : StackFrame(Frame), Mode(Initial) {}
+
+ static void *getTag() {
+ static int Tag = 0;
+ return static_cast<void *>(&Tag);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(ReturnVisitor::getTag());
+ ID.AddPointer(StackFrame);
+ }
+
+ /// Adds a ReturnVisitor if the given statement represents a call that was
+ /// inlined.
+ ///
+ /// This will search back through the ExplodedGraph, starting from the given
+ /// node, looking for when the given statement was processed. If it turns out
+ /// 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) {
+ if (!CallEvent::isCallStmt(S))
+ return;
+
+ // First, find when we processed the statement.
+ do {
+ if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>())
+ if (CEE->getCalleeContext()->getCallSite() == S)
+ break;
+ if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>())
+ if (SP->getStmt() == S)
+ break;
+
+ Node = Node->getFirstPred();
+ } while (Node);
+
+ // Next, step over any post-statement checks.
+ while (Node && isa<PostStmt>(Node->getLocation()))
+ Node = Node->getFirstPred();
+
+ // 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));
+ }
+ }
+ }
+ }
+
+ /// Returns true if any counter-suppression heuristics are enabled for
+ /// ReturnVisitor.
+ static bool hasCounterSuppression(AnalyzerOptions &Options) {
+ return Options.shouldAvoidSuppressingNullArgumentPaths();
+ }
+
+ PathDiagnosticPiece *visitNodeInitial(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ // Only print a message at the interesting return statement.
+ if (N->getLocationContext() != StackFrame)
+ return 0;
+
+ const StmtPoint *SP = N->getLocationAs<StmtPoint>();
+ if (!SP)
+ return 0;
+
+ const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt());
+ if (!Ret)
+ return 0;
+
+ // Okay, we're at the right return statement, but do we have the return
+ // value available?
+ ProgramStateRef State = N->getState();
+ SVal V = State->getSVal(Ret, StackFrame);
+ if (V.isUnknownOrUndef())
+ return 0;
+
+ // Don't print any more notes after this one.
+ Mode = Satisfied;
+
+ const Expr *RetE = Ret->getRetValue();
+ assert(RetE && "Tracking a return value for a void function");
+ 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)) {
+ BR.markInteresting(V);
+ ReturnVisitor::addVisitorIfNecessary(N, RetE, BR);
+ return 0;
+ }
+
+ // If we're returning 0, we should track where that 0 came from.
+ bugreporter::trackNullOrUndefValue(N, RetE, BR);
+
+ // 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
+ // 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 (RetE->getType()->isObjCObjectPointerType())
+ Out << "Returning nil";
+ else
+ Out << "Returning null pointer";
+ } else {
+ 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 << "')";
+
+ PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame);
+ return new PathDiagnosticEventPiece(L, Out.str());
+ }
+
+ PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ // Are we at the entry node for this call?
+ const CallEnter *CE = N->getLocationAs<CallEnter>();
+ if (!CE)
+ return 0;
+
+ if (CE->getCalleeContext() != StackFrame)
+ return 0;
+
+ 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;
+
+ 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.)
+ }
+ }
+
+ // There is no reason not to suppress this report; go ahead and do it.
+ BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ return 0;
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ switch (Mode) {
+ case Initial:
+ return visitNodeInitial(N, PrevN, BRC, BR);
+ case MaybeSuppress:
+ return visitNodeMaybeSuppress(N, PrevN, BRC, BR);
+ case Satisfied:
+ return 0;
+ }
+
+ llvm_unreachable("Invalid visit mode!");
+ }
+};
+} // end anonymous namespace
+
+
void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
ID.AddPointer(&tag);
@@ -110,59 +354,90 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
ID.Add(V);
}
-PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
if (satisfied)
return NULL;
- if (!StoreSite) {
- // Make sure the region is actually bound to value V here.
- // This is necessary because the region may not actually be live at the
- // report's error node.
- if (N->getState()->getSVal(R) != V)
- return NULL;
-
- const ExplodedNode *Node = N, *Last = N;
-
- // Now look for the store of V.
- for ( ; Node ; Node = Node->getFirstPred()) {
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- if (const PostStmt *P = Node->getLocationAs<PostStmt>())
- if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
- if (DS->getSingleDecl() == VR->getDecl()) {
- // Record the last seen initialization point.
- Last = Node;
- break;
- }
+ const ExplodedNode *StoreSite = 0;
+ const Expr *InitE = 0;
+ bool IsParam = false;
+
+ // 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 (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) {
+ if (DS->getSingleDecl() == VR->getDecl()) {
+ StoreSite = Pred;
+ InitE = VR->getDecl()->getInit();
+ }
}
-
- // Does the region still bind to value V? If not, we are done
- // looking for store sites.
- if (Node->getState()->getSVal(R) != V)
- break;
-
- Last = Node;
}
+ }
- if (!Node) {
- satisfied = true;
+ // Otherwise, check that Succ has this binding and Pred does not, i.e. this is
+ // where the binding first occurred.
+ if (!StoreSite) {
+ if (Succ->getState()->getSVal(R) != V)
+ return NULL;
+ if (Pred->getState()->getSVal(R) == V)
return NULL;
- }
- StoreSite = Last;
+ StoreSite = Succ;
+
+ // If this is an assignment expression, we can track the value
+ // being assigned.
+ if (const PostStmt *P = Succ->getLocationAs<PostStmt>())
+ if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>())
+ if (BO->isAssignmentOp())
+ InitE = BO->getRHS();
+
+ // If this is a call entry, the variable should be a parameter.
+ // 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 (StoreSite != N)
+ if (!StoreSite)
return NULL;
-
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 (!IsParam)
+ InitE = InitE->IgnoreParenCasts();
+ bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam);
+ } else {
+ ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(),
+ BR);
+ }
+ }
+
+ if (!R->canPrintPretty())
+ return 0;
+
+ // Okay, we've found the binding. Emit an appropriate message.
SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
- if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
+ if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -201,6 +476,30 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
os << "initialized here";
}
}
+ } else if (isa<CallEnter>(StoreSite->getLocation())) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(cast<VarRegion>(R)->getDecl());
+
+ 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";
+ }
+
+ // 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 << '\'';
}
if (os.str().empty()) {
@@ -228,17 +527,19 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
else
os << "Value assigned to ";
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << '\'' << *VR->getDecl() << '\'';
- }
- else
- return NULL;
+ os << '\'';
+ R->printPretty(os);
+ os << '\'';
}
// Construct a new PathDiagnosticPiece.
- ProgramPoint P = N->getLocation();
- PathDiagnosticLocation L =
- PathDiagnosticLocation::create(P, BRC.getSourceManager());
+ ProgramPoint P = StoreSite->getLocation();
+ PathDiagnosticLocation L;
+ if (isa<CallEnter>(P))
+ L = PathDiagnosticLocation(InitE, BRC.getSourceManager(),
+ P.getLocationContext());
+ else
+ L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
if (!L.isValid())
return NULL;
return new PathDiagnosticEventPiece(L, os.str());
@@ -251,6 +552,12 @@ void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
ID.Add(Constraint);
}
+/// Return the tag associated with this visitor. This tag will be used
+/// to make all PathDiagnosticPieces created by this visitor.
+const char *TrackConstraintBRVisitor::getTag() {
+ return "TrackConstraintBRVisitor";
+}
+
PathDiagnosticPiece *
TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
@@ -290,62 +597,97 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
PathDiagnosticLocation::create(P, BRC.getSourceManager());
if (!L.isValid())
return NULL;
- return new PathDiagnosticEventPiece(L, os.str());
+
+ PathDiagnosticEventPiece *X = new PathDiagnosticEventPiece(L, os.str());
+ X->setTag(getTag());
+ return X;
}
return NULL;
}
-void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N,
- const Stmt *S,
- BugReport *report) {
+bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
+ BugReport &report, bool IsArg) {
if (!S || !N)
- return;
+ return false;
- ProgramStateManager &StateMgr = N->getState()->getStateManager();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
+ S = OVE->getSourceExpr();
+
+ if (IsArg) {
+ assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
+ } else {
+ // Walk through nodes until we get one that matches the statement exactly.
+ do {
+ const ProgramPoint &pp = N->getLocation();
+ if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
+ if (ps->getStmt() == S)
+ break;
+ } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
+ if (CEE->getCalleeContext()->getCallSite() == S)
+ break;
+ }
+ N = N->getFirstPred();
+ } while (N);
- // Walk through nodes until we get one that matches the statement
- // exactly.
- while (N) {
- const ProgramPoint &pp = N->getLocation();
- if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
- if (ps->getStmt() == S)
- break;
- }
- N = N->getFirstPred();
+ if (!N)
+ return false;
}
-
- if (!N)
- return;
ProgramStateRef state = N->getState();
- // Walk through lvalue-to-rvalue conversions.
- const Expr *Ex = dyn_cast<Expr>(S);
- if (Ex) {
+ // 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())) {
- const VarRegion *R =
- StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
+ ProgramStateManager &StateMgr = state->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());
- // What did we load?
+ // Mark both the variable region and its contents as interesting.
SVal V = state->getRawSVal(loc::MemRegionVal(R));
- report->markInteresting(R);
- report->markInteresting(V);
+ // 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));
+
+ // If the contents are symbolic, find out when they became null.
if (V.getAsLocSymbol()) {
BugReporterVisitor *ConstraintTracker
- = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false);
- report->addVisitor(ConstraintTracker);
+ = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false);
+ report.addVisitor(ConstraintTracker);
}
- report->addVisitor(new FindLastStoreBRVisitor(V, R));
- return;
+ report.addVisitor(new FindLastStoreBRVisitor(V, R));
+ return true;
}
}
}
+ // If the expression does NOT refer to a variable, we can still track
+ // constraints on its contents.
SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
// Uncomment this to find cases where we aren't properly getting the
@@ -354,17 +696,27 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N,
// Is it a symbolic value?
if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
- const SubRegion *R = cast<SubRegion>(L->getRegion());
- while (R && !isa<SymbolicRegion>(R)) {
- R = dyn_cast<SubRegion>(R->getSuperRegion());
- }
+ // 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 (R) {
- report->markInteresting(R);
- report->addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(R),
- false));
+ 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 *
@@ -406,7 +758,7 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
// 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::addTrackNullOrUndefValueVisitor(N, Receiver, &BR);
+ bugreporter::trackNullOrUndefValue(N, Receiver, BR);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
@@ -452,14 +804,23 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
//===----------------------------------------------------------------------===//
// Visitor that tries to report interesting diagnostics from conditions.
//===----------------------------------------------------------------------===//
+
+/// Return the tag associated with this visitor. This tag will be used
+/// to make all PathDiagnosticPieces created by this visitor.
+const char *ConditionBRVisitor::getTag() {
+ return "ConditionBRVisitor";
+}
+
PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *Prev,
BugReporterContext &BRC,
BugReport &BR) {
PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR);
- if (PathDiagnosticEventPiece *ev =
- dyn_cast_or_null<PathDiagnosticEventPiece>(piece))
- ev->setPrunable(true, /* override */ false);
+ if (piece) {
+ piece->setTag(getTag());
+ if (PathDiagnosticEventPiece *ev=dyn_cast<PathDiagnosticEventPiece>(piece))
+ ev->setPrunable(true, /* override */ false);
+ }
return piece;
}
@@ -468,8 +829,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) {
- const ProgramPoint &progPoint = N->getLocation();
-
+ ProgramPoint progPoint = N->getLocation();
ProgramStateRef CurrentState = N->getState();
ProgramStateRef PrevState = Prev->getState();
@@ -494,7 +854,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// violation.
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
cast<GRBugReporter>(BRC.getBugReporter()).
- getEngine().getEagerlyAssumeTags();
+ getEngine().geteagerlyAssumeBinOpBifurcationTags();
const ProgramPointTag *tag = PS->getTag();
if (tag == tags.first)
@@ -533,8 +893,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
assert(Cond);
assert(srcBlk->succ_size() == 2);
const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
- return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
- tookTrue, BRC, R, N);
+ return VisitTrueTest(Cond, tookTrue, BRC, R, N);
}
PathDiagnosticPiece *
@@ -547,7 +906,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const Expr *Ex = Cond;
while (true) {
- Ex = Ex->IgnoreParens();
+ Ex = Ex->IgnoreParenCasts();
switch (Ex->getStmtClass()) {
default:
return 0;
@@ -561,7 +920,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const UnaryOperator *UO = cast<UnaryOperator>(Ex);
if (UO->getOpcode() == UO_LNot) {
tookTrue = !tookTrue;
- Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext());
+ Ex = UO->getSubExpr();
continue;
}
return 0;
@@ -802,3 +1161,54 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
return event;
}
+PathDiagnosticPiece *
+UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+
+ ProgramStateRef State = N->getState();
+ ProgramPoint ProgLoc = N->getLocation();
+
+ // We are only interested in visiting CallEnter nodes.
+ CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc);
+ if (!CEnter)
+ return 0;
+
+ // Check if one of the arguments is the region the visitor is tracking.
+ CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
+ CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
+ unsigned Idx = 0;
+ for (CallEvent::param_iterator I = Call->param_begin(),
+ E = Call->param_end(); I != E; ++I, ++Idx) {
+ const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
+
+ // Are we tracking the argument or its subregion?
+ if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts())))
+ continue;
+
+ // Check the function parameter type.
+ const ParmVarDecl *ParamDecl = *I;
+ assert(ParamDecl && "Formal parameter has no decl?");
+ QualType T = ParamDecl->getType();
+
+ if (!(T->isAnyPointerType() || T->isReferenceType())) {
+ // Function can only change the value passed in by address.
+ continue;
+ }
+
+ // If it is a const pointer value, the function does not intend to
+ // change the value.
+ if (T->getPointeeType().isConstQualified())
+ continue;
+
+ // Mark the call site (LocationContext) as interesting if the value of the
+ // argument is undefined or '0'/'NULL'.
+ SVal BoundVal = State->getSVal(R);
+ if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
+ BR.markInteresting(CEnter->getCalleeContext());
+ return 0;
+ }
+ }
+ return 0;
+}
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index b16b233d6346..91f15b31da63 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -1,9 +1,9 @@
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangStaticAnalyzerCore
- AnalysisManager.cpp
APSIntType.cpp
- BasicConstraintManager.cpp
+ AnalysisManager.cpp
+ AnalyzerOptions.cpp
BasicValueFactory.cpp
BlockCounter.cpp
BugReporter.cpp
@@ -14,6 +14,7 @@ add_clang_library(clangStaticAnalyzerCore
CheckerHelpers.cpp
CheckerManager.cpp
CheckerRegistry.cpp
+ ConstraintManager.cpp
CoreEngine.cpp
Environment.cpp
ExplodedGraph.cpp
@@ -54,5 +55,5 @@ target_link_libraries(clangStaticAnalyzerCore
clangLex
clangAST
clangFrontend
- clangRewrite
+ clangRewriteCore
)
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 5345bd517045..c5cb317bd18d 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#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 "llvm/ADT/SmallSet.h"
@@ -23,10 +24,26 @@ using namespace clang;
using namespace ento;
QualType CallEvent::getResultType() const {
- QualType ResultTy = getDeclaredResultType();
+ const Expr *E = getOriginExpr();
+ assert(E && "Calls without origin expressions do not have results");
+ QualType ResultTy = E->getType();
- if (ResultTy.isNull())
- ResultTy = getOriginExpr()->getType();
+ ASTContext &Ctx = getState()->getStateManager().getContext();
+
+ // A function that returns a reference to 'int' will have a result type
+ // of simply 'int'. Check the origin expr's value kind to recover the
+ // proper type.
+ switch (E->getValueKind()) {
+ case VK_LValue:
+ ResultTy = Ctx.getLValueReferenceType(ResultTy);
+ break;
+ case VK_XValue:
+ ResultTy = Ctx.getRValueReferenceType(ResultTy);
+ break;
+ case VK_RValue:
+ // No adjustment is necessary.
+ break;
+ }
return ResultTy;
}
@@ -45,7 +62,7 @@ static bool isCallbackArg(SVal V, QualType T) {
// Check if a callback is passed inside a struct (for both, struct passed by
// reference and by value). Dig just one level into the struct for now.
- if (isa<PointerType>(T) || isa<ReferenceType>(T))
+ if (T->isAnyPointerType() || T->isReferenceType())
T = T->getPointeeType();
if (const RecordType *RT = T->getAsStructureType()) {
@@ -83,6 +100,14 @@ bool CallEvent::hasNonZeroCallbackArg() const {
return false;
}
+bool CallEvent::isGlobalCFunction(StringRef FunctionName) const {
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
+ if (!FD)
+ return false;
+
+ return CheckerContext::isCLibraryFunction(FD, FunctionName);
+}
+
/// \brief Returns true if a type is a pointer-to-const or reference-to-const
/// with no further indirection.
static bool isPointerToConst(QualType Ty) {
@@ -207,6 +232,13 @@ SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
return ArgE->getSourceRange();
}
+SVal CallEvent::getReturnValue() const {
+ const Expr *E = getOriginExpr();
+ if (!E)
+ return UndefinedVal();
+ return getSVal(E);
+}
+
void CallEvent::dump() const {
dump(llvm::errs());
}
@@ -230,10 +262,20 @@ void CallEvent::dump(raw_ostream &Out) const {
}
-bool CallEvent::mayBeInlined(const Stmt *S) {
- // FIXME: Kill this.
+bool CallEvent::isCallStmt(const Stmt *S) {
return isa<CallExpr>(S) || isa<ObjCMessageExpr>(S)
- || isa<CXXConstructExpr>(S);
+ || isa<CXXConstructExpr>(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))
+ return FD->getResultType();
+ else if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getResultType();
+ return QualType();
}
static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
@@ -285,14 +327,6 @@ void AnyFunctionCall::getInitialStackFrameContents(
D->param_begin(), D->param_end());
}
-QualType AnyFunctionCall::getDeclaredResultType() const {
- const FunctionDecl *D = getDecl();
- if (!D)
- return QualType();
-
- return D->getResultType();
-}
-
bool AnyFunctionCall::argumentsMayEscape() const {
if (hasNonZeroCallbackArg())
return true;
@@ -303,7 +337,7 @@ bool AnyFunctionCall::argumentsMayEscape() const {
const IdentifierInfo *II = D->getIdentifier();
if (!II)
- return true;
+ return false;
// This set of "escaping" APIs is
@@ -376,6 +410,17 @@ void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const {
Regions.push_back(R);
}
+SVal CXXInstanceCall::getCXXThisVal() const {
+ const Expr *Base = getCXXThisExpr();
+ // FIXME: This doesn't handle an overloaded ->* operator.
+ if (!Base)
+ return UnknownVal();
+
+ SVal ThisVal = getSVal(Base);
+ assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
+ return ThisVal;
+}
+
RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// Do we have a decl at all?
@@ -400,13 +445,30 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// Is the type a C++ class? (This is mostly a defensive check.)
QualType RegionType = DynType.getType()->getPointeeType();
+ assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer.");
+
const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl();
if (!RD || !RD->hasDefinition())
return RuntimeDefinition();
// Find the decl for this method in that class.
const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true);
- assert(Result && "At the very least the static decl should show up.");
+ if (!Result) {
+ // We might not even get the original statically-resolved method due to
+ // some particularly nasty casting (e.g. casts to sister classes).
+ // However, we should at least be able to search up and down our own class
+ // hierarchy, and some real bugs have been caught by checking this.
+ assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method");
+
+ // FIXME: This is checking that our DynamicTypeInfo is at least as good as
+ // the static type. However, because we currently don't update
+ // DynamicTypeInfo when an object is cast, we can't actually be sure the
+ // DynamicTypeInfo is up to date. This assert should be re-enabled once
+ // this is fixed. <rdar://problem/12287087>
+ //assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo");
+
+ return RuntimeDefinition();
+ }
// Does the decl that we found have an implementation?
const FunctionDecl *Definition;
@@ -459,6 +521,18 @@ const Expr *CXXMemberCall::getCXXThisExpr() const {
return getOriginExpr()->getImplicitObjectArgument();
}
+RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const {
+ // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the
+ // id-expression in the class member access expression is a qualified-id,
+ // that function is called. Otherwise, its final overrider in the dynamic type
+ // of the object expression is called.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee()))
+ if (ME->hasQualifier())
+ return AnyFunctionCall::getRuntimeDefinition();
+
+ return CXXInstanceCall::getRuntimeDefinition();
+}
+
const Expr *CXXMemberOperatorCall::getCXXThisExpr() const {
return getOriginExpr()->getArg(0);
@@ -501,15 +575,6 @@ void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
}
-QualType BlockCall::getDeclaredResultType() const {
- const BlockDataRegion *BR = getBlockRegion();
- if (!BR)
- return QualType();
- QualType BlockTy = BR->getCodeRegion()->getLocationType();
- return cast<FunctionType>(BlockTy->getPointeeType())->getResultType();
-}
-
-
SVal CXXConstructorCall::getCXXThisVal() const {
if (Data)
return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
@@ -539,10 +604,19 @@ void CXXConstructorCall::getInitialStackFrameContents(
SVal CXXDestructorCall::getCXXThisVal() const {
if (Data)
- return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
+ return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer());
return UnknownVal();
}
+RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
+ // Base destructors are always called non-virtually.
+ // Skip CXXInstanceCall's devirtualization logic in this case.
+ if (isBaseDestructor())
+ return AnyFunctionCall::getRuntimeDefinition();
+
+ return CXXInstanceCall::getRuntimeDefinition();
+}
+
CallEvent::param_iterator ObjCMethodCall::param_begin() const {
const ObjCMethodDecl *D = getDecl();
@@ -566,12 +640,12 @@ ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const {
Regions.push_back(R);
}
-QualType ObjCMethodCall::getDeclaredResultType() const {
- const ObjCMethodDecl *D = getDecl();
- if (!D)
- return QualType();
-
- return D->getResultType();
+SVal ObjCMethodCall::getSelfSVal() const {
+ const LocationContext *LCtx = getLocationContext();
+ const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
+ if (!SelfDecl)
+ return SVal();
+ return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx));
}
SVal ObjCMethodCall::getReceiverSVal() const {
@@ -584,10 +658,23 @@ SVal ObjCMethodCall::getReceiverSVal() const {
// An instance message with no expression means we are sending to super.
// In this case the object reference is the same as 'self'.
- const LocationContext *LCtx = getLocationContext();
- const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
- assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
- return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx));
+ assert(getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance);
+ SVal SelfVal = getSelfSVal();
+ assert(SelfVal.isValid() && "Calling super but not in ObjC method");
+ return SelfVal;
+}
+
+bool ObjCMethodCall::isReceiverSelfOrSuper() const {
+ if (getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance ||
+ getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperClass)
+ return true;
+
+ if (!isInstanceMessage())
+ return false;
+
+ SVal RecVal = getSVal(getOriginExpr()->getInstanceReceiver());
+
+ return (RecVal == getSelfSVal());
}
SourceRange ObjCMethodCall::getSourceRange() const {
@@ -820,7 +907,8 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
return getSimpleCall(CE, State, CallerCtx);
switch (CallSite->getStmtClass()) {
- case Stmt::CXXConstructExprClass: {
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXTemporaryObjectExprClass: {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl());
Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx);
@@ -858,5 +946,5 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
Trigger = Dtor->getBody();
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
- State, CallerCtx);
+ isa<CFGBaseDtor>(E), State, CallerCtx);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 0a047d922aa9..74eeef1c67a8 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -38,17 +38,14 @@ StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const {
bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
StringRef Name) {
- return isCLibraryFunction(FD, Name, getASTContext());
-}
-
-bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
- StringRef Name, ASTContext &Context) {
// To avoid false positives (Ex: finding user defined functions with
// similar names), only perform fuzzy name matching when it's a builtin.
// Using a string compare is slow, we might want to switch on BuiltinID here.
unsigned BId = FD->getBuiltinID();
if (BId != 0) {
- StringRef BName = Context.BuiltinInfo.GetName(BId);
+ if (Name.empty())
+ return true;
+ StringRef BName = FD->getASTContext().BuiltinInfo.GetName(BId);
if (BName.find(Name) != StringRef::npos)
return true;
}
@@ -59,6 +56,24 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
if (!II)
return false;
+ // Look through 'extern "C"' and anything similar invented in the future.
+ const DeclContext *DC = FD->getDeclContext();
+ while (DC->isTransparentContext())
+ DC = DC->getParent();
+
+ // If this function is in a namespace, it is not a C library function.
+ if (!DC->isTranslationUnit())
+ return false;
+
+ // If this function is not externally visible, it is not a C library function.
+ // Note that we make an exception for inline functions, which may be
+ // declared in header files without external linkage.
+ if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage)
+ return false;
+
+ if (Name.empty())
+ return true;
+
StringRef FName = II->getName();
if (FName.equals(Name))
return true;
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index c7866559c6d7..3672952b8f6e 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -36,8 +36,7 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
!DeadSymbolsCheckers.empty() ||
!RegionChangesCheckers.empty() ||
!EvalAssumeCheckers.empty() ||
- !EvalCallCheckers.empty() ||
- !InlineCallCheckers.empty();
+ !EvalCallCheckers.empty();
}
void CheckerManager::finishedCheckerRegistration() {
@@ -314,20 +313,19 @@ namespace {
SVal Val;
const Stmt *S;
ExprEngine &Eng;
- ProgramPoint::Kind PointKind;
+ const ProgramPoint &PP;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckBindContext(const CheckersTy &checkers,
SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
- ProgramPoint::Kind PK)
- : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {}
+ const ProgramPoint &pp)
+ : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {}
void runChecker(CheckerManager::CheckBindFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind,
- Pred->getLocationContext(), checkFn.Checker);
+ const ProgramPoint &L = PP.withTag(checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L);
checkFn(Loc, Val, S, C);
@@ -340,8 +338,8 @@ void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng,
- ProgramPoint::Kind PointKind) {
- CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind);
+ const ProgramPoint &PP) {
+ CheckBindContext C(BindCheckers, location, val, S, Eng, PP);
expandGraphWithCheckers(C, Dst, Src);
}
@@ -357,8 +355,8 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
// for this callback since end of path nodes are expected to be final.
void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
ExprEngine &Eng) {
- ExplodedNode *Pred = BC.Pred;
// 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
@@ -509,41 +507,13 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
for (ExplodedNodeSet::iterator
NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
-
ExplodedNode *Pred = *NI;
bool anyEvaluated = false;
- // First, check if any of the InlineCall callbacks can evaluate the call.
- assert(InlineCallCheckers.size() <= 1 &&
- "InlineCall is a special hacky callback to allow intrusive"
- "evaluation of the call (which simulates inlining). It is "
- "currently only used by OSAtomicChecker and should go away "
- "at some point.");
- for (std::vector<InlineCallFunc>::iterator
- EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
- EI != EE; ++EI) {
- ExplodedNodeSet checkDst;
- bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
- assert(!(evaluated && anyEvaluated)
- && "There are more than one checkers evaluating the call");
- if (evaluated) {
- anyEvaluated = true;
- Dst.insert(checkDst);
-#ifdef NDEBUG
- break; // on release don't check that no other checker also evals.
-#endif
- }
- }
-
-#ifdef NDEBUG // on release don't check that no other checker also evals.
- if (anyEvaluated) {
- break;
- }
-#endif
-
ExplodedNodeSet checkDst;
NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
- // Next, check if any of the EvalCall callbacks can evaluate the call.
+
+ // Check if any of the EvalCall callbacks can evaluate the call.
for (std::vector<EvalCallFunc>::iterator
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
EI != EE; ++EI) {
@@ -679,10 +649,6 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}
-void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
- InlineCallCheckers.push_back(checkfn);
-}
-
void CheckerManager::_registerForEndOfTranslationUnit(
CheckEndOfTranslationUnit checkfn) {
EndOfTranslationUnitCheckers.push_back(checkfn);
diff --git a/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/lib/StaticAnalyzer/Core/ConstraintManager.cpp
new file mode 100644
index 000000000000..4dec52600518
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/ConstraintManager.cpp
@@ -0,0 +1,39 @@
+//== ConstraintManager.cpp - Constraints on symbolic values -----*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the interface to manage constraints on symbolic values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+using namespace clang;
+using namespace ento;
+
+ConstraintManager::~ConstraintManager() {}
+
+static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
+ SymbolRef Sym) {
+ const MemRegion *R = State->getStateManager().getRegionManager()
+ .getSymbolicRegion(Sym);
+ return loc::MemRegionVal(R);
+}
+
+ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State,
+ SymbolRef Sym) {
+ QualType Ty = Sym->getType();
+ DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym)
+ : nonloc::SymbolVal(Sym);
+ const ProgramStatePair &P = assumeDual(State, V);
+ if (P.first && !P.second)
+ return ConditionTruthVal(false);
+ if (!P.first && P.second)
+ return ConditionTruthVal(true);
+ return ConditionTruthVal();
+}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 1f137424d450..ec2379212dc6 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -243,11 +243,6 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
case ProgramPoint::CallEnterKind: {
CallEnter CEnter = cast<CallEnter>(Loc);
- if (AnalyzedCallees)
- if (const CallExpr* CE =
- dyn_cast_or_null<CallExpr>(CEnter.getCallExpr()))
- if (const Decl *CD = CE->getCalleeDecl())
- AnalyzedCallees->insert(CD);
SubEng.processCallEnter(CEnter, Pred);
break;
}
@@ -303,7 +298,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
&& "EXIT block cannot contain Stmts.");
// Process the final state transition.
- SubEng.processEndOfFunction(BuilderCtx);
+ SubEng.processEndOfFunction(BuilderCtx, Pred);
// This path is done. Don't enqueue any more nodes.
return;
@@ -313,7 +308,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
ExplodedNodeSet dstNodes;
BlockEntrance BE(Blk, Pred->getLocationContext());
NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
- SubEng.processCFGBlockEntrance(L, nodeBuilder);
+ SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
// Auto-generate a node.
if (!nodeBuilder.hasGeneratedNodes()) {
@@ -519,9 +514,9 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
return;
}
- const CFGStmt *CS = (*Block)[Idx].getAs<CFGStmt>();
- const Stmt *St = CS ? CS->getStmt() : 0;
- PostStmt Loc(St, N->getLocationContext());
+ // At this point, we know we're processing a normal statement.
+ CFGStmt CS = cast<CFGStmt>((*Block)[Idx]);
+ PostStmt Loc(CS.getStmt(), N->getLocationContext());
if (Loc == N->getLocation()) {
// Note: 'N' should be a fresh node because otherwise it shouldn't be
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 52644f7702fc..bab89c545c34 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -20,6 +20,44 @@
using namespace clang;
using namespace ento;
+static const Expr *ignoreTransparentExprs(const Expr *E) {
+ E = E->IgnoreParens();
+
+ switch (E->getStmtClass()) {
+ case Stmt::OpaqueValueExprClass:
+ E = cast<OpaqueValueExpr>(E)->getSourceExpr();
+ break;
+ case Stmt::ExprWithCleanupsClass:
+ E = cast<ExprWithCleanups>(E)->getSubExpr();
+ break;
+ case Stmt::CXXBindTemporaryExprClass:
+ E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
+ break;
+ 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;
+ }
+
+ return ignoreTransparentExprs(E);
+}
+
+static const Stmt *ignoreTransparentExprs(const Stmt *S) {
+ if (const Expr *E = dyn_cast<Expr>(S))
+ return ignoreTransparentExprs(E);
+ return S;
+}
+
+EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L)
+ : std::pair<const Stmt *,
+ const StackFrameContext *>(ignoreTransparentExprs(S),
+ L ? L->getCurrentStackFrame() : 0) {}
+
SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
const SVal* X = ExprBindings.lookup(E);
if (X) {
@@ -30,101 +68,72 @@ SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
}
SVal Environment::getSVal(const EnvironmentEntry &Entry,
- SValBuilder& svalBuilder,
- bool useOnlyDirectBindings) const {
-
- if (useOnlyDirectBindings) {
- // This branch is rarely taken, but can be exercised by
- // checkers that explicitly bind values to arbitrary
- // expressions. It is crucial that we do not ignore any
- // expression here, and do a direct lookup.
- return lookupExpr(Entry);
+ SValBuilder& svalBuilder) const {
+ const Stmt *S = Entry.getStmt();
+ const LocationContext *LCtx = Entry.getLocationContext();
+
+ switch (S->getStmtClass()) {
+ case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::ExprWithCleanupsClass:
+ case Stmt::GenericSelectionExprClass:
+ case Stmt::OpaqueValueExprClass:
+ case Stmt::ParenExprClass:
+ case Stmt::SubstNonTypeTemplateParmExprClass:
+ llvm_unreachable("Should have been handled by ignoreTransparentExprs");
+
+ case Stmt::AddrLabelExprClass:
+ return svalBuilder.makeLoc(cast<AddrLabelExpr>(S));
+
+ case Stmt::CharacterLiteralClass: {
+ const CharacterLiteral *C = cast<CharacterLiteral>(S);
+ return svalBuilder.makeIntVal(C->getValue(), C->getType());
}
- const Stmt *E = Entry.getStmt();
- const LocationContext *LCtx = Entry.getLocationContext();
-
- for (;;) {
- if (const Expr *Ex = dyn_cast<Expr>(E))
- E = Ex->IgnoreParens();
-
- switch (E->getStmtClass()) {
- case Stmt::AddrLabelExprClass:
- return svalBuilder.makeLoc(cast<AddrLabelExpr>(E));
- case Stmt::OpaqueValueExprClass: {
- const OpaqueValueExpr *ope = cast<OpaqueValueExpr>(E);
- E = ope->getSourceExpr();
- continue;
- }
- case Stmt::ParenExprClass:
- case Stmt::GenericSelectionExprClass:
- llvm_unreachable("ParenExprs and GenericSelectionExprs should "
- "have been handled by IgnoreParens()");
- case Stmt::CharacterLiteralClass: {
- const CharacterLiteral* C = cast<CharacterLiteral>(E);
- return svalBuilder.makeIntVal(C->getValue(), C->getType());
- }
- case Stmt::CXXBoolLiteralExprClass: {
- const SVal *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
- if (X)
- return *X;
- else
- return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(E));
- }
- case Stmt::CXXScalarValueInitExprClass:
- case Stmt::ImplicitValueInitExprClass: {
- QualType Ty = cast<Expr>(E)->getType();
- return svalBuilder.makeZeroVal(Ty);
- }
- case Stmt::IntegerLiteralClass: {
- // In C++, this expression may have been bound to a temporary object.
- SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
- if (X)
- return *X;
- else
- return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
- }
- case Stmt::ObjCBoolLiteralExprClass:
- return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(E));
-
- // For special C0xx nullptr case, make a null pointer SVal.
- case Stmt::CXXNullPtrLiteralExprClass:
- return svalBuilder.makeNull();
- case Stmt::ExprWithCleanupsClass:
- E = cast<ExprWithCleanups>(E)->getSubExpr();
- continue;
- case Stmt::CXXBindTemporaryExprClass:
- E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
- continue;
- case Stmt::SubstNonTypeTemplateParmExprClass:
- E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
- continue;
- case Stmt::ObjCStringLiteralClass: {
- MemRegionManager &MRMgr = svalBuilder.getRegionManager();
- const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E);
- return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL));
- }
- case Stmt::StringLiteralClass: {
- MemRegionManager &MRMgr = svalBuilder.getRegionManager();
- const StringLiteral *SL = cast<StringLiteral>(E);
- return svalBuilder.makeLoc(MRMgr.getStringRegion(SL));
- }
- case Stmt::ReturnStmtClass: {
- const ReturnStmt *RS = cast<ReturnStmt>(E);
- if (const Expr *RE = RS->getRetValue()) {
- E = RE;
- continue;
- }
- return UndefinedVal();
- }
-
- // Handle all other Stmt* using a lookup.
- default:
- break;
- };
+ case Stmt::CXXBoolLiteralExprClass:
+ return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S));
+
+ case Stmt::CXXScalarValueInitExprClass:
+ case Stmt::ImplicitValueInitExprClass: {
+ QualType Ty = cast<Expr>(S)->getType();
+ return svalBuilder.makeZeroVal(Ty);
+ }
+
+ case Stmt::IntegerLiteralClass:
+ return svalBuilder.makeIntVal(cast<IntegerLiteral>(S));
+
+ case Stmt::ObjCBoolLiteralExprClass:
+ return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S));
+
+ // For special C0xx nullptr case, make a null pointer SVal.
+ case Stmt::CXXNullPtrLiteralExprClass:
+ return svalBuilder.makeNull();
+
+ case Stmt::ObjCStringLiteralClass: {
+ MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+ const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S);
+ return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL));
+ }
+
+ case Stmt::StringLiteralClass: {
+ MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+ const StringLiteral *SL = cast<StringLiteral>(S);
+ return svalBuilder.makeLoc(MRMgr.getStringRegion(SL));
+ }
+
+ case Stmt::ReturnStmtClass: {
+ const ReturnStmt *RS = cast<ReturnStmt>(S);
+ if (const Expr *RE = RS->getRetValue())
+ return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
+ return UndefinedVal();
+ }
+
+ // Handle all other Stmt* using a lookup.
+ default:
break;
}
- return lookupExpr(EnvironmentEntry(E, LCtx));
+
+ return lookupExpr(EnvironmentEntry(S, LCtx));
}
Environment EnvironmentManager::bindExpr(Environment Env,
@@ -140,16 +149,16 @@ Environment EnvironmentManager::bindExpr(Environment Env,
return Environment(F.add(Env.ExprBindings, E, V));
}
-static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) {
- const Stmt *S = E.getStmt();
- S = (const Stmt*) (((uintptr_t) S) | 0x1);
- return EnvironmentEntry(S, E.getLocationContext());
+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, MakeLocation(E), location),
+ return Environment(F.add(F.add(Env.ExprBindings, E.makeLocation(), location),
E, V));
}
@@ -286,7 +295,8 @@ void Environment::printAux(raw_ostream &Out, bool printLocations,
S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1));
}
- Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") ";
+ Out << " (" << (const void*) En.getLocationContext() << ','
+ << (const void*) S << ") ";
LangOptions LO; // FIXME.
S->printPretty(Out, 0, PrintingPolicy(LO));
Out << " : " << I.getData();
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index b79f3f5d1eaa..c284bd7dfad4 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -47,10 +47,8 @@ void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
// Cleanup.
//===----------------------------------------------------------------------===//
-static const unsigned CounterTop = 1000;
-
ExplodedGraph::ExplodedGraph()
- : NumNodes(0), reclaimNodes(false), reclaimCounter(CounterTop) {}
+ : NumNodes(0), ReclaimNodeInterval(0) {}
ExplodedGraph::~ExplodedGraph() {}
@@ -63,12 +61,12 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
//
// (1) 1 predecessor (that has one successor)
// (2) 1 successor (that has one predecessor)
- // (3) The ProgramPoint is for a PostStmt.
+ // (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 is for a non-consumed Stmt or Expr.
+ // (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).
// FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
@@ -87,16 +85,13 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Condition 3.
ProgramPoint progPoint = node->getLocation();
- if (!isa<PostStmt>(progPoint))
+ if (!isa<PostStmt>(progPoint) || isa<PostStore>(progPoint))
return false;
// Condition 4.
PostStmt ps = cast<PostStmt>(progPoint);
if (ps.getTag())
return false;
-
- if (isa<BinaryOperator>(ps.getStmt()))
- return false;
// Conditions 5, 6, and 7.
ProgramStateRef state = node->getState();
@@ -106,6 +101,12 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
return false;
// Condition 8.
+ // 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()))
+ return false;
+
if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) {
ParentMap &PM = progPoint.getLocationContext()->getParentMap();
if (!PM.isConsumedExpr(Ex))
@@ -115,7 +116,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Condition 9.
const ProgramPoint SuccLoc = succ->getLocation();
if (const StmtPoint *SP = dyn_cast<StmtPoint>(&SuccLoc))
- if (CallEvent::mayBeInlined(SP->getStmt()))
+ if (CallEvent::isCallStmt(SP->getStmt()))
return false;
return true;
@@ -141,13 +142,13 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
if (ChangedNodes.empty())
return;
- // Only periodically relcaim nodes so that we can build up a set of
+ // Only periodically reclaim nodes so that we can build up a set of
// nodes that meet the reclamation criteria. Freshly created nodes
// by definition have no successor, and thus cannot be reclaimed (see below).
- assert(reclaimCounter > 0);
- if (--reclaimCounter != 0)
+ assert(ReclaimCounter > 0);
+ if (--ReclaimCounter != 0)
return;
- reclaimCounter = CounterTop;
+ ReclaimCounter = ReclaimNodeInterval;
for (NodeVector::iterator it = ChangedNodes.begin(), et = ChangedNodes.end();
it != et; ++it) {
@@ -162,9 +163,18 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
// ExplodedNode.
//===----------------------------------------------------------------------===//
-static inline BumpVector<ExplodedNode*>& getVector(void *P) {
- return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P);
-}
+// An NodeGroup's storage type is actually very much like a TinyPtrVector:
+// it can be either a pointer to a single ExplodedNode, or a pointer to a
+// BumpVector allocated with the ExplodedGraph's allocator. This allows the
+// common case of single-node NodeGroups to be implemented with no extra memory.
+//
+// Consequently, each of the NodeGroup methods have up to four cases to handle:
+// 1. The flag is set and this group does not actually contain any nodes.
+// 2. The group is empty, in which case the storage value is null.
+// 3. The group contains a single node.
+// 4. The group contains more than one node.
+typedef BumpVector<ExplodedNode *> ExplodedNodeVector;
+typedef llvm::PointerUnion<ExplodedNode *, ExplodedNodeVector *> GroupStorage;
void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
assert (!V->isSink());
@@ -176,71 +186,77 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
}
void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
- assert(getKind() == Size1);
- P = reinterpret_cast<uintptr_t>(node);
- assert(getKind() == Size1);
+ assert(!getFlag());
+
+ GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
+ assert(Storage.is<ExplodedNode *>());
+ Storage = node;
+ assert(Storage.is<ExplodedNode *>());
}
void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) {
- assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
assert(!getFlag());
- if (getKind() == Size1) {
- if (ExplodedNode *NOld = getNode()) {
- BumpVectorContext &Ctx = G.getNodeAllocator();
- BumpVector<ExplodedNode*> *V =
- G.getAllocator().Allocate<BumpVector<ExplodedNode*> >();
- new (V) BumpVector<ExplodedNode*>(Ctx, 4);
-
- assert((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
- V->push_back(NOld, Ctx);
- V->push_back(N, Ctx);
- P = reinterpret_cast<uintptr_t>(V) | SizeOther;
- assert(getPtr() == (void*) V);
- assert(getKind() == SizeOther);
- }
- else {
- P = reinterpret_cast<uintptr_t>(N);
- assert(getKind() == Size1);
- }
+ GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
+ if (Storage.isNull()) {
+ Storage = N;
+ assert(Storage.is<ExplodedNode *>());
+ return;
}
- else {
- assert(getKind() == SizeOther);
- getVector(getPtr()).push_back(N, G.getNodeAllocator());
+
+ ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>();
+
+ if (!V) {
+ // Switch from single-node to multi-node representation.
+ ExplodedNode *Old = Storage.get<ExplodedNode *>();
+
+ BumpVectorContext &Ctx = G.getNodeAllocator();
+ V = G.getAllocator().Allocate<ExplodedNodeVector>();
+ new (V) ExplodedNodeVector(Ctx, 4);
+ V->push_back(Old, Ctx);
+
+ Storage = V;
+ assert(!getFlag());
+ assert(Storage.is<ExplodedNodeVector *>());
}
+
+ V->push_back(N, G.getNodeAllocator());
}
unsigned ExplodedNode::NodeGroup::size() const {
if (getFlag())
return 0;
- if (getKind() == Size1)
- return getNode() ? 1 : 0;
- else
- return getVector(getPtr()).size();
+ const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
+ if (Storage.isNull())
+ return 0;
+ if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
+ return V->size();
+ return 1;
}
-ExplodedNode **ExplodedNode::NodeGroup::begin() const {
+ExplodedNode * const *ExplodedNode::NodeGroup::begin() const {
if (getFlag())
- return NULL;
+ return 0;
- if (getKind() == Size1)
- return (ExplodedNode**) (getPtr() ? &P : NULL);
- else
- return const_cast<ExplodedNode**>(&*(getVector(getPtr()).begin()));
+ const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
+ if (Storage.isNull())
+ return 0;
+ if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
+ return V->begin();
+ return Storage.getAddrOfPtr1();
}
-ExplodedNode** ExplodedNode::NodeGroup::end() const {
+ExplodedNode * const *ExplodedNode::NodeGroup::end() const {
if (getFlag())
- return NULL;
-
- if (getKind() == Size1)
- return (ExplodedNode**) (getPtr() ? &P+1 : NULL);
- else {
- // Dereferencing end() is undefined behaviour. The vector is not empty, so
- // we can dereference the last elem and then add 1 to the result.
- return const_cast<ExplodedNode**>(getVector(getPtr()).end());
- }
+ return 0;
+
+ const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
+ if (Storage.isNull())
+ return 0;
+ if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
+ return V->end();
+ return Storage.getAddrOfPtr1() + 1;
}
ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
@@ -266,7 +282,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
new (V) NodeTy(L, State, IsSink);
- if (reclaimNodes)
+ if (ReclaimNodeInterval)
ChangedNodes.push_back(V);
// Insert the node into the node set and return it.
@@ -314,8 +330,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// ===- Pass 1 (reverse DFS) -===
for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
- assert(*I);
- WL1.push_back(*I);
+ if (*I)
+ WL1.push_back(*I);
}
// Process the first worklist until it is empty. Because it is a std::list
@@ -338,7 +354,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
}
// Visit our predecessors and enqueue them.
- for (ExplodedNode** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I)
+ for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
+ I != E; ++I)
WL1.push_back(*I);
}
@@ -375,7 +392,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// Walk through the predecessors of 'N' and hook up their corresponding
// nodes in the new graph (if any) to the freshly created node.
- for (ExplodedNode **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
+ for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
+ I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI == Pass2.end())
continue;
@@ -387,7 +405,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// been created, we should hook them up as successors. Otherwise, enqueue
// the new nodes from the original graph that should have nodes created
// in the new graph.
- for (ExplodedNode **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
+ for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end();
+ I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI != Pass2.end()) {
PI->second->addPredecessor(NewN, *G);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index b0435fb562e3..045591c9074b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -55,32 +55,32 @@ STATISTIC(NumTimesRetriedWithoutInlining,
//===----------------------------------------------------------------------===//
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCallees,
+ SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS)
: AMgr(mgr),
AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
- Engine(*this, VisitedCallees, FS),
+ Engine(*this, FS),
G(Engine.getGraph()),
StateMgr(getContext(), mgr.getStoreManagerCreator(),
mgr.getConstraintManagerCreator(), G.getAllocator(),
- *this),
+ this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
EntryNode(NULL),
- currentStmt(NULL), currentStmtIdx(0), currentBuilderContext(0),
- NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
- RaiseSel(GetNullarySelector("raise", getContext())),
- ObjCGCEnabled(gcEnabled), BR(mgr, *this) {
-
- if (mgr.shouldEagerlyTrimExplodedGraph()) {
- // Enable eager node reclaimation when constructing the ExplodedGraph.
- G.enableNodeReclamation();
+ currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
+ ObjCNoRet(mgr.getASTContext()),
+ ObjCGCEnabled(gcEnabled), BR(mgr, *this),
+ VisitedCallees(VisitedCalleesIn)
+{
+ unsigned TrimInterval = mgr.options.getGraphTrimInterval();
+ if (TrimInterval != 0) {
+ // Enable eager node reclaimation when constructing the ExplodedGraph.
+ G.enableNodeReclamation(TrimInterval);
}
}
ExprEngine::~ExprEngine() {
BR.FlushReports();
- delete [] NSExceptionInstanceRaiseSelectors;
}
//===----------------------------------------------------------------------===//
@@ -164,6 +164,23 @@ 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));
+ }
+
+ return State;
+}
+
//===----------------------------------------------------------------------===//
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
@@ -200,8 +217,8 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
unsigned StmtIdx, NodeBuilderContext *Ctx) {
- currentStmtIdx = StmtIdx;
- currentBuilderContext = Ctx;
+ currStmtIdx = StmtIdx;
+ currBldrCtx = Ctx;
switch (E.getKind()) {
case CFGElement::Invalid:
@@ -219,7 +236,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
return;
}
- currentBuilderContext = 0;
+ currBldrCtx = 0;
}
static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
@@ -228,7 +245,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
const LocationContext *LC) {
// Are we never purging state values?
- if (AMgr.getPurgeMode() == PurgeNone)
+ if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
return false;
// Is this the beginning of a basic block?
@@ -240,7 +257,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
return true;
// Run before processing a call.
- if (CallEvent::mayBeInlined(S.getStmt()))
+ if (CallEvent::isCallStmt(S.getStmt()))
return true;
// Is this an expression that is consumed by another expression? If so,
@@ -251,12 +268,12 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
const Stmt *ReferenceStmt,
- const LocationContext *LC,
+ const StackFrameContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K) {
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
- ReferenceStmt == 0) && "PreStmt is not generally supported by "
- "the SymbolReaper yet");
+ ReferenceStmt == 0)
+ && "PostStmt is not generally supported by the SymbolReaper yet");
NumRemoveDeadBindings++;
CleanedState = Pred->getState();
SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager());
@@ -276,8 +293,8 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// Generate a CleanedNode that has the environment and store cleaned
// up. Since no symbols are dead, we can optimize and not clean out
// the constraint manager.
- StmtNodeBuilder Bldr(Pred, Out, *currentBuilderContext);
- Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, false, &cleanupTag,K);
+ StmtNodeBuilder Bldr(Pred, Out, *currBldrCtx);
+ Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, &cleanupTag, K);
} else {
// Call checkers with the non-cleaned state so that they could query the
@@ -289,7 +306,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// For each node in CheckedSet, generate CleanedNodes that have the
// environment, the store, and the constraints cleaned up but have the
// user-supplied states as the predecessors.
- StmtNodeBuilder Bldr(CheckedSet, Out, *currentBuilderContext);
+ StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx);
for (ExplodedNodeSet::const_iterator
I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) {
ProgramStateRef CheckerState = (*I)->getState();
@@ -309,8 +326,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// generate a transition to that state.
ProgramStateRef CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
- Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, false,
- &cleanupTag, K);
+ Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, &cleanupTag, K);
}
}
}
@@ -320,17 +336,17 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
- currentStmt = S.getStmt();
+ currStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- currentStmt->getLocStart(),
+ currStmt->getLocStart(),
"Error evaluating statement");
// Remove dead bindings and symbols.
EntryNode = Pred;
ExplodedNodeSet CleanedStates;
if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){
- removeDead(EntryNode, CleanedStates, currentStmt,
- Pred->getLocationContext(), currentStmt);
+ removeDead(EntryNode, CleanedStates, currStmt,
+ Pred->getStackFrame(), currStmt);
} else
CleanedStates.Add(EntryNode);
@@ -340,44 +356,45 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
E = CleanedStates.end(); I != E; ++I) {
ExplodedNodeSet DstI;
// Visit the statement.
- Visit(currentStmt, *I, DstI);
+ Visit(currStmt, *I, DstI);
Dst.insert(DstI);
}
// Enqueue the new nodes onto the work list.
- Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
// NULL out these variables to cleanup.
CleanedState = NULL;
EntryNode = NULL;
- currentStmt = 0;
+ currStmt = 0;
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ExplodedNode *Pred) {
- ExplodedNodeSet Dst;
- NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
-
- ProgramStateRef State = Pred->getState();
-
const CXXCtorInitializer *BMI = Init.getInitializer();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
BMI->getSourceLocation(),
"Error evaluating initializer");
- // We don't set EntryNode and currentStmt. And we don't clean up state.
+ // We don't set EntryNode and currStmt. And we don't clean up state.
const StackFrameContext *stackFrame =
cast<StackFrameContext>(Pred->getLocationContext());
const CXXConstructorDecl *decl =
cast<CXXConstructorDecl>(stackFrame->getDecl());
+
+ ProgramStateRef State = Pred->getState();
SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
+ PostInitializer PP(BMI, stackFrame);
+ ExplodedNodeSet Tmp(Pred);
+
// 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.
- if (!isa<CXXConstructExpr>(BMI->getInit())) {
+ const Expr *Init = BMI->getInit();
+ if (!isa<CXXConstructExpr>(Init)) {
SVal FieldLoc;
if (BMI->isIndirectMemberInitializer())
FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
@@ -385,22 +402,26 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
FieldLoc = State->getLValue(BMI->getMember(), thisVal);
SVal InitVal = State->getSVal(BMI->getInit(), stackFrame);
- State = State->bindLoc(FieldLoc, InitVal);
+
+ Tmp.clear();
+ evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
}
} else {
assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
// We already did all the work when visiting the CXXConstructExpr.
}
- // Construct a PostInitializer node whether the state changed or not,
+ // Construct PostInitializer nodes whether the state changed or not,
// so that the diagnostics don't get confused.
- PostInitializer PP(BMI, stackFrame);
- // Builder automatically add the generated node to the deferred set,
- // which are processed in the builder's dtor.
- Bldr.generateNode(PP, State, Pred);
+ ExplodedNodeSet Dst;
+ NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ ExplodedNode *N = *I;
+ Bldr.generateNode(PP, N->getState(), N);
+ }
// Enqueue the new nodes onto the work list.
- Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
@@ -424,7 +445,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
}
// Enqueue the new nodes onto the work list.
- Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
@@ -441,7 +462,7 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(),
- Dtor.getTriggerStmt(), Pred, Dst);
+ Dtor.getTriggerStmt(), /*IsBase=*/false, Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
@@ -459,7 +480,7 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(),
- CurDtor->getBody(), Pred, Dst);
+ CurDtor->getBody(), /*IsBase=*/true, Pred, Dst);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
@@ -475,7 +496,7 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
VisitCXXDestructor(Member->getType(),
cast<loc::MemRegionVal>(FieldVal).getRegion(),
- CurDtor->getBody(), Pred, Dst);
+ CurDtor->getBody(), /*IsBase=*/false, Pred, Dst);
}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
@@ -488,7 +509,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
S->getLocStart(),
"Error evaluating statement");
ExplodedNodeSet Dst;
- StmtNodeBuilder Bldr(Pred, DstTop, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);
// Expressions to ignore.
if (const Expr *Ex = dyn_cast<Expr>(S))
@@ -498,7 +519,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// this check when we KNOW that there is no block-level subexpression.
// The motivation is that this check requires a hashtable lookup.
- if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
+ if (S != currStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
return;
switch (S->getStmtClass()) {
@@ -521,21 +542,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXNoexceptExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
+ case Stmt::FunctionParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::LambdaExprClass:
case Stmt::SEHFinallyStmtClass: {
- const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState(),
- /* sink */ true);
- Engine.addAbortedBlock(node, currentBuilderContext->getBlock());
+ const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
+ Engine.addAbortedBlock(node, currBldrCtx->getBlock());
break;
}
- // We don't handle default arguments either yet, but we can fake it
- // for now by just skipping them.
- case Stmt::CXXDefaultArgExprClass:
- break;
-
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
case Stmt::GenericSelectionExprClass:
@@ -607,11 +623,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::AtomicExprClass:
// Fall through.
- // Currently all handling of 'throw' just falls to the CFG. We
- // can consider doing more if necessary.
- case Stmt::CXXThrowExprClass:
- // Fall through.
-
// Cases we intentionally don't evaluate, since they don't need
// to be explicitly evaluated.
case Stmt::AddrLabelExprClass:
@@ -626,6 +637,7 @@ 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);
@@ -647,7 +659,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
ExplodedNodeSet Tmp;
- StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext);
+ StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);
const Expr *Ex = cast<Expr>(S);
QualType resultType = Ex->getType();
@@ -656,9 +668,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
it != et; ++it) {
ExplodedNode *N = *it;
const LocationContext *LCtx = N->getLocationContext();
- SVal result =
- svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType,
- currentBuilderContext->getCurrentBlockCount());
+ SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType,
+ currBldrCtx->blockCount());
ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
Bldr2.generateNode(S, N, state);
}
@@ -674,9 +685,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
- case Stmt::AsmStmtClass:
+ case Stmt::GCCAsmStmtClass:
Bldr.takeNodes(Pred);
- VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+ VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
@@ -711,11 +722,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.takeNodes(Pred);
- if (AMgr.shouldEagerlyAssume() &&
+ if (AMgr.options.eagerlyAssumeBinOpBifurcation &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
- evalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
+ evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
}
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
@@ -724,8 +735,26 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
+ case Stmt::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *OCE = cast<CXXOperatorCallExpr>(S);
+
+ // For instance method operators, make sure the 'this' argument has a
+ // valid region.
+ const Decl *Callee = OCE->getCalleeDecl();
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
+ if (MD->isInstance()) {
+ ProgramStateRef State = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef NewState =
+ createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
+ if (NewState != State)
+ Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0,
+ ProgramPoint::PreStmtKind);
+ }
+ }
+ // FALLTHROUGH
+ }
case Stmt::CallExprClass:
- case Stmt::CXXOperatorCallExprClass:
case Stmt::CXXMemberCallExprClass:
case Stmt::UserDefinedLiteralClass: {
Bldr.takeNodes(Pred);
@@ -846,12 +875,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Expr::MaterializeTemporaryExprClass: {
Bldr.takeNodes(Pred);
- const MaterializeTemporaryExpr *Materialize
- = cast<MaterializeTemporaryExpr>(S);
- if (Materialize->getType()->isRecordType())
- Dst.Add(Pred);
- else
- CreateCXXTemporaryObject(Materialize, Pred, Dst);
+ const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);
+ CreateCXXTemporaryObject(MTE, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
@@ -886,12 +911,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
- case Stmt::ObjCAtThrowStmtClass: {
+ case Stmt::ObjCAtThrowStmtClass:
+ case Stmt::CXXThrowExprClass:
// FIXME: This is not complete. We basically treat @throw as
// an abort.
- Bldr.generateNode(S, Pred, Pred->getState());
+ Bldr.generateSink(S, Pred, Pred->getState());
break;
- }
case Stmt::ReturnStmtClass:
Bldr.takeNodes(Pred);
@@ -935,10 +960,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::UnaryOperatorClass: {
Bldr.takeNodes(Pred);
const UnaryOperator *U = cast<UnaryOperator>(S);
- if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) {
+ if (AMgr.options.eagerlyAssumeBinOpBifurcation && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
- evalEagerlyAssume(Dst, Tmp, U);
+ evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
@@ -1030,19 +1055,18 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
/// Block entrance. (Update counters).
void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
- NodeBuilderWithSinks &nodeBuilder) {
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred) {
// FIXME: Refactor this into a checker.
- ExplodedNode *pred = nodeBuilder.getContext().getPred();
-
- if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) {
+ if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
const ExplodedNode *Sink =
- nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
+ nodeBuilder.generateSink(Pred->getState(), Pred, &tag);
// Check if we stopped at the top level function or not.
// Root node should have the location context of the top most function.
- const LocationContext *CalleeLC = pred->getLocation().getLocationContext();
+ const LocationContext *CalleeLC = Pred->getLocation().getLocationContext();
const LocationContext *CalleeSF = CalleeLC->getCurrentStackFrame();
const LocationContext *RootLC =
(*G.roots_begin())->getLocation().getLocationContext();
@@ -1053,7 +1077,8 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
// no-inlining policy in the state and enqueuing the new work item on
// the list. Replay should almost never fail. Use the stats to catch it
// if it does.
- if ((!AMgr.NoRetryExhausted && replayWithoutInlining(pred, CalleeLC)))
+ if ((!AMgr.options.NoRetryExhausted &&
+ replayWithoutInlining(Pred, CalleeLC)))
return;
NumMaxBlockCountReachedInInlined++;
} else
@@ -1155,7 +1180,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
- currentBuilderContext = &BldCtx;
+ currBldrCtx = &BldCtx;
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
@@ -1238,7 +1263,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
builder.markInfeasible(false);
}
}
- currentBuilderContext = 0;
+ currBldrCtx = 0;
}
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
@@ -1287,10 +1312,25 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
-void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) {
- StateMgr.EndPath(BC.Pred->getState());
+void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred) {
+ StateMgr.EndPath(Pred->getState());
+
ExplodedNodeSet Dst;
- getCheckerManager().runCheckersForEndPath(BC, Dst, *this);
+ if (Pred->getLocationContext()->inTopFrame()) {
+ // Remove dead symbols.
+ ExplodedNodeSet AfterRemovedDead;
+ removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead);
+
+ // Notify checkers.
+ for (ExplodedNodeSet::iterator I = AfterRemovedDead.begin(),
+ E = AfterRemovedDead.end(); I != E; ++I) {
+ getCheckerManager().runCheckersForEndPath(BC, Dst, *I, *this);
+ }
+ } else {
+ getCheckerManager().runCheckersForEndPath(BC, Dst, Pred, *this);
+ }
+
Engine.enqueueEndOfFunction(Dst);
}
@@ -1404,7 +1444,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
@@ -1422,7 +1462,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = UnknownVal();
}
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
@@ -1434,19 +1474,23 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
if (isa<FieldDecl>(D)) {
- // FIXME: Compute lvalue of fields.
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()),
- false, 0, ProgramPoint::PostLValueKind);
+ // FIXME: Compute lvalue of field pointers-to-member.
+ // Right now we just use a non-null void pointer, so that it gives proper
+ // results in boolean contexts.
+ SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
+ currBldrCtx->blockCount());
+ state = state->assume(cast<DefinedOrUnknownSVal>(V), true);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
+ ProgramPoint::PostLValueKind);
return;
}
- assert (false &&
- "ValueDecl support for this ValueDecl not implemented.");
+ llvm_unreachable("Support for this Decl not implemented.");
}
/// VisitArraySubscriptExpr - Transfer function for array accesses
@@ -1461,7 +1505,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
- StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
ei = checkerPreStmt.end(); it != ei; ++it) {
@@ -1471,8 +1515,8 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
state->getSVal(Idx, LCtx),
state->getSVal(Base, LCtx));
assert(A->isGLValue());
- Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V),
- false, 0, ProgramPoint::PostLValueKind);
+ Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0,
+ ProgramPoint::PostLValueKind);
}
}
@@ -1480,52 +1524,40 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
ExplodedNodeSet &TopDst) {
- StmtNodeBuilder Bldr(Pred, TopDst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx);
ExplodedNodeSet Dst;
- Decl *member = M->getMemberDecl();
+ ValueDecl *Member = M->getMemberDecl();
- if (VarDecl *VD = dyn_cast<VarDecl>(member)) {
- assert(M->isGLValue());
+ // Handle static member variables and enum constants accessed via
+ // member syntax.
+ if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) {
Bldr.takeNodes(Pred);
- VisitCommonDeclRefExpr(M, VD, Pred, Dst);
+ VisitCommonDeclRefExpr(M, Member, Pred, Dst);
Bldr.addNodes(Dst);
return;
}
- // Handle C++ method calls.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(member)) {
- Bldr.takeNodes(Pred);
- SVal MDVal = svalBuilder.getFunctionPointer(MD);
- ProgramStateRef state =
- Pred->getState()->BindExpr(M, Pred->getLocationContext(), MDVal);
- Bldr.generateNode(M, Pred, state);
- return;
- }
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ Expr *BaseExpr = M->getBase();
+ // Handle C++ method calls.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
+ if (MD->isInstance())
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
- FieldDecl *field = dyn_cast<FieldDecl>(member);
- if (!field) // FIXME: skipping member expressions for non-fields
- return;
+ SVal MDVal = svalBuilder.getFunctionPointer(MD);
+ state = state->BindExpr(M, LCtx, MDVal);
- Expr *baseExpr = M->getBase()->IgnoreParens();
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
- if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
- isa<nonloc::CompoundVal>(baseExprVal) ||
- // FIXME: This can originate by conjuring a symbol for an unknown
- // temporary struct object, see test/Analysis/fields.c:
- // (p = getit()).x
- isa<nonloc::SymbolVal>(baseExprVal)) {
- Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal()));
+ Bldr.generateNode(M, Pred, state);
return;
}
- // FIXME: Should we insert some assumption logic in here to determine
- // if "Base" is a valid piece of memory? Before we put this assumption
- // later when using FieldOffset lvals (which we no longer have).
+ // Handle regular struct fields / member variables.
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
+ SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
- // For all other cases, compute an lvalue.
+ FieldDecl *field = cast<FieldDecl>(Member);
SVal L = state->getLValue(field, baseExprVal);
if (M->isGLValue()) {
if (field->getType()->isReferenceType()) {
@@ -1535,7 +1567,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
L = UnknownVal();
}
- Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), false, 0,
+ Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0,
ProgramPoint::PostLValueKind);
} else {
Bldr.takeNodes(Pred);
@@ -1548,40 +1580,48 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit) {
+ SVal location, SVal Val,
+ bool atDeclInit, const ProgramPoint *PP) {
+
+ const LocationContext *LC = Pred->getLocationContext();
+ PostStmt PS(StoreE, LC);
+ if (!PP)
+ PP = &PS;
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
- StoreE, *this,
- ProgramPoint::PostStmtKind);
+ StoreE, *this, *PP);
+ // 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;
+ return;
+ }
+
ExplodedNodeSet TmpDst;
- StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx);
- const LocationContext *LC = Pred->getLocationContext();
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState();
-
- if (atDeclInit) {
- const VarRegion *VR =
- cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
-
- state = state->bindDecl(VR, Val);
- } else {
- state = state->bindLoc(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),
+ Val, /* notifyChanges = */ !atDeclInit);
+
const MemRegion *LocReg = 0;
- if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location))
+ if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) {
LocReg = LocRegVal->getRegion();
-
+ }
+
const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
- Bldr.generateNode(L, PredI, state, false);
+ Bldr.generateNode(L, state, PredI);
}
-
Dst.insert(TmpDst);
}
@@ -1671,7 +1711,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
if (Tmp.empty())
return;
- StmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
if (location.isUndef())
return;
@@ -1684,8 +1724,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
// This is important. We must nuke the old binding.
Bldr.generateNode(NodeEx, *NI,
state->BindExpr(BoundEx, LCtx, UnknownVal()),
- false, tag,
- ProgramPoint::PostLoadKind);
+ tag, ProgramPoint::PostLoadKind);
}
else {
if (LoadTy.isNull())
@@ -1693,7 +1732,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
SVal V = state->getSVal(cast<Loc>(location), LoadTy);
Bldr.generateNode(NodeEx, *NI,
state->bindExprAndLocation(BoundEx, LCtx, location, V),
- false, tag, ProgramPoint::PostLoadKind);
+ tag, ProgramPoint::PostLoadKind);
}
}
}
@@ -1706,7 +1745,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
SVal location,
const ProgramPointTag *tag,
bool isLoad) {
- StmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx);
// Early checks for performance reason.
if (location.isUnknown()) {
return;
@@ -1714,7 +1753,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
ExplodedNodeSet Src;
BldrTop.takeNodes(Pred);
- StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx);
if (Pred->getState() != state) {
// Associate this new state with an ExplodedNode.
// FIXME: If I pass null tag, the graph is incorrect, e.g for
@@ -1725,9 +1764,8 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
// instead "int *p" is noted as
// "Variable 'p' initialized to a null pointer value"
- // FIXME: why is 'tag' not used instead of etag?
- static SimpleProgramPointTag etag("ExprEngine: Location");
- Bldr.generateNode(NodeEx, Pred, state, false, &etag);
+ static SimpleProgramPointTag tag("ExprEngine: Location");
+ Bldr.generateNode(NodeEx, Pred, state, &tag);
}
ExplodedNodeSet Tmp;
getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad,
@@ -1736,16 +1774,18 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
}
std::pair<const ProgramPointTag *, const ProgramPointTag*>
-ExprEngine::getEagerlyAssumeTags() {
+ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
static SimpleProgramPointTag
- EagerlyAssumeTrue("ExprEngine : Eagerly Assume True"),
- EagerlyAssumeFalse("ExprEngine : Eagerly Assume False");
- return std::make_pair(&EagerlyAssumeTrue, &EagerlyAssumeFalse);
+ eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"),
+ eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False");
+ return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
+ &eagerlyAssumeBinOpBifurcationFalse);
}
-void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
- const Expr *Ex) {
- StmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext);
+void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ const Expr *Ex) {
+ StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I;
@@ -1762,28 +1802,28 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
- getEagerlyAssumeTags();
+ geteagerlyAssumeBinOpBifurcationTags();
// First assume that the condition is true.
if (ProgramStateRef StateTrue = state->assume(*SEV, true)) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
- Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first);
+ Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
}
// Next, assume that the condition is false.
if (ProgramStateRef StateFalse = state->assume(*SEV, false)) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
- Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second);
+ Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
}
}
}
}
-void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
// We have processed both the inputs and the outputs. All of the outputs
// should evaluate to Locs. Nuke all of their values.
@@ -1793,7 +1833,7 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
- for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
+ 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.
@@ -1807,7 +1847,7 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(A, Pred, Pred->getState());
}
@@ -1932,7 +1972,7 @@ struct DOTGraphTraits<ExplodedNode*> :
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
const Stmt *S = L->getStmt();
- Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
+ Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
LangOptions LO; // FIXME.
S->printPretty(Out, 0, PrintingPolicy(LO));
printLocation(Out, S->getLocStart());
@@ -2038,8 +2078,8 @@ struct DOTGraphTraits<ExplodedNode*> :
}
ProgramStateRef state = N->getState();
- Out << "\\|StateID: " << (void*) state.getPtr()
- << " NodeID: " << (void*) N << "\\|";
+ Out << "\\|StateID: " << (const void*) state.getPtr()
+ << " NodeID: " << (const void*) N << "\\|";
state->printDOT(Out);
Out << "\\l";
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 46cba81b14f7..00b2f4a6bee9 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -45,8 +45,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
if (RightV.isUnknown()) {
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx, Count);
+ unsigned Count = currBldrCtx->blockCount();
+ RightV = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, Count);
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
@@ -57,7 +57,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
}
if (!B->isAssignmentOp()) {
- StmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext);
+ StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
if (B->isAdditiveOp()) {
// If one of the operands is a location, conjure a symbol for the other
@@ -65,16 +65,16 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// results in an ElementRegion.
// TODO: This can be removed after we enable history tracking with
// SymSymExpr.
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
+ unsigned Count = currBldrCtx->blockCount();
if (isa<Loc>(LeftV) &&
RHS->getType()->isIntegerType() && RightV.isUnknown()) {
- RightV = svalBuilder.getConjuredSymbolVal(RHS, LCtx,
- RHS->getType(), Count);
+ RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(),
+ Count);
}
if (isa<Loc>(RightV) &&
LHS->getType()->isIntegerType() && LeftV.isUnknown()) {
- LeftV = svalBuilder.getConjuredSymbolVal(LHS, LCtx,
- LHS->getType(), Count);
+ LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(),
+ Count);
}
}
@@ -145,15 +145,11 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
SVal LHSVal;
if (Result.isUnknown()) {
-
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
-
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
// LValue on the LHS will bind to.
- LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx,
- LTy, Count);
-
+ LHSVal = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, LTy,
+ currBldrCtx->blockCount());
// However, we need to convert the symbol to the computation type.
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
}
@@ -208,11 +204,10 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
}
ExplodedNodeSet Tmp;
- StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
Bldr.generateNode(BE, Pred,
State->BindExpr(BE, Pred->getLocationContext(), V),
- false, 0,
- ProgramPoint::PostLValueKind);
+ 0, ProgramPoint::PostLValueKind);
// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
@@ -242,12 +237,14 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
- StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I != E; ++I) {
Pred = *I;
-
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+
switch (CastE->getCastKind()) {
case CK_LValueToRValue:
llvm_unreachable("LValueToRValue casts handled earlier.");
@@ -267,7 +264,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_NonAtomicToAtomic:
// True no-ops.
case CK_NoOp:
- case CK_FunctionToPointerDecay: {
+ case CK_ConstructorConversion:
+ case CK_UserDefinedConversion:
+ case CK_FunctionToPointerDecay:
+ case CK_BuiltinFnToFnPtr: {
// Copy the SVal of Ex to CastE.
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
@@ -276,6 +276,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
Bldr.generateNode(CastE, Pred, state);
continue;
}
+ case CK_MemberPointerToBoolean:
+ // FIXME: For now, member pointers are represented by void *.
+ // FALLTHROUGH
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
@@ -304,8 +307,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast: {
// Delegate to SValBuilder to process.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
state = state->BindExpr(CastE, LCtx, V);
@@ -315,8 +316,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
// For DerivedToBase cast, delegate to the store manager.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
SVal val = state->getSVal(Ex, LCtx);
val = getStoreManager().evalDerivedToBase(val, CastE);
state = state->BindExpr(CastE, LCtx, val);
@@ -325,8 +324,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
}
// Handle C++ dyn_cast.
case CK_Dynamic: {
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
SVal val = state->getSVal(Ex, LCtx);
// Compute the type of the result.
@@ -347,7 +344,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (T->isReferenceType()) {
// A bad_cast exception is thrown if input value is a reference.
// Currently, we model this, by generating a sink.
- Bldr.generateNode(CastE, Pred, state, true);
+ Bldr.generateSink(CastE, Pred, state);
continue;
} else {
// If the cast fails on a pointer, bind to 0.
@@ -356,9 +353,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
} else {
// If we don't know if the cast succeeded, conjure a new symbol.
if (val.isUnknown()) {
- DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL,
- CastE, LCtx, resultType,
- currentBuilderContext->getCurrentBlockCount());
+ DefinedOrUnknownSVal NewSym =
+ svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType,
+ currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, NewSym);
} else
// Else, bind to the derived region value.
@@ -367,27 +364,29 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
Bldr.generateNode(CastE, Pred, state);
continue;
}
+ case CK_NullToMemberPointer: {
+ // FIXME: For now, member pointers are represented by void *.
+ SVal V = svalBuilder.makeIntValWithPtrWidth(0, true);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
// Various C++ casts that are not handled yet.
case CK_ToUnion:
case CK_BaseToDerived:
- case CK_NullToMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_ReinterpretMemberPointer:
- case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
case CK_VectorSplat:
- case CK_MemberPointerToBoolean:
case CK_LValueBitCast: {
// Recover some path-sensitivty by conjuring a new value.
QualType resultType = CastE->getType();
if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, LCtx,
- resultType, currentBuilderContext->getCurrentBlockCount());
- ProgramStateRef state = Pred->getState()->BindExpr(CastE, LCtx,
- result);
+ SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx,
+ resultType,
+ currBldrCtx->blockCount());
+ state = state->BindExpr(CastE, LCtx, result);
Bldr.generateNode(CastE, Pred, state);
continue;
}
@@ -398,7 +397,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
const InitListExpr *ILE
= cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
@@ -442,7 +441,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
- StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
const VarDecl *VD = dyn_cast<VarDecl>(D);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
@@ -478,8 +477,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Ty = getContext().getPointerType(Ty);
}
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
- currentBuilderContext->getCurrentBlockCount());
+ InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty,
+ currBldrCtx->blockCount());
}
B.takeNodes(N);
ExplodedNodeSet Dst2;
@@ -488,7 +487,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
}
}
else {
- B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
+ B.generateNode(DS, N, state);
}
}
}
@@ -498,7 +497,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
assert(B->getOpcode() == BO_LAnd ||
B->getOpcode() == BO_LOr);
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
ExplodedNode *N = Pred;
@@ -531,10 +530,28 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
else {
// If there is no terminator, by construction the last statement
// 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());
- const Stmt *S = Elem.getStmt();
- X = N->getState()->getSVal(S, Pred->getLocationContext());
+ 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());
+ } else {
+ // The value is known to be true.
+ X = getSValBuilder().makeIntVal(1, 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));
@@ -543,14 +560,15 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
QualType T = getContext().getCanonicalType(IE->getType());
unsigned NumInitElements = IE->getNumInits();
- if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
+ if (T->isArrayType() || T->isRecordType() || T->isVectorType() ||
+ T->isAnyComplexType()) {
llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements.
@@ -590,7 +608,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
const Expr *R,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
const CFGBlock *SrcBlock = 0;
@@ -631,7 +649,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
void ExprEngine::
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
APSInt IV;
if (OOE->EvaluateAsInt(IV, getContext())) {
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
@@ -650,7 +668,7 @@ void ExprEngine::
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
QualType T = Ex->getTypeOfArgument();
@@ -683,7 +701,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
switch (U->getOpcode()) {
default: {
Bldr.takeNodes(Pred);
@@ -816,7 +834,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
evalLoad(Tmp, U, Ex, Pred, state, loc);
ExplodedNodeSet Dst2;
- StmtNodeBuilder Bldr(Tmp, Dst2, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) {
state = (*I)->getState();
@@ -840,16 +858,17 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
if (U->getType()->isAnyPointerType())
RHS = svalBuilder.makeArrayIndex(1);
- else
+ else if (U->getType()->isIntegralOrEnumerationType())
RHS = svalBuilder.makeIntVal(1, U->getType());
+ else
+ RHS = UnknownVal();
SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal =
- svalBuilder.getConjuredSymbolVal(NULL, Ex, LCtx,
- currentBuilderContext->getCurrentBlockCount());
+ svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount());
Result = SymVal;
// If the value is a location, ++/-- should always preserve
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 44a860f689da..b3baa7905782 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -25,20 +25,28 @@ using namespace ento;
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
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, Pred->getLocationContext());
-
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
+ 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.
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR || !isa<CXXTempObjectRegion>(MR)) {
+ const MemRegion *R =
+ svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
+
+ SVal L = loc::MemRegionVal(R);
+ state = state->bindLoc(L, V);
+ V = L;
+ }
- state = state->bindLoc(loc::MemRegionVal(R), V);
- Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
+ Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V));
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
@@ -53,9 +61,9 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
case CXXConstructExpr::CK_Complete: {
// See if we're constructing an existing region by looking at the next
// element in the CFG.
- const CFGBlock *B = currentBuilderContext->getBlock();
- if (currentStmtIdx + 1 < B->size()) {
- CFGElement Next = (*B)[currentStmtIdx+1];
+ const CFGBlock *B = currBldrCtx->getBlock();
+ if (currStmtIdx + 1 < B->size()) {
+ CFGElement Next = (*B)[currStmtIdx+1];
// Is this a constructor for a local variable?
if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) {
@@ -101,8 +109,12 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
// FIXME: This will eventually need to handle new-expressions as well.
}
- // If we couldn't find an existing region to construct into, we'll just
- // generate a symbolic region, which is fine.
+ // If we couldn't find an existing region to construct into, assume we're
+ // constructing a temporary.
+ if (!Target) {
+ MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
+ Target = MRMgr.getCXXTempObjectRegion(CE, LCtx);
+ }
break;
}
@@ -137,7 +149,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
*Call, *this);
ExplodedNodeSet DstInvalidated;
- StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
+ StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
defaultEvalCall(Bldr, *I, *Call);
@@ -151,6 +163,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
void ExprEngine::VisitCXXDestructor(QualType ObjectType,
const MemRegion *Dest,
const Stmt *S,
+ bool IsBaseDtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
const LocationContext *LCtx = Pred->getLocationContext();
@@ -171,7 +184,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDestructorCall> Call =
- CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, State, LCtx);
+ CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),
@@ -182,7 +195,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
*Call, *this);
ExplodedNodeSet DstInvalidated;
- StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
+ StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
defaultEvalCall(Bldr, *I, *Call);
@@ -198,12 +211,13 @@ 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, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- unsigned blockCount = currentBuilderContext->getCurrentBlockCount();
+ unsigned blockCount = currBldrCtx->blockCount();
const LocationContext *LCtx = Pred->getLocationContext();
- DefinedOrUnknownSVal symVal =
- svalBuilder.getConjuredSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount);
+ DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx,
+ CNE->getType(),
+ blockCount);
ProgramStateRef State = Pred->getState();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
@@ -215,6 +229,18 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// we should be using the usual pre-/(default-)eval-/post-call checks here.
State = Call->invalidateRegions(blockCount);
+ // 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>())
+ if (!ProtoType->isNothrow(getContext()))
+ State = State->assume(symVal, true);
+ }
+
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
@@ -232,11 +258,12 @@ 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.)
- FunctionDecl *FD = CNE->getOperatorNew();
if (FD && FD->isReservedGlobalPlacementOperator()) {
// Non-array placement new should always return the placement location.
SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
- State = State->BindExpr(CNE, LCtx, PlacementLoc);
+ SVal Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
+ CNE->getPlacementArg(0)->getType());
+ State = State->BindExpr(CNE, LCtx, Result);
} else {
State = State->BindExpr(CNE, LCtx, symVal);
}
@@ -259,7 +286,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
Bldr.generateNode(CDE, Pred, state);
}
@@ -274,18 +301,18 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS,
}
const LocationContext *LCtx = Pred->getLocationContext();
- SVal V = svalBuilder.getConjuredSymbolVal(CS, LCtx, VD->getType(),
- currentBuilderContext->getCurrentBlockCount());
+ SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(),
+ currBldrCtx->blockCount());
ProgramStateRef state = Pred->getState();
state = state->bindLoc(state->getLValue(VD, LCtx), V);
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(CS, Pred, state);
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
// Get the this object region from StoreManager.
const LocationContext *LCtx = Pred->getLocationContext();
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 3b2e4ec8243b..3ead0817f71b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -17,19 +17,22 @@
#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 "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
-#define CXX_INLINING_ENABLED 1
-
using namespace clang;
using namespace ento;
STATISTIC(NumOfDynamicDispatchPathSplits,
"The # of times we split the path due to imprecise dynamic dispatch info");
+STATISTIC(NumInlinedCalls,
+ "The # of times we inlined a call");
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -64,35 +67,47 @@ static std::pair<const Stmt*,
const StackFrameContext *SF =
Node->getLocation().getLocationContext()->getCurrentStackFrame();
- // Back up through the ExplodedGraph until we reach a statement node.
+ // Back up through the ExplodedGraph until we reach a statement node in this
+ // stack frame.
while (Node) {
const ProgramPoint &PP = Node->getLocation();
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
- S = SP->getStmt();
- break;
- } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
- S = CEE->getCalleeContext()->getCallSite();
- if (S)
+ if (PP.getLocationContext()->getCurrentStackFrame() == SF) {
+ if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
+ S = SP->getStmt();
break;
- // If we have an implicit call, we'll probably end up with a
- // StmtPoint inside the callee, which is acceptable.
- // (It's possible a function ONLY contains implicit calls -- such as an
- // implicitly-generated destructor -- so we shouldn't just skip back to
- // the CallEnter node and keep going.)
+ } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
+ S = CEE->getCalleeContext()->getCallSite();
+ if (S)
+ break;
+
+ // 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;
+ do {
+ Node = Node->getFirstPred();
+ CE = Node->getLocationAs<CallEnter>();
+ } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());
+
+ // Continue searching the graph.
+ }
} else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) {
// If we reached the CallEnter for this function, it has no statements.
if (CE->getCalleeContext() == SF)
break;
}
+ if (Node->pred_empty())
+ return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0);
+
Node = *Node->pred_begin();
}
const CFGBlock *Blk = 0;
if (S) {
// Now, get the enclosing basic block.
- while (Node && Node->pred_size() >=1 ) {
+ while (Node) {
const ProgramPoint &PP = Node->getLocation();
if (isa<BlockEdge>(PP) &&
(PP.getLocationContext()->getCurrentStackFrame() == SF)) {
@@ -100,6 +115,9 @@ static std::pair<const Stmt*,
Blk = EPP.getDst();
break;
}
+ if (Node->pred_empty())
+ return std::pair<const Stmt*, const CFGBlock*>(S, (CFGBlock*)0);
+
Node = *Node->pred_begin();
}
}
@@ -107,6 +125,82 @@ static std::pair<const Stmt*,
return std::pair<const Stmt*, const CFGBlock*>(S, Blk);
}
+/// Adjusts a return value when the called function's return type does not
+/// match the caller's expression type. This can happen when a dynamic call
+/// is devirtualized, and the overridding method has a covariant (more specific)
+/// return type than the parent's method. For C++ objects, this means we need
+/// to add base casts.
+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))
+ return V;
+
+ // If the types already match, don't do any unnecessary work.
+ ExpectedTy = ExpectedTy.getCanonicalType();
+ ActualTy = ActualTy.getCanonicalType();
+ if (ExpectedTy == ActualTy)
+ return V;
+
+ // No adjustment is needed between Objective-C pointer types.
+ if (ExpectedTy->isObjCObjectPointerType() &&
+ ActualTy->isObjCObjectPointerType())
+ return V;
+
+ // C++ object pointers may need "derived-to-base" casts.
+ const CXXRecordDecl *ExpectedClass = ExpectedTy->getPointeeCXXRecordDecl();
+ const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl();
+ if (ExpectedClass && ActualClass) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (ActualClass->isDerivedFrom(ExpectedClass, Paths) &&
+ !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) {
+ return StoreMgr.evalDerivedToBase(V, Paths.front());
+ }
+ }
+
+ // Unfortunately, Objective-C does not enforce that overridden methods have
+ // covariant return types, so we can't assert that that never happens.
+ // Be safe and return UnknownVal().
+ return UnknownVal();
+}
+
+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) {
+ 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,
+ ProgramPoint::PostStmtPurgeDeadSymbolsKind);
+ currBldrCtx = 0;
+}
+
+static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
+ const StackFrameContext *calleeCtx) {
+ const Decl *RuntimeCallee = calleeCtx->getDecl();
+ const Decl *StaticDecl = Call->getDecl();
+ assert(RuntimeCallee);
+ if (!StaticDecl)
+ return true;
+ return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
+}
+
/// 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:
@@ -133,6 +227,11 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
const CFGBlock *Blk = 0;
llvm::tie(LastSt, Blk) = getLastStmt(CEBNode);
+ // Generate a CallEvent /before/ cleaning the state, so that we can get the
+ // correct value for 'this' (if necessary).
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state);
+
// Step 2: generate node with bound return value: CEBNode -> BindedRetNode.
// If the callee returns an expression, bind its value to CallExpr.
@@ -140,6 +239,19 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
+
+ // Ensure that the return type matches the type of the returned Expr.
+ if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) {
+ QualType ReturnedTy =
+ CallEvent::getDeclaredResultType(calleeCtx->getDecl());
+ if (!ReturnedTy.isNull()) {
+ if (const Expr *Ex = dyn_cast<Expr>(CE)) {
+ V = adjustReturnValue(V, Ex->getType(), ReturnedTy,
+ getStoreManager());
+ }
+ }
+ }
+
state = state->BindExpr(CE, callerCtx, V);
}
@@ -149,23 +261,25 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
SVal ThisV = state->getSVal(This);
- // Always bind the region to the CXXConstructExpr.
+ // 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));
+
state = state->BindExpr(CCE, callerCtx, ThisV);
}
}
- // Generate a CallEvent /before/ cleaning the state, so that we can get the
- // correct value for 'this' (if necessary).
- CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state);
-
// Step 3: BindedRetNode -> CleanedNodes
// If we can find a statement and a block in the inlined function, run remove
// dead bindings before returning from the call. This is important to ensure
// that we report the issues such as leaks in the stack contexts in which
// they occurred.
ExplodedNodeSet CleanedNodes;
- if (LastSt && Blk) {
+ if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) {
static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value");
PostStmt Loc(LastSt, calleeCtx, &retValBind);
bool isNew;
@@ -175,14 +289,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
return;
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
- currentBuilderContext = &Ctx;
+ currBldrCtx = &Ctx;
// Here, we call the Symbol Reaper with 0 statement and caller 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,
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
- currentBuilderContext = 0;
+ currBldrCtx = 0;
} else {
CleanedNodes.Add(CEBNode);
}
@@ -204,9 +318,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// result onto the work list.
// CEENode -> Dst -> WorkList
NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
- SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
+ SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx,
&Ctx);
- SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
+ SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex());
CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
@@ -236,14 +350,48 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
}
}
-static unsigned getNumberStackFrames(const LocationContext *LCtx) {
- unsigned count = 0;
+void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx,
+ bool &IsRecursive, unsigned &StackDepth) {
+ IsRecursive = false;
+ StackDepth = 0;
+
while (LCtx) {
- if (isa<StackFrameContext>(LCtx))
- ++count;
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LCtx)) {
+ const Decl *DI = SFC->getDecl();
+
+ // Mark recursive (and mutually recursive) functions and always count
+ // them when measuring the stack depth.
+ if (DI == D) {
+ IsRecursive = true;
+ ++StackDepth;
+ LCtx = LCtx->getParent();
+ continue;
+ }
+
+ // Do not count the small functions when determining the stack depth.
+ AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI);
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+ if (CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize())
+ ++StackDepth;
+ }
LCtx = LCtx->getParent();
}
- return count;
+
+}
+
+static bool IsInStdNamespace(const FunctionDecl *FD) {
+ const DeclContext *DC = FD->getEnclosingNamespaceContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND)
+ return false;
+
+ while (const DeclContext *Parent = ND->getParent()) {
+ if (!isa<NamespaceDecl>(Parent))
+ break;
+ ND = cast<NamespaceDecl>(Parent);
+ }
+
+ return ND->getName() == "std";
}
// Determine if we should inline the call.
@@ -256,14 +404,18 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
if (!CalleeCFG)
return false;
- if (getNumberStackFrames(Pred->getLocationContext())
- == AMgr.InlineMaxStackDepth)
+ 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.InlineMaxFunctionSize)
+ if (CalleeCFG->getNumBlockIDs() > AMgr.options.InlineMaxFunctionSize)
return false;
// Do not inline variadic calls (for now).
@@ -276,6 +428,21 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
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>())
@@ -284,26 +451,21 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
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
-/// done to ensure we do not drop coverage.
-/// This is the map from the receiver region to a bool, specifying either we
-/// consider this region's information precise or not along the given path.
-namespace clang {
-namespace ento {
-enum DynamicDispatchMode { DynamicDispatchModeInlined = 1,
- DynamicDispatchModeConservative };
-
-struct DynamicDispatchBifurcationMap {};
-typedef llvm::ImmutableMap<const MemRegion*,
- unsigned int> DynamicDispatchBifur;
-template<> struct ProgramStateTrait<DynamicDispatchBifurcationMap>
- : public ProgramStatePartialTrait<DynamicDispatchBifur> {
- static void *GDMIndex() { static int index; return &index; }
-};
-
-}}
+// 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
+// done to ensure we do not drop coverage.
+// This is the map from the receiver region to a bool, specifying either we
+// consider this region's information precise or not along the given path.
+namespace {
+ enum DynamicDispatchMode {
+ DynamicDispatchModeInlined = 1,
+ DynamicDispatchModeConservative
+ };
+}
+REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
+ CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *,
+ unsigned))
bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
NodeBuilder &Bldr, ExplodedNode *Pred,
@@ -314,24 +476,19 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
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 (!CXX_INLINING_ENABLED)
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
return false;
break;
case CE_CXXConstructor: {
- if (!CXX_INLINING_ENABLED)
- return false;
-
- // Only inline constructors and destructors if we built the CFGs for them
- // properly.
- const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
- !ADC->getCFGBuildOptions().AddInitializers)
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
return false;
const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
@@ -341,9 +498,31 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
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.
- const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
if (!Target || !isa<DeclRegion>(Target))
return false;
@@ -351,15 +530,13 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
break;
}
case CE_CXXDestructor: {
- if (!CXX_INLINING_ENABLED)
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
return false;
- // Only inline constructors and destructors if we built the CFGs for them
- // properly.
+ // Inlining destructors requires building the CFG correctly.
const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
- !ADC->getCFGBuildOptions().AddInitializers)
- return false;
+ assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
+ (void)ADC;
const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
@@ -371,9 +548,6 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
break;
}
case CE_CXXAllocator:
- if (!CXX_INLINING_ENABLED)
- return false;
-
// Do not inline allocators until we model deallocators.
// This is unfortunate, but basically necessary for smart pointers and such.
return false;
@@ -387,8 +561,10 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
break;
}
case CE_ObjCMessage:
- if (!(getAnalysisManager().IPAMode == DynamicDispatch ||
- getAnalysisManager().IPAMode == DynamicDispatchBifurcate))
+ if (!Opts.mayInlineObjCMethod())
+ return false;
+ if (!(getAnalysisManager().options.IPAMode == DynamicDispatch ||
+ getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate))
return false;
break;
}
@@ -406,8 +582,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
const StackFrameContext *CalleeSFC =
CalleeADC->getStackFrame(ParentOfCallee, CallE,
- currentBuilderContext->getBlock(),
- currentStmtIdx);
+ currBldrCtx->getBlock(),
+ currStmtIdx);
CallEnter Loc(CallE, CalleeSFC, CurLC);
@@ -426,6 +602,12 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
// added onto the work list so remove it from the node builder.
Bldr.takeNodes(Pred);
+ NumInlinedCalls++;
+
+ // Mark the decl as visited.
+ if (VisitedCallees)
+ VisitedCallees->insert(D);
+
return true;
}
@@ -520,8 +702,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// Conjure a symbol if the return value is unknown.
QualType ResultTy = Call.getResultType();
SValBuilder &SVB = getSValBuilder();
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- SVal R = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+ unsigned Count = currBldrCtx->blockCount();
+ SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count);
return State->BindExpr(E, LCtx, R);
}
@@ -529,8 +711,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// a conjured return value.
void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State) {
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- State = Call.invalidateRegions(Count, State);
+ State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
State = bindReturnValue(Call, Pred->getLocationContext(), State);
// And make the result node.
@@ -562,13 +743,13 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
if (D) {
if (RD.mayHaveOtherDefinitions()) {
// Explore with and without inlining the call.
- if (getAnalysisManager().IPAMode == DynamicDispatchBifurcate) {
+ if (getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate) {
BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred);
return;
}
// Don't inline if we're not in any dynamic dispatch mode.
- if (getAnalysisManager().IPAMode != DynamicDispatch) {
+ if (getAnalysisManager().options.IPAMode != DynamicDispatch) {
conservativeEvalCall(*Call, Bldr, Pred, State);
return;
}
@@ -593,7 +774,7 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg,
// Check if we've performed the split already - note, we only want
// to split the path once per memory region.
ProgramStateRef State = Pred->getState();
- const unsigned int *BState =
+ const unsigned *BState =
State->get<DynamicDispatchBifurcationMap>(BifurReg);
if (BState) {
// If we are on "inline path", keep inlining if possible.
@@ -630,7 +811,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
- StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
if (RS->getRetValue()) {
for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index e3bc498b51e8..51dda19b5315 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -28,7 +28,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
SVal location = state->getLValue(Ex->getDecl(), baseVal);
ExplodedNodeSet dstIvar;
- StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
// Perform the post-condition check of the ObjCIvarRefExpr and store
@@ -88,7 +88,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
ExplodedNodeSet Tmp;
- StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
NE = dstLocation.end(); NI!=NE; ++NI) {
@@ -112,8 +112,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
// For now, just 'conjure' up a symbolic value.
QualType T = R->getValueType();
assert(Loc::isLocType(T));
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count);
+ SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
+ currBldrCtx->blockCount());
SVal V = svalBuilder.makeLoc(Sym);
hasElems = hasElems->bindLoc(elementV, V);
@@ -132,14 +132,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
}
-static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
- if (!Class)
- return false;
- if (Class->getIdentifier() == II)
- return true;
- return isSubclass(Class->getSuperClass(), II);
-}
-
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
@@ -157,7 +149,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
- StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
+ StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
@@ -184,68 +176,30 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
// Check if the "raise" message was sent.
assert(notNilState);
- if (Msg->getSelector() == RaiseSel) {
+ 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.generateNode(currentStmt, Pred, State, true);
+ Bldr.generateSink(currStmt, Pred, State);
continue;
}
// Generate a transition to non-Nil state.
- if (notNilState != State)
- Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
+ if (notNilState != State) {
+ Pred = Bldr.generateNode(currStmt, Pred, notNilState);
+ assert(Pred && "Should have cached out already!");
+ }
}
} else {
- // Check for special class methods.
- if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
- if (!NSExceptionII) {
- ASTContext &Ctx = getContext();
- NSExceptionII = &Ctx.Idents.get("NSException");
- }
-
- if (isSubclass(Iface, NSExceptionII)) {
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
- if (!NSExceptionInstanceRaiseSelectors) {
- ASTContext &Ctx = getContext();
- NSExceptionInstanceRaiseSelectors =
- new Selector[NUM_RAISE_SELECTORS];
- SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
- unsigned idx = 0;
-
- // raise:format:
- II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
-
- // raise:format:arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
-
- Selector S = Msg->getSelector();
- bool RaisesException = false;
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true;
- break;
- }
- }
- if (RaisesException) {
- // If we raise an exception, for now treat it as a sink.
- // Eventually we will want to handle exceptions properly.
- Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
- continue;
- }
-
- }
+ // Check for special class methods that are known to not return
+ // and that we should treat as a sink.
+ 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());
+ continue;
}
}
- // Evaluate the call.
defaultEvalCall(Bldr, Pred, *UpdatedMsg);
}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 982bcbfcdf9a..fd875f66d2db 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -17,8 +17,8 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Rewrite/Rewriter.h"
-#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/FileSystem.h"
@@ -189,7 +189,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
- << D.getDescription() << "</td></tr>\n";
+ << D.getVerboseDescription() << "</td></tr>\n";
// Output any other meta data.
@@ -209,15 +209,15 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
std::string s;
llvm::raw_string_ostream os(s);
- const std::string& BugDesc = D.getDescription();
+ StringRef BugDesc = D.getVerboseDescription();
if (!BugDesc.empty())
os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
- const std::string& BugType = D.getBugType();
+ StringRef BugType = D.getBugType();
if (!BugType.empty())
os << "\n<!-- BUGTYPE " << BugType << " -->\n";
- const std::string& BugCategory = D.getCategory();
+ StringRef BugCategory = D.getCategory();
if (!BugCategory.empty())
os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
@@ -267,8 +267,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
}
if (filesMade) {
- filesMade->push_back(std::make_pair(StringRef(getName()),
- llvm::sys::path::filename(H.str())));
+ filesMade->addDiagnostic(D, getName(), llvm::sys::path::filename(H.str()));
}
// Emit the HTML to disk.
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 62e602a7e1e1..fab10cfd3d04 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -352,7 +352,7 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const FunctionDecl *FD,
+ const NamedDecl *FD,
const MemRegion*) {
ID.AddInteger(MemRegion::FunctionTextRegionKind);
ID.AddPointer(FD);
@@ -444,7 +444,7 @@ void MemRegion::dumpToStream(raw_ostream &os) const {
}
void AllocaRegion::dumpToStream(raw_ostream &os) const {
- os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
+ os << "alloca{" << (const void*) Ex << ',' << Cnt << '}';
}
void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
@@ -452,7 +452,7 @@ void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
}
void BlockTextRegion::dumpToStream(raw_ostream &os) const {
- os << "block_code{" << (void*) this << '}';
+ os << "block_code{" << (const void*) this << '}';
}
void BlockDataRegion::dumpToStream(raw_ostream &os) const {
@@ -461,12 +461,12 @@ void BlockDataRegion::dumpToStream(raw_ostream &os) const {
void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
// FIXME: More elaborate pretty-printing.
- os << "{ " << (void*) CL << " }";
+ os << "{ " << (const void*) CL << " }";
}
void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
os << "temp_object{" << getValueType().getAsString() << ','
- << (void*) Ex << '}';
+ << (const void*) Ex << '}';
}
void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
@@ -748,11 +748,11 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
}
else {
assert(D->isStaticLocal());
- const Decl *D = STC->getDecl();
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ const Decl *STCD = STC->getDecl();
+ if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD))
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
- getFunctionTextRegion(FD));
- else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ getFunctionTextRegion(cast<NamedDecl>(STCD)));
+ else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) {
const BlockTextRegion *BTR =
getBlockTextRegion(BD,
C.getCanonicalType(BD->getSignatureAsWritten()->getType()),
@@ -761,8 +761,6 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
BTR);
}
else {
- // FIXME: For ObjC-methods, we need a new CodeTextRegion. For now
- // just use the main global memspace.
sReg = getGlobalsRegion();
}
}
@@ -845,7 +843,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
}
const FunctionTextRegion *
-MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
+MemRegionManager::getFunctionTextRegion(const NamedDecl *FD) {
return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
}
@@ -990,6 +988,10 @@ const MemRegion *MemRegion::getBaseRegion() const {
return R;
}
+bool MemRegion::isSubRegionOf(const MemRegion *R) const {
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// View handling.
//===----------------------------------------------------------------------===//
@@ -1107,7 +1109,7 @@ RegionOffset MemRegion::getAsOffset() const {
// If our base region is symbolic, we don't know what type it really is.
// 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(getContext())->getPointeeType();
+ Ty = SR->getSymbol()->getType()->getPointeeType();
}
const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
@@ -1166,8 +1168,12 @@ RegionOffset MemRegion::getAsOffset() const {
R = FR->getSuperRegion();
const RecordDecl *RD = FR->getDecl()->getParent();
- if (!RD->isCompleteDefinition()) {
+ if (RD->isUnion() || !RD->isCompleteDefinition()) {
// We cannot compute offset for incomplete type.
+ // For unions, we could treat everything as offset 0, but we'd rather
+ // treat each field as a symbolic offset so they aren't stored on top
+ // of each other, since we depend on things in typed regions actually
+ // matching their types.
SymbolicOffsetBase = R;
}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index c849778e7f23..0f48d1e1c798 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace ento;
@@ -104,11 +105,12 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
PathDiagnostic::~PathDiagnostic() {}
PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
- StringRef bugtype, StringRef desc,
- StringRef category)
+ StringRef bugtype, StringRef verboseDesc,
+ StringRef shortDesc, StringRef category)
: DeclWithIssue(declWithIssue),
BugType(StripTrailingDots(bugtype)),
- Desc(StripTrailingDots(desc)),
+ VerboseDesc(StripTrailingDots(verboseDesc)),
+ ShortDesc(StripTrailingDots(shortDesc)),
Category(StripTrailingDots(category)),
path(pathImpl) {}
@@ -198,6 +200,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
if (orig_size <= new_size)
return;
+ assert(orig != D);
Diags.RemoveNode(orig);
delete orig;
}
@@ -205,39 +208,151 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
Diags.InsertNode(OwningD.take());
}
+static llvm::Optional<bool> comparePath(const PathPieces &X,
+ const PathPieces &Y);
+static llvm::Optional<bool>
+compareControlFlow(const PathDiagnosticControlFlowPiece &X,
+ const PathDiagnosticControlFlowPiece &Y) {
+ FullSourceLoc XSL = X.getStartLocation().asLocation();
+ FullSourceLoc YSL = Y.getStartLocation().asLocation();
+ if (XSL != YSL)
+ return XSL.isBeforeInTranslationUnitThan(YSL);
+ FullSourceLoc XEL = X.getEndLocation().asLocation();
+ FullSourceLoc YEL = Y.getEndLocation().asLocation();
+ if (XEL != YEL)
+ return XEL.isBeforeInTranslationUnitThan(YEL);
+ return llvm::Optional<bool>();
+}
+
+static llvm::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) {
+ FullSourceLoc X_CEL = X.callEnter.asLocation();
+ FullSourceLoc Y_CEL = Y.callEnter.asLocation();
+ if (X_CEL != Y_CEL)
+ return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
+ FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
+ FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
+ if (X_CEWL != Y_CEWL)
+ return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
+ FullSourceLoc X_CRL = X.callReturn.asLocation();
+ FullSourceLoc Y_CRL = Y.callReturn.asLocation();
+ if (X_CRL != Y_CRL)
+ return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
+ return comparePath(X.path, Y.path);
+}
+
+static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
+ const PathDiagnosticPiece &Y) {
+ if (X.getKind() != Y.getKind())
+ return X.getKind() < Y.getKind();
+
+ FullSourceLoc XL = X.getLocation().asLocation();
+ FullSourceLoc YL = Y.getLocation().asLocation();
+ if (XL != YL)
+ return XL.isBeforeInTranslationUnitThan(YL);
+
+ if (X.getString() != Y.getString())
+ return X.getString() < Y.getString();
+
+ if (X.getRanges().size() != Y.getRanges().size())
+ return X.getRanges().size() < Y.getRanges().size();
+
+ const SourceManager &SM = XL.getManager();
+
+ for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
+ SourceRange XR = X.getRanges()[i];
+ SourceRange YR = Y.getRanges()[i];
+ if (XR != YR) {
+ if (XR.getBegin() != YR.getBegin())
+ return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
+ return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
+ }
+ }
+
+ switch (X.getKind()) {
+ case clang::ento::PathDiagnosticPiece::ControlFlow:
+ return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
+ cast<PathDiagnosticControlFlowPiece>(Y));
+ case clang::ento::PathDiagnosticPiece::Event:
+ return llvm::Optional<bool>();
+ case clang::ento::PathDiagnosticPiece::Macro:
+ return compareMacro(cast<PathDiagnosticMacroPiece>(X),
+ cast<PathDiagnosticMacroPiece>(Y));
+ case clang::ento::PathDiagnosticPiece::Call:
+ return compareCall(cast<PathDiagnosticCallPiece>(X),
+ cast<PathDiagnosticCallPiece>(Y));
+ }
+ llvm_unreachable("all cases handled");
+}
+
+static llvm::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]);
+ if (b.hasValue())
+ return b.getValue();
+ }
+ return llvm::Optional<bool>();
+}
+
+static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
+ FullSourceLoc XL = X.getLocation().asLocation();
+ FullSourceLoc YL = Y.getLocation().asLocation();
+ if (XL != YL)
+ return XL.isBeforeInTranslationUnitThan(YL);
+ if (X.getBugType() != Y.getBugType())
+ return X.getBugType() < Y.getBugType();
+ if (X.getCategory() != Y.getCategory())
+ return X.getCategory() < Y.getCategory();
+ if (X.getVerboseDescription() != Y.getVerboseDescription())
+ return X.getVerboseDescription() < Y.getVerboseDescription();
+ if (X.getShortDescription() != Y.getShortDescription())
+ return X.getShortDescription() < Y.getShortDescription();
+ if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
+ const Decl *XD = X.getDeclWithIssue();
+ if (!XD)
+ return true;
+ const Decl *YD = Y.getDeclWithIssue();
+ if (!YD)
+ return false;
+ SourceLocation XDL = XD->getLocation();
+ SourceLocation YDL = YD->getLocation();
+ if (XDL != YDL) {
+ const SourceManager &SM = XL.getManager();
+ return SM.isBeforeInTranslationUnit(XDL, YDL);
+ }
+ }
+ PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
+ PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
+ if (XE - XI != YE - YI)
+ return (XE - XI) < (YE - YI);
+ for ( ; XI != XE ; ++XI, ++YI) {
+ if (*XI != *YI)
+ return (*XI) < (*YI);
+ }
+ llvm::Optional<bool> b = comparePath(X.path, Y.path);
+ assert(b.hasValue());
+ return b.getValue();
+}
namespace {
struct CompareDiagnostics {
// Compare if 'X' is "<" than 'Y'.
bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
- // First compare by location
- const FullSourceLoc &XLoc = X->getLocation().asLocation();
- const FullSourceLoc &YLoc = Y->getLocation().asLocation();
- if (XLoc < YLoc)
- return true;
- if (XLoc != YLoc)
+ if (X == Y)
return false;
-
- // Next, compare by bug type.
- StringRef XBugType = X->getBugType();
- StringRef YBugType = Y->getBugType();
- if (XBugType < YBugType)
- return true;
- if (XBugType != YBugType)
- return false;
-
- // Next, compare by bug description.
- StringRef XDesc = X->getDescription();
- StringRef YDesc = Y->getDescription();
- if (XDesc < YDesc)
- return true;
- if (XDesc != YDesc)
- return false;
-
- // FIXME: Further refine by comparing PathDiagnosticPieces?
- return false;
- }
-};
+ return compare(*X, *Y);
+ }
+};
}
void PathDiagnosticConsumer::FlushDiagnostics(
@@ -250,11 +365,9 @@ void PathDiagnosticConsumer::FlushDiagnostics(
std::vector<const PathDiagnostic *> BatchDiags;
for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
et = Diags.end(); it != et; ++it) {
- BatchDiags.push_back(&*it);
+ const PathDiagnostic *D = &*it;
+ BatchDiags.push_back(D);
}
-
- // Clear out the FoldingSet.
- Diags.clear();
// Sort the diagnostics so that they are always emitted in a deterministic
// order.
@@ -269,6 +382,42 @@ void PathDiagnosticConsumer::FlushDiagnostics(
const PathDiagnostic *D = *it;
delete D;
}
+
+ // Clear out the FoldingSet.
+ Diags.clear();
+}
+
+void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
+ StringRef ConsumerName,
+ StringRef FileName) {
+ llvm::FoldingSetNodeID NodeID;
+ NodeID.Add(PD);
+ void *InsertPos;
+ PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
+ if (!Entry) {
+ Entry = Alloc.Allocate<PDFileEntry>();
+ Entry = new (Entry) PDFileEntry(NodeID);
+ InsertNode(Entry, InsertPos);
+ }
+
+ // Allocate persistent storage for the file name.
+ char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
+ memcpy(FileName_cstr, FileName.data(), FileName.size());
+
+ Entry->files.push_back(std::make_pair(ConsumerName,
+ StringRef(FileName_cstr,
+ FileName.size())));
+}
+
+PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
+PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
+ llvm::FoldingSetNodeID NodeID;
+ NodeID.Add(PD);
+ void *InsertPos;
+ PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
+ if (!Entry)
+ return 0;
+ return &Entry->files;
}
//===----------------------------------------------------------------------===//
@@ -437,8 +586,8 @@ PathDiagnosticLocation
const CFGBlock *BSrc = BE->getSrc();
S = BSrc->getTerminatorCondition();
}
- else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- S = PS->getStmt();
+ else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+ S = SP->getStmt();
}
else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
return PathDiagnosticLocation(PIE->getLocation(), SMng);
@@ -453,6 +602,9 @@ PathDiagnosticLocation
CEE->getLocationContext(),
SMng);
}
+ else {
+ llvm_unreachable("Unexpected ProgramPoint");
+ }
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
}
@@ -463,21 +615,26 @@ PathDiagnosticLocation
assert(N && "Cannot create a location with a null node.");
const ExplodedNode *NI = N;
+ const Stmt *S = 0;
while (NI) {
ProgramPoint P = NI->getLocation();
- const LocationContext *LC = P.getLocationContext();
if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
- return PathDiagnosticLocation(PS->getStmt(), SM, LC);
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- const Stmt *Term = BE->getSrc()->getTerminator();
- if (Term) {
- return PathDiagnosticLocation(Term, SM, LC);
- }
- }
+ S = PS->getStmt();
+ else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
+ S = BE->getSrc()->getTerminator();
+ if (S)
+ break;
NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
}
+ if (S) {
+ const LocationContext *LC = NI->getLocationContext();
+ if (S->getLocStart().isValid())
+ return PathDiagnosticLocation(S, SM, LC);
+ return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
+ }
+
return createDeclEnd(N->getLocationContext(), SM);
}
@@ -587,24 +744,6 @@ void PathDiagnosticLocation::flatten() {
}
}
-PathDiagnosticLocation PathDiagnostic::getLocation() const {
- assert(path.size() > 0 &&
- "getLocation() requires a non-empty PathDiagnostic.");
-
- PathDiagnosticPiece *p = path.rbegin()->getPtr();
-
- while (true) {
- if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
- assert(!cp->path.empty());
- p = cp->path.rbegin()->getPtr();
- continue;
- }
- break;
- }
-
- return p->getLocation();
-}
-
//===----------------------------------------------------------------------===//
// Manipulation of PathDiagnosticCallPieces.
//===----------------------------------------------------------------------===//
@@ -753,10 +892,9 @@ void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
}
void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
- if (!path.empty())
- getLocation().Profile(ID);
+ ID.Add(getLocation());
ID.AddString(BugType);
- ID.AddString(Desc);
+ ID.AddString(VerboseDesc);
ID.AddString(Category);
}
@@ -818,42 +956,16 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
return getMessageForSymbolNotFound();
}
-/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
-/// some common place. (Same as HandleOrdinalModifier.)
-void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
- llvm::raw_svector_ostream &Out) {
- assert(ValNo != 0 && "ValNo must be strictly positive!");
-
- // We could use text forms for the first N ordinals, but the numeric
- // forms are actually nicer in diagnostics because they stand out.
- Out << ValNo;
-
- // It is critically important that we do this perfectly for
- // user-written sequences with over 100 elements.
- switch (ValNo % 100) {
- case 11:
- case 12:
- case 13:
- Out << "th"; return;
- default:
- switch (ValNo % 10) {
- case 1: Out << "st"; return;
- case 2: Out << "nd"; return;
- case 3: Out << "rd"; return;
- default: Out << "th"; return;
- }
- }
-}
-
std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
- unsigned ArgIndex) {
+ unsigned ArgIndex) {
+ // Printed parameters start at 1, not 0.
+ ++ArgIndex;
+
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << Msg << " via ";
- // Printed parameters start at 1, not 0.
- printOrdinal(++ArgIndex, os);
- os << " parameter";
+ os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
+ << " parameter";
return os.str();
}
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index d5fdd9d2bb99..17ef4cf571e8 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -13,8 +13,9 @@
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/Basic/SourceManager.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"
@@ -47,7 +48,6 @@ namespace {
PathGenerationScheme getGenerationScheme() const { return Extensive; }
bool supportsLogicalOpControlFlow() const { return true; }
bool supportsAllBlockEdges() const { return true; }
- virtual bool useVerboseDescription() const { return false; }
virtual bool supportsCrossFileDiagnostics() const {
return SupportsCrossFileDiagnostics;
}
@@ -247,6 +247,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
// Output the short text.
// FIXME: Really use a short string.
Indent(o, indent) << "<key>message</key>\n";
+ Indent(o, indent);
EmitString(o, P.getString()) << '\n';
// Finish up.
@@ -409,10 +410,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
"<plist version=\"1.0\">\n";
// Write the root object: a <dict> containing...
+ // - "clang_version", the string representation of clang version
// - "files", an <array> mapping from FIDs to file names
// - "diagnostics", an <array> containing the path diagnostics
- o << "<dict>\n"
- " <key>files</key>\n"
+ o << "<dict>\n" <<
+ " <key>clang_version</key>\n";
+ EmitString(o, getClangFullVersion()) << '\n';
+ o << " <key>files</key>\n"
" <array>\n";
for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
@@ -443,7 +447,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the bug type and bug category.
o << " <key>description</key>";
- EmitString(o, D->getDescription()) << '\n';
+ EmitString(o, D->getShortDescription()) << '\n';
o << " <key>category</key>";
EmitString(o, D->getCategory()) << '\n';
o << " <key>type</key>";
@@ -499,19 +503,23 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the diagnostic to the sub-diagnostic client, if any.
if (!filesMade->empty()) {
StringRef lastName;
- for (FilesMade::iterator I = filesMade->begin(), E = filesMade->end();
- I != E; ++I) {
- StringRef newName = I->first;
- if (newName != lastName) {
- if (!lastName.empty())
- o << " </array>\n";
- lastName = newName;
- o << " <key>" << lastName << "_files</key>\n";
- o << " <array>\n";
+ PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
+ if (files) {
+ for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
+ CE = files->end(); CI != CE; ++CI) {
+ StringRef newName = CI->first;
+ if (newName != lastName) {
+ if (!lastName.empty()) {
+ o << " </array>\n";
+ }
+ lastName = newName;
+ o << " <key>" << lastName << "_files</key>\n";
+ o << " <array>\n";
+ }
+ o << " <string>" << CI->second << "</string>\n";
}
- o << " <string>" << I->second << "</string>\n";
+ o << " </array>\n";
}
- o << " </array>\n";
}
// Close up the entry.
@@ -521,10 +529,5 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " </array>\n";
// Finish.
- o << "</dict>\n</plist>";
-
- if (filesMade) {
- StringRef Name(getName());
- filesMade->push_back(std::make_pair(Name, OutputFile));
- }
+ o << "</dict>\n</plist>";
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 2000338ee0a6..b49a11e64214 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -22,10 +22,6 @@
using namespace clang;
using namespace ento;
-// Give the vtable for ConstraintManager somewhere to live.
-// FIXME: Move this elsewhere.
-ConstraintManager::~ConstraintManager() {}
-
namespace clang { namespace ento {
/// Increments the number of times this state is referenced.
@@ -75,8 +71,8 @@ ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateSMgr,
ConstraintManagerCreator CreateCMgr,
llvm::BumpPtrAllocator &alloc,
- SubEngine &SubEng)
- : Eng(&SubEng), EnvMgr(alloc), GDMFactory(alloc),
+ SubEngine *SubEng)
+ : Eng(SubEng), EnvMgr(alloc), GDMFactory(alloc),
svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
StoreMgr.reset((*CreateSMgr)(*this));
@@ -110,47 +106,25 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
SymReaper);
NewState.setStore(newStore);
SymReaper.setReapedStore(newStore);
-
- return getPersistentState(NewState);
-}
-
-ProgramStateRef ProgramStateManager::MarshalState(ProgramStateRef state,
- const StackFrameContext *InitLoc) {
- // make up an empty state for now.
- ProgramState State(this,
- EnvMgr.getInitialEnvironment(),
- StoreMgr->getInitialStore(InitLoc),
- GDMFactory.getEmptyMap());
- return getPersistentState(State);
+ ProgramStateRef Result = getPersistentState(NewState);
+ return ConstraintMgr->removeDeadBindings(Result, SymReaper);
}
ProgramStateRef ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const {
const StoreRef &newStore =
- getStateManager().StoreMgr->BindCompoundLiteral(getStore(), CL, LC, V);
+ getStateManager().StoreMgr->bindCompoundLiteral(getStore(), CL, LC, V);
return makeWithStore(newStore);
}
-ProgramStateRef ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const {
- const StoreRef &newStore =
- getStateManager().StoreMgr->BindDecl(getStore(), VR, IVal);
- return makeWithStore(newStore);
-}
-
-ProgramStateRef ProgramState::bindDeclWithNoInit(const VarRegion* VR) const {
- const StoreRef &newStore =
- getStateManager().StoreMgr->BindDeclWithNoInit(getStore(), VR);
- return makeWithStore(newStore);
-}
-
-ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V) const {
+ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const {
ProgramStateManager &Mgr = getStateManager();
ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
LV, V));
const MemRegion *MR = LV.getAsRegion();
- if (MR && Mgr.getOwningEngine())
+ if (MR && Mgr.getOwningEngine() && notifyChanges)
return Mgr.getOwningEngine()->processRegionChange(newState, MR);
return newState;
@@ -204,11 +178,12 @@ ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
return makeWithStore(newStore);
}
-ProgramStateRef ProgramState::unbindLoc(Loc LV) const {
+ProgramStateRef ProgramState::killBinding(Loc LV) const {
assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
Store OldStore = getStore();
- const StoreRef &newStore = getStateManager().StoreMgr->Remove(OldStore, LV);
+ const StoreRef &newStore =
+ getStateManager().StoreMgr->killBinding(OldStore, LV);
if (newStore.getStore() == OldStore)
return this;
@@ -249,7 +224,9 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
// about).
if (!T.isNull()) {
if (SymbolRef sym = V.getAsSymbol()) {
- if (const llvm::APSInt *Int = getSymVal(sym)) {
+ if (const llvm::APSInt *Int = getStateManager()
+ .getConstraintManager()
+ .getSymVal(this, sym)) {
// FIXME: Because we don't correctly model (yet) sign-extension
// and truncation of symbolic values, we need to convert
// the integer value to the correct signedness and bitwidth.
@@ -710,7 +687,9 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
bool Tainted = false;
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
SI != SE; ++SI) {
- assert(isa<SymbolData>(*SI));
+ if (!isa<SymbolData>(*SI))
+ continue;
+
const TaintTagType *Tag = get<TaintMap>(*SI);
Tainted = (Tag && *Tag == Kind);
@@ -734,15 +713,10 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
}
/// The GDM component containing the dynamic type info. This is a map from a
-/// symbol to it's most likely type.
-namespace clang {
-namespace ento {
-typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> DynamicTypeMap;
-template<> struct ProgramStateTrait<DynamicTypeMap>
- : public ProgramStatePartialTrait<DynamicTypeMap> {
- static void *GDMIndex() { static int index; return &index; }
-};
-}}
+/// symbol to its most likely type.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicTypeMap,
+ CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *,
+ DynamicTypeInfo))
DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
Reg = Reg->StripCasts();
@@ -758,7 +732,7 @@ DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
SymbolRef Sym = SR->getSymbol();
- return DynamicTypeInfo(Sym->getType(getStateManager().getContext()));
+ return DynamicTypeInfo(Sym->getType());
}
return DynamicTypeInfo();
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 550404a51075..411094bc1d14 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -24,9 +24,6 @@
using namespace clang;
using namespace ento;
-namespace { class ConstraintRange {}; }
-static int ConstraintRangeIndex = 0;
-
/// A Range represents the closed range [from, to]. The caller must
/// guarantee that from <= to. Note that Range is immutable, so as not
/// to subvert RangeSet's immutability.
@@ -280,23 +277,15 @@ public:
};
} // end anonymous namespace
-typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<ConstraintRange>
- : public ProgramStatePartialTrait<ConstraintRangeTy> {
- static inline void *GDMIndex() { return &ConstraintRangeIndex; }
-};
-}
-}
+REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintRange,
+ CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef,
+ RangeSet))
namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(ProgramStateRef state, SymbolRef sym);
public:
- RangeConstraintManager(SubEngine &subengine, BasicValueFactory &BVF)
+ RangeConstraintManager(SubEngine *subengine, BasicValueFactory &BVF)
: SimpleConstraintManager(subengine, BVF) {}
ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
@@ -324,12 +313,7 @@ public:
const llvm::APSInt& Adjustment);
const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const;
-
- // FIXME: Refactor into SimpleConstraintManager?
- bool isEqual(ProgramStateRef St, SymbolRef sym, const llvm::APSInt& V) const {
- const llvm::APSInt *i = getSymVal(St, sym);
- return i ? *i == V : false;
- }
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper);
@@ -343,7 +327,7 @@ private:
} // end anonymous namespace
ConstraintManager *
-ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine &Eng) {
+ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
return new RangeConstraintManager(Eng, StMgr.getBasicVals());
}
@@ -353,6 +337,30 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
return T ? T->getConcreteValue() : NULL;
}
+ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
+ SymbolRef Sym) {
+ const RangeSet *Ranges = State->get<ConstraintRange>(Sym);
+
+ // If we don't have any information about this symbol, it's underconstrained.
+ if (!Ranges)
+ return ConditionTruthVal();
+
+ // If we have a concrete value, see if it's zero.
+ if (const llvm::APSInt *Value = Ranges->getConcreteValue())
+ return *Value == 0;
+
+ BasicValueFactory &BV = getBasicVals();
+ APSIntType IntType = BV.getAPSIntType(Sym->getType());
+ llvm::APSInt Zero = IntType.getZeroValue();
+
+ // Check if zero is in the set of possible values.
+ if (Ranges->Intersect(BV, F, Zero, Zero).isEmpty())
+ return false;
+
+ // Zero is a possible value, but it is not the /only/ possible value.
+ return ConditionTruthVal();
+}
+
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
ProgramStateRef
@@ -379,8 +387,18 @@ RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) {
// Lazily generate a new RangeSet representing all possible values for the
// given symbol type.
BasicValueFactory &BV = getBasicVals();
- QualType T = sym->getType(BV.getContext());
- return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T));
+ QualType T = sym->getType();
+
+ RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T));
+
+ // Special case: references are known to be non-zero.
+ if (T->isReferenceType()) {
+ APSIntType IntType = BV.getAPSIntType(T);
+ Result = Result.Intersect(BV, F, ++IntType.getZeroValue(),
+ --IntType.getZeroValue());
+ }
+
+ return Result;
}
//===------------------------------------------------------------------------===
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index bc4e4bbf602b..aed994df4110 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -15,9 +15,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/CXXInheritance.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
@@ -193,19 +190,6 @@ public:
/// casts from arrays to pointers.
SVal ArrayToPointer(Loc Array);
- /// For DerivedToBase casts, create a CXXBaseObjectRegion and return it.
- virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType);
-
- /// \brief Evaluates C++ dynamic_cast cast.
- /// The callback may result in the following 3 scenarios:
- /// - Successful cast (ex: derived is subclass of base).
- /// - Failed cast (ex: derived is definitely not a subclass of base).
- /// - We don't know (base is a symbolic region and we don't have
- /// enough info to determine if the cast will succeed at run time).
- /// The function returns an SVal representing the derived class; it's
- /// valid only if Failed flag is set to false.
- virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,bool &Failed);
-
StoreRef getInitialStore(const LocationContext *InitLoc) {
return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this);
}
@@ -244,7 +228,7 @@ public: // Made public for helper classes.
RegionBindings removeBinding(RegionBindings B, BindingKey K);
RegionBindings removeBinding(RegionBindings B, const MemRegion *R,
- BindingKey::Kind k);
+ BindingKey::Kind k);
RegionBindings removeBinding(RegionBindings B, const MemRegion *R) {
return removeBinding(removeBinding(B, R, BindingKey::Direct), R,
@@ -266,15 +250,20 @@ public: // Part of public interface to class.
.getRootWithoutRetain(), *this);
}
- StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr *CL,
+ /// \brief Create a new store that binds a value to a compound literal.
+ ///
+ /// \param ST The original store whose bindings are the basis for the new
+ /// store.
+ ///
+ /// \param CL The compound literal to bind (the binding key).
+ ///
+ /// \param LC The LocationContext for the binding.
+ ///
+ /// \param V The value to bind to the compound literal.
+ StoreRef bindCompoundLiteral(Store ST,
+ const CompoundLiteralExpr *CL,
const LocationContext *LC, SVal V);
- StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal);
-
- StoreRef BindDeclWithNoInit(Store store, const VarRegion *) {
- return StoreRef(store, *this);
- }
-
/// BindStruct - Bind a compound value to a structure.
StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V);
@@ -287,7 +276,10 @@ public: // Part of public interface to class.
/// as a Default binding.
StoreRef BindAggregate(Store store, const TypedRegion *R, SVal DefaultVal);
- StoreRef Remove(Store store, Loc LV);
+ /// \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);
void incrementReferenceCount(Store store) {
GetRegionBindings(store).manualRetain();
@@ -477,12 +469,8 @@ public:
}
bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) {
- if (C) {
- if (Visited.count(C))
- return false;
- Visited.insert(C);
- }
-
+ if (C && !Visited.insert(C))
+ return false;
WL.push_back(R);
return true;
}
@@ -534,6 +522,46 @@ bool RegionStoreManager::scanReachableSymbols(Store S, const MemRegion *R,
return true;
}
+static inline bool isUnionField(const FieldRegion *FR) {
+ return FR->getDecl()->getParent()->isUnion();
+}
+
+typedef SmallVector<const FieldDecl *, 8> FieldVector;
+
+void getSymbolicOffsetFields(BindingKey K, FieldVector &Fields) {
+ assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
+
+ const MemRegion *Base = K.getConcreteOffsetRegion();
+ const MemRegion *R = K.getRegion();
+
+ while (R != Base) {
+ if (const FieldRegion *FR = dyn_cast<FieldRegion>(R))
+ if (!isUnionField(FR))
+ Fields.push_back(FR->getDecl());
+
+ R = cast<SubRegion>(R)->getSuperRegion();
+ }
+}
+
+static bool isCompatibleWithFields(BindingKey K, const FieldVector &Fields) {
+ assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
+
+ if (Fields.empty())
+ return true;
+
+ FieldVector FieldsInBindingKey;
+ getSymbolicOffsetFields(K, FieldsInBindingKey);
+
+ ptrdiff_t Delta = FieldsInBindingKey.size() - Fields.size();
+ if (Delta >= 0)
+ return std::equal(FieldsInBindingKey.begin() + Delta,
+ FieldsInBindingKey.end(),
+ Fields.begin());
+ else
+ return std::equal(FieldsInBindingKey.begin(), FieldsInBindingKey.end(),
+ Fields.begin() - Delta);
+}
+
RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
const SubRegion *R) {
BindingKey SRKey = BindingKey::Make(R, BindingKey::Default);
@@ -543,10 +571,12 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
return RBFactory.remove(B, R);
}
- if (SRKey.hasSymbolicOffset()) {
- const SubRegion *Base = cast<SubRegion>(SRKey.getConcreteOffsetRegion());
- B = removeSubRegionBindings(B, Base);
- return addBinding(B, Base, BindingKey::Default, UnknownVal());
+ FieldVector FieldsInSymbolicSubregions;
+ bool HasSymbolicOffset = SRKey.hasSymbolicOffset();
+ if (HasSymbolicOffset) {
+ getSymbolicOffsetFields(SRKey, FieldsInSymbolicSubregions);
+ R = cast<SubRegion>(SRKey.getConcreteOffsetRegion());
+ SRKey = BindingKey::Make(R, BindingKey::Default);
}
// This assumes the region being invalidated is char-aligned. This isn't
@@ -574,11 +604,17 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
I != E; ++I) {
BindingKey NextKey = I.getKey();
if (NextKey.getRegion() == SRKey.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) {
// Case 1: The next binding is inside the region we're invalidating.
// Remove it.
Result = CBFactory.remove(Result, NextKey);
+
} else if (NextKey.getOffset() == SRKey.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,
@@ -589,6 +625,7 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
if (NextKey.isDirect())
Result = CBFactory.remove(Result, NextKey);
}
+
} else if (NextKey.hasSymbolicOffset()) {
const MemRegion *Base = NextKey.getConcreteOffsetRegion();
if (R->isSubRegionOf(Base)) {
@@ -596,16 +633,24 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
// its concrete region. We don't know if the binding is still valid, so
// we'll be conservative and remove it.
if (NextKey.isDirect())
- Result = CBFactory.remove(Result, NextKey);
+ if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
+ Result = CBFactory.remove(Result, NextKey);
} 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))
- Result = CBFactory.remove(Result, NextKey);
+ if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
+ Result = CBFactory.remove(Result, NextKey);
}
}
}
+ // 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());
+
if (Result.isEmpty())
return RBFactory.remove(B, ClusterHead);
return RBFactory.add(B, ClusterHead, Result);
@@ -724,7 +769,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
+ svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -739,8 +784,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (T->isStructureOrClassType()) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
- DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
+ DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
+ Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -748,7 +793,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx,
+ svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
AT->getElementType(), Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
@@ -764,8 +809,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
}
- DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx,
- T,Count);
+ DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
+ T,Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
B = RM.addBinding(B, baseR, BindingKey::Direct, V);
}
@@ -779,10 +824,9 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
// 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);
- SVal V =
- svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex, LCtx,
- /* symbol type, doesn't matter */ Ctx.IntTy,
- Count);
+ SVal V = svalBuilder.conjureSymbolVal(/* SymbolTag = */ (const void*) GS, Ex, LCtx,
+ /* type does not matter */ Ctx.IntTy,
+ Count);
B = removeBinding(B, GS);
B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
@@ -897,103 +941,6 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx));
}
-// This mirrors Type::getCXXRecordDeclForPointerType(), but there doesn't
-// appear to be another need for this in the rest of the codebase.
-static const CXXRecordDecl *GetCXXRecordDeclForReferenceType(QualType Ty) {
- if (const ReferenceType *RT = Ty->getAs<ReferenceType>())
- if (const RecordType *RCT = RT->getPointeeType()->getAs<RecordType>())
- return dyn_cast<CXXRecordDecl>(RCT->getDecl());
- return 0;
-}
-
-SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) {
- const CXXRecordDecl *baseDecl;
-
- if (baseType->isPointerType())
- baseDecl = baseType->getCXXRecordDeclForPointerType();
- else if (baseType->isReferenceType())
- baseDecl = GetCXXRecordDeclForReferenceType(baseType);
- else
- baseDecl = baseType->getAsCXXRecordDecl();
-
- assert(baseDecl && "not a CXXRecordDecl?");
-
- loc::MemRegionVal *derivedRegVal = dyn_cast<loc::MemRegionVal>(&derived);
- if (!derivedRegVal)
- return derived;
-
- const MemRegion *baseReg =
- MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion());
-
- return loc::MemRegionVal(baseReg);
-}
-
-SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType,
- bool &Failed) {
- Failed = false;
-
- loc::MemRegionVal *baseRegVal = dyn_cast<loc::MemRegionVal>(&base);
- if (!baseRegVal)
- return UnknownVal();
- const MemRegion *BaseRegion = baseRegVal->stripCasts(/*StripBases=*/false);
-
- // Assume the derived class is a pointer or a reference to a CXX record.
- derivedType = derivedType->getPointeeType();
- assert(!derivedType.isNull());
- const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl();
- if (!DerivedDecl && !derivedType->isVoidType())
- return UnknownVal();
-
- // Drill down the CXXBaseObject chains, which represent upcasts (casts from
- // derived to base).
- const MemRegion *SR = BaseRegion;
- while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) {
- QualType BaseType = TSR->getLocationType()->getPointeeType();
- assert(!BaseType.isNull());
- const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl();
- if (!SRDecl)
- return UnknownVal();
-
- // If found the derived class, the cast succeeds.
- if (SRDecl == DerivedDecl)
- return loc::MemRegionVal(TSR);
-
- if (!derivedType->isVoidType()) {
- // Static upcasts are marked as DerivedToBase casts by Sema, so this will
- // only happen when multiple or virtual inheritance is involved.
- CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
- if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) {
- SVal Result = loc::MemRegionVal(TSR);
- const CXXBasePath &Path = *Paths.begin();
- for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
- I != E; ++I) {
- Result = evalDerivedToBase(Result, I->Base->getType());
- }
- return Result;
- }
- }
-
- if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR))
- // Drill down the chain to get the derived classes.
- SR = R->getSuperRegion();
- else {
- // We reached the bottom of the hierarchy.
-
- // If this is a cast to void*, return the region.
- if (derivedType->isVoidType())
- return loc::MemRegionVal(TSR);
-
- // We did not find the derived class. We we must be casting the base to
- // derived, so the cast should fail.
- Failed = true;
- return UnknownVal();
- }
- }
-
- return UnknownVal();
-}
-
//===----------------------------------------------------------------------===//
// Loading values from regions.
//===----------------------------------------------------------------------===//
@@ -1047,7 +994,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
T = TR->getLocationType();
else {
const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
- T = SR->getSymbol()->getType(Ctx);
+ T = SR->getSymbol()->getType();
}
}
MR = GetElementZeroRegion(MR, T);
@@ -1540,14 +1487,14 @@ bool RegionStoreManager::includedInBindings(Store store,
// Binding values to regions.
//===----------------------------------------------------------------------===//
-StoreRef RegionStoreManager::Remove(Store store, Loc L) {
+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(store),
+ return StoreRef(removeBinding(GetRegionBindings(ST),
R).getRootWithoutRetain(),
*this);
- return StoreRef(store, *this);
+ return StoreRef(ST, *this);
}
StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
@@ -1560,6 +1507,8 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
// 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);
if (Ty->isStructureOrClassType())
return BindStruct(store, TR, V);
if (Ty->isVectorType())
@@ -1569,13 +1518,9 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
// Binding directly to a symbolic region should be treated as binding
// to element 0.
- QualType T = SR->getSymbol()->getType(Ctx);
-
- // FIXME: Is this the right way to handle symbols that are references?
- if (const PointerType *PT = T->getAs<PointerType>())
- T = PT->getPointeeType();
- else
- T = T->getAs<ReferenceType>()->getPointeeType();
+ QualType T = SR->getSymbol()->getType();
+ if (T->isAnyPointerType() || T->isReferenceType())
+ T = T->getPointeeType();
R = GetElementZeroRegion(SR, T);
}
@@ -1589,26 +1534,12 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
return StoreRef(addBinding(B, Key, V).getRootWithoutRetain(), *this);
}
-StoreRef RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
- SVal InitVal) {
-
- QualType T = VR->getDecl()->getType();
-
- if (T->isArrayType())
- return BindArray(store, VR, InitVal);
- if (T->isStructureOrClassType())
- return BindStruct(store, VR, InitVal);
-
- return Bind(store, svalBuilder.makeLoc(VR), InitVal);
-}
-
// FIXME: this method should be merged into Bind().
-StoreRef RegionStoreManager::BindCompoundLiteral(Store store,
+StoreRef RegionStoreManager::bindCompoundLiteral(Store ST,
const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) {
- return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
- V);
+ return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V);
}
StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
@@ -1864,7 +1795,7 @@ RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
const MemRegion *R,
- BindingKey::Kind k){
+ BindingKey::Kind k){
return removeBinding(B, BindingKey::Make(R, k));
}
@@ -1897,7 +1828,6 @@ public:
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C);
void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitBindingKey(BindingKey K);
bool UpdatePostponed();
void VisitBinding(SVal V);
};
@@ -1932,17 +1862,21 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
const StackArgumentsSpaceRegion *StackReg =
cast<StackArgumentsSpaceRegion>(TR->getSuperRegion());
const StackFrameContext *RegCtx = StackReg->getStackFrame();
- if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx))
+ if (CurrentLCtx &&
+ (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx)))
AddToWorkList(TR, &C);
}
}
void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
const ClusterBindings &C) {
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I) {
- VisitBindingKey(I.getKey());
+ // 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)
VisitBinding(I.getData());
- }
}
void removeDeadBindingsWorker::VisitBinding(SVal V) {
@@ -1979,8 +1913,8 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(),
E = BR->referenced_vars_end();
- for ( ; I != E; ++I)
- AddToWorkList(I.getCapturedRegion());
+ for ( ; I != E; ++I)
+ AddToWorkList(I.getCapturedRegion());
}
}
@@ -1991,20 +1925,6 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
SymReaper.markLive(*SI);
}
-void removeDeadBindingsWorker::VisitBindingKey(BindingKey K) {
- const MemRegion *R = K.getRegion();
-
- // Mark this region "live" by adding it to the worklist. This will cause
- // use to visit all regions in the cluster (if we haven't visited them
- // already).
- if (AddToWorkList(R)) {
- // Mark the symbol for any live SymbolicRegion as "live". This means we
- // should continue to track that symbol.
- if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
- SymReaper.markLive(SymR->getSymbol());
- }
-}
-
bool removeDeadBindingsWorker::UpdatePostponed() {
// See if any postponed SymbolicRegions are actually live now, after
// having done a scan.
@@ -2012,7 +1932,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
for (SmallVectorImpl<const SymbolicRegion*>::iterator
I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) {
- if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(*I)) {
+ if (const SymbolicRegion *SR = *I) {
if (SymReaper.isLive(SR->getSymbol())) {
changed |= AddToWorkList(SR);
*I = NULL;
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index d1936cd3603e..b87169a4b335 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -106,25 +106,23 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal
-SValBuilder::getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- unsigned count) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned count) {
QualType T = expr->getType();
- return getConjuredSymbolVal(symbolTag, expr, LCtx, T, count);
+ return conjureSymbolVal(symbolTag, expr, LCtx, T, count);
}
-DefinedOrUnknownSVal
-SValBuilder::getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- QualType type,
- unsigned count) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned count) {
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(expr, LCtx, type, count, symbolTag);
+ SymbolRef sym = SymMgr.conjureSymbol(expr, LCtx, type, count, symbolTag);
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -133,15 +131,14 @@ SValBuilder::getConjuredSymbolVal(const void *symbolTag,
}
-DefinedOrUnknownSVal
-SValBuilder::getConjuredSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount) {
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount);
+ SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -157,7 +154,7 @@ SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
assert(Loc::isLocType(T));
assert(SymbolManager::canSymbolicate(T));
- SymbolRef sym = SymMgr.getConjuredSymbol(E, LCtx, T, VisitCount);
+ SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount);
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
}
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 8437f50f911f..e34ab6a2be91 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -51,7 +51,8 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
const MemRegion* R = X->getRegion();
if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
- return CTR->getDecl();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
+ return FD;
}
return 0;
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 5568f1ca555d..4236ee470af4 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -67,7 +67,9 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
- return SU.processAssume(state, cond, assumption);
+ if (NotifyAssumeClients && SU)
+ return SU->processAssume(state, cond, assumption);
+ return state;
}
ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
@@ -113,7 +115,9 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
NonLoc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
- return SU.processAssume(state, cond, assumption);
+ if (NotifyAssumeClients && SU)
+ return SU->processAssume(state, cond, assumption);
+ return state;
}
static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
@@ -136,7 +140,7 @@ ProgramStateRef
SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State,
SymbolRef Sym, bool Assumption) {
BasicValueFactory &BVF = getBasicVals();
- QualType T = Sym->getType(BVF.getContext());
+ QualType T = Sym->getType();
// None of the constraint solvers currently support non-integer types.
if (!T->isIntegerType())
@@ -186,7 +190,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
BinaryOperator::Opcode op = SE->getOpcode();
// Implicitly compare non-comparison expressions to 0.
if (!BinaryOperator::isComparisonOp(op)) {
- QualType T = SE->getType(BasicVals.getContext());
+ QualType T = SE->getType();
const llvm::APSInt &zero = BasicVals.getValue(0, T);
op = (Assumption ? BO_NE : BO_EQ);
return assumeSymRel(state, SE, op, zero);
@@ -235,11 +239,9 @@ ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state,
assert(BinaryOperator::isComparisonOp(op) &&
"Non-comparison ops should be rewritten as comparisons to zero.");
- BasicValueFactory &BVF = getBasicVals();
- ASTContext &Ctx = BVF.getContext();
-
// Get the type used for calculating wraparound.
- APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType(Ctx));
+ BasicValueFactory &BVF = getBasicVals();
+ APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType());
// We only handle simple comparisons of the form "$sym == constant"
// or "($sym+constant1) == constant2".
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 088d70c2717f..01f0b4e4461f 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -22,10 +22,10 @@ namespace clang {
namespace ento {
class SimpleConstraintManager : public ConstraintManager {
- SubEngine &SU;
+ SubEngine *SU;
BasicValueFactory &BVF;
public:
- SimpleConstraintManager(SubEngine &subengine, BasicValueFactory &BV)
+ SimpleConstraintManager(SubEngine *subengine, BasicValueFactory &BV)
: SU(subengine), BVF(BV) {}
virtual ~SimpleConstraintManager();
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index ad58a07c784e..fbc6ba055105 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -81,7 +81,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
}
if (const SymExpr *se = val.getAsSymbolicExpression()) {
- QualType T = Context.getCanonicalType(se->getType(Context));
+ QualType T = Context.getCanonicalType(se->getType());
// If types are the same or both are integers, ignore the cast.
// FIXME: Remove this hack when we support symbolic truncation/extension.
// HACK: If both castTy and T are integers, ignore the cast. This is
@@ -276,7 +276,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
// with the given constant.
// FIXME: This is an approximation of Sema::UsualArithmeticConversions.
ASTContext &Ctx = getContext();
- QualType SymbolType = LHS->getType(Ctx);
+ QualType SymbolType = LHS->getType();
uint64_t ValWidth = RHS.getBitWidth();
uint64_t TypeWidth = Ctx.getTypeSize(SymbolType);
@@ -318,7 +318,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
return makeTruthVal(false, resultTy);
case BO_Xor:
case BO_Sub:
- return makeIntVal(0, resultTy);
+ if (resultTy->isIntegralOrEnumerationType())
+ return makeIntVal(0, resultTy);
+ return evalCastFromNonLoc(makeIntVal(0, /*Unsigned=*/false), resultTy);
case BO_Or:
case BO_And:
return evalCastFromNonLoc(lhs, resultTy);
@@ -459,7 +461,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_NE:
// Negate the comparison and make a value.
opc = NegateComparison(opc);
- assert(symIntExpr->getType(Context) == resultTy);
+ assert(symIntExpr->getType() == resultTy);
return makeNonLoc(symIntExpr->getLHS(), opc,
symIntExpr->getRHS(), resultTy);
}
@@ -505,7 +507,8 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
} 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->getSymVal(Sym)) {
+ if (const llvm::APSInt *Constant = state->getConstraintManager()
+ .getSymVal(state, Sym)) {
lhs = nonloc::ConcreteInt(*Constant);
continue;
}
@@ -916,14 +919,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
else if (isa<SubRegion>(region)) {
superR = region;
index = rhs;
- if (const PointerType *PT = resultTy->getAs<PointerType>()) {
- elementType = PT->getPointeeType();
- }
- else {
- const ObjCObjectPointerType *OT =
- resultTy->getAs<ObjCObjectPointerType>();
- elementType = OT->getPointeeType();
- }
+ if (resultTy->isAnyPointerType())
+ elementType = resultTy->getPointeeType();
}
if (NonLoc *indexV = dyn_cast<NonLoc>(&index)) {
@@ -946,7 +943,7 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
return &X->getValue();
if (SymbolRef Sym = V.getAsSymbol())
- return state->getSymVal(Sym);
+ return state->getConstraintManager().getSymVal(state, Sym);
// FIXME: Add support for SymExprs.
return NULL;
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 3af60a170727..939ae54dad74 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -15,6 +15,7 @@
#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/DeclObjC.h"
using namespace clang;
@@ -233,6 +234,91 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
return Result;
}
+SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) {
+ // Walk through the path to create nested CXXBaseRegions.
+ SVal Result = Derived;
+ for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
+ I != E; ++I) {
+ Result = evalDerivedToBase(Result, I->Base->getType());
+ }
+ return Result;
+}
+
+SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
+ loc::MemRegionVal *DerivedRegVal = dyn_cast<loc::MemRegionVal>(&Derived);
+ if (!DerivedRegVal)
+ return Derived;
+
+ const CXXRecordDecl *BaseDecl = BaseType->getPointeeCXXRecordDecl();
+ if (!BaseDecl)
+ BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "not a C++ object?");
+
+ const MemRegion *BaseReg =
+ MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion());
+
+ return loc::MemRegionVal(BaseReg);
+}
+
+SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType,
+ bool &Failed) {
+ Failed = false;
+
+ loc::MemRegionVal *BaseRegVal = dyn_cast<loc::MemRegionVal>(&Base);
+ if (!BaseRegVal)
+ return UnknownVal();
+ const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false);
+
+ // Assume the derived class is a pointer or a reference to a CXX record.
+ DerivedType = DerivedType->getPointeeType();
+ assert(!DerivedType.isNull());
+ const CXXRecordDecl *DerivedDecl = DerivedType->getAsCXXRecordDecl();
+ if (!DerivedDecl && !DerivedType->isVoidType())
+ return UnknownVal();
+
+ // Drill down the CXXBaseObject chains, which represent upcasts (casts from
+ // derived to base).
+ const MemRegion *SR = BaseRegion;
+ while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) {
+ QualType BaseType = TSR->getLocationType()->getPointeeType();
+ assert(!BaseType.isNull());
+ const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl();
+ if (!SRDecl)
+ return UnknownVal();
+
+ // If found the derived class, the cast succeeds.
+ if (SRDecl == DerivedDecl)
+ return loc::MemRegionVal(TSR);
+
+ if (!DerivedType->isVoidType()) {
+ // Static upcasts are marked as DerivedToBase casts by Sema, so this will
+ // only happen when multiple or virtual inheritance is involved.
+ CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SRDecl->isDerivedFrom(DerivedDecl, Paths))
+ return evalDerivedToBase(loc::MemRegionVal(TSR), Paths.front());
+ }
+
+ if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR))
+ // Drill down the chain to get the derived classes.
+ SR = R->getSuperRegion();
+ else {
+ // We reached the bottom of the hierarchy.
+
+ // If this is a cast to void*, return the region.
+ if (DerivedType->isVoidType())
+ return loc::MemRegionVal(TSR);
+
+ // We did not find the derived class. We we must be casting the base to
+ // derived, so the cast should fail.
+ Failed = true;
+ return UnknownVal();
+ }
+ }
+
+ return UnknownVal();
+}
+
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 0bc192d64571..0c5098b1e7d0 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -117,21 +117,17 @@ bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
itr.push_back(SE);
- while (!isa<SymbolData>(itr.back())) expand();
}
SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
- assert(isa<SymbolData>(itr.back()));
- itr.pop_back();
- if (!itr.empty())
- while (!isa<SymbolData>(itr.back())) expand();
+ expand();
return *this;
}
SymbolRef SymExpr::symbol_iterator::operator*() {
assert(!itr.empty() && "attempting to dereference an 'end' iterator");
- return cast<SymbolData>(itr.back());
+ return itr.back();
}
void SymExpr::symbol_iterator::expand() {
@@ -187,11 +183,11 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
return cast<SymbolRegionValue>(SD);
}
-const SymbolConjured*
-SymbolManager::getConjuredSymbol(const Stmt *E, const LocationContext *LCtx,
- QualType T, unsigned Count,
- const void *SymbolTag) {
-
+const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
+ const LocationContext *LCtx,
+ QualType T,
+ unsigned Count,
+ const void *SymbolTag) {
llvm::FoldingSetNodeID profile;
SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag);
void *InsertPos;
@@ -328,23 +324,24 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
return cast<SymSymExpr>(data);
}
-QualType SymbolConjured::getType(ASTContext&) const {
+QualType SymbolConjured::getType() const {
return T;
}
-QualType SymbolDerived::getType(ASTContext &Ctx) const {
+QualType SymbolDerived::getType() const {
return R->getValueType();
}
-QualType SymbolExtent::getType(ASTContext &Ctx) const {
+QualType SymbolExtent::getType() const {
+ ASTContext &Ctx = R->getMemRegionManager()->getContext();
return Ctx.getSizeType();
}
-QualType SymbolMetadata::getType(ASTContext&) const {
+QualType SymbolMetadata::getType() const {
return T;
}
-QualType SymbolRegionValue::getType(ASTContext &C) const {
+QualType SymbolRegionValue::getType() const {
return R->getValueType();
}
@@ -466,41 +463,56 @@ bool SymbolReaper::isLive(SymbolRef sym) {
markDependentsLive(sym);
return true;
}
-
- if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
- if (isLive(derived->getParentSymbol())) {
- markLive(sym);
- return true;
- }
- return false;
- }
-
- if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
- if (isLiveRegion(extent->getRegion())) {
- markLive(sym);
- return true;
- }
- return false;
+
+ bool KnownLive;
+
+ 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;
+ break;
+ case SymExpr::ConjuredKind:
+ KnownLive = false;
+ break;
+ case SymExpr::DerivedKind:
+ KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
+ break;
+ case SymExpr::ExtentKind:
+ KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
+ break;
+ case SymExpr::MetadataKind:
+ KnownLive = MetadataInUse.count(sym) &&
+ isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
+ if (KnownLive)
+ MetadataInUse.erase(sym);
+ break;
+ case SymExpr::SymIntKind:
+ KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
+ break;
+ case SymExpr::IntSymKind:
+ KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
+ break;
+ case SymExpr::SymSymKind:
+ KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
+ isLive(cast<SymSymExpr>(sym)->getRHS());
+ break;
+ case SymExpr::CastSymbolKind:
+ KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
+ break;
}
- if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
- if (MetadataInUse.count(sym)) {
- if (isLiveRegion(metadata->getRegion())) {
- markLive(sym);
- MetadataInUse.erase(sym);
- return true;
- }
- }
- return false;
- }
+ if (KnownLive)
+ markLive(sym);
- // Interogate the symbol. It may derive from an input value to
- // the analyzed function/method.
- return isa<SymbolRegionValue>(sym);
+ return KnownLive;
}
bool
SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
+ if (LCtx == 0)
+ return false;
+
if (LCtx != ELCtx) {
// If the reaper's location context is a parent of the expression's
// location context, then the expression value is now "out of scope".
@@ -508,6 +520,7 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
return false;
return true;
}
+
// If no statement is provided, everything is this and parent contexts is live.
if (!Loc)
return true;
@@ -517,10 +530,16 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
const StackFrameContext *VarContext = VR->getStackFrame();
+
+ if (!VarContext)
+ return true;
+
+ if (!LCtx)
+ return false;
const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
if (VarContext == CurrentContext) {
- // If no statemetnt is provided, everything is live.
+ // If no statement is provided, everything is live.
if (!Loc)
return true;
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index 66bf4bb222d1..e09f4e365344 100644
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
@@ -41,7 +41,6 @@ public:
PathGenerationScheme getGenerationScheme() const { return Minimal; }
bool supportsLogicalOpControlFlow() const { return true; }
bool supportsAllBlockEdges() const { return true; }
- virtual bool useVerboseDescription() const { return true; }
virtual bool supportsCrossFileDiagnostics() const { return true; }
};
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 34b5266e4b76..7dbac3cf93a0 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -34,7 +34,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
@@ -78,7 +78,6 @@ public:
ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {}
virtual ~ClangDiagPathDiagConsumer() {}
virtual StringRef getName() const { return "ClangDiags"; }
- virtual bool useVerboseDescription() const { return false; }
virtual PathGenerationScheme getGenerationScheme() const { return None; }
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
@@ -86,7 +85,7 @@ public:
for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
E = Diags.end(); I != E; ++I) {
const PathDiagnostic *PD = *I;
- StringRef desc = PD->getDescription();
+ StringRef desc = PD->getShortDescription();
SmallString<512> TmpStr;
llvm::raw_svector_ostream Out(TmpStr);
for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) {
@@ -121,11 +120,12 @@ namespace {
class AnalysisConsumer : public ASTConsumer,
public RecursiveASTVisitor<AnalysisConsumer> {
- enum AnalysisMode {
- ANALYSIS_SYNTAX,
- ANALYSIS_PATH,
- ANALYSIS_ALL
+ enum {
+ AM_None = 0,
+ AM_Syntax = 0x1,
+ AM_Path = 0x2
};
+ typedef unsigned AnalysisMode;
/// Mode of the analyzes while recursively visiting Decls.
AnalysisMode RecVisitorMode;
@@ -136,7 +136,7 @@ public:
ASTContext *Ctx;
const Preprocessor &PP;
const std::string OutDir;
- AnalyzerOptions Opts;
+ AnalyzerOptionsRef Opts;
ArrayRef<std::string> Plugins;
/// \brief Stores the declarations from the local translation unit.
@@ -164,19 +164,19 @@ public:
AnalysisConsumer(const Preprocessor& pp,
const std::string& outdir,
- const AnalyzerOptions& opts,
+ AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins)
- : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
+ : RecVisitorMode(0), RecVisitorBR(0),
Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
DigestAnalyzerOptions();
- if (Opts.PrintStats) {
+ if (Opts->PrintStats) {
llvm::EnableStatistics();
TUTotalTimer = new llvm::Timer("Analyzer Total Time");
}
}
~AnalysisConsumer() {
- if (Opts.PrintStats)
+ if (Opts->PrintStats)
delete TUTotalTimer;
}
@@ -185,49 +185,52 @@ public:
PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics()));
if (!OutDir.empty()) {
- switch (Opts.AnalysisDiagOpt) {
+ switch (Opts->AnalysisDiagOpt) {
default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
case PD_##NAME: CREATEFN(PathConsumers, OutDir, PP); break;
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
}
- } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
+ } 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);
}
// Create the analyzer component creators.
- switch (Opts.AnalysisStoreOpt) {
+ switch (Opts->AnalysisStoreOpt) {
default:
llvm_unreachable("Unknown store manager.");
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateStoreMgr = CREATEFN; break;
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
}
- switch (Opts.AnalysisConstraintsOpt) {
+ switch (Opts->AnalysisConstraintsOpt) {
default:
llvm_unreachable("Unknown store manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateConstraintMgr = CREATEFN; break;
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
}
}
void DisplayFunction(const Decl *D, AnalysisMode Mode) {
- if (!Opts.AnalyzerDisplayProgress)
+ if (!Opts->AnalyzerDisplayProgress)
return;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
if (Loc.isValid()) {
llvm::errs() << "ANALYZE";
- switch (Mode) {
- case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
- case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
- case ANALYSIS_ALL: break;
- };
+
+ if (Mode == AM_Syntax)
+ llvm::errs() << " (Syntax)";
+ else if (Mode == AM_Path)
+ llvm::errs() << " (Path)";
+ else
+ assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
+
llvm::errs() << ": " << Loc.getFilename();
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
@@ -246,7 +249,7 @@ public:
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
- checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins,
+ checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
PP.getDiagnostics()));
Mgr.reset(new AnalysisManager(*Ctx,
PP.getDiagnostics(),
@@ -255,17 +258,7 @@ public:
CreateStoreMgr,
CreateConstraintMgr,
checkerMgr.get(),
- Opts.MaxNodes, Opts.MaxLoop,
- Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
- Opts.TrimGraph,
- Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
- Opts.EagerlyTrimEGraph,
- Opts.IPAMode,
- Opts.InlineMaxStackDepth,
- Opts.InlineMaxFunctionSize,
- Opts.InliningMode,
- Opts.NoRetryExhausted));
+ *Opts));
}
/// \brief Store the top level decls in the set to be processed later on.
@@ -277,7 +270,7 @@ public:
/// \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 HandleDeclsGallGraph(const unsigned LocalTUDeclsSize);
+ void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
/// \brief Run analyzes(syntax or path sensitive) on the given function.
/// \param Mode - determines if we are requesting syntax only or path
@@ -297,7 +290,9 @@ public:
/// Handle callbacks for arbitrary Decls.
bool VisitDecl(Decl *D) {
- checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
+ AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
+ if (Mode & AM_Syntax)
+ checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
return true;
}
@@ -316,7 +311,6 @@ public:
}
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
if (MD->isThisDeclarationADefinition())
HandleCode(MD, RecVisitorMode);
return true;
@@ -326,7 +320,7 @@ private:
void storeTopLevelDecls(DeclGroupRef DG);
/// \brief Check if we should skip (not analyze) the given function.
- bool skipFunction(Decl *D);
+ AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
};
} // end anonymous namespace
@@ -358,7 +352,23 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
}
}
-void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) {
+static bool shouldSkipFunction(CallGraphNode *N,
+ SmallPtrSet<CallGraphNode*,24> Visited) {
+ // We want to re-analyse the functions as top level in several 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.
+ // - We want to reanalyze all ObjC methods as top level to report Retain
+ // Count naming convention errors more aggressively.
+ if (isa<ObjCMethodDecl>(N->getDecl()))
+ return false;
+
+ // Otherwise, if we visited the function before, do not reanalyze it.
+ return Visited.count(N);
+}
+
+void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
// Otherwise, use the Callgraph to derive the order.
// Build the Call Graph.
CallGraph CG;
@@ -407,21 +417,21 @@ void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) {
// Push the children into the queue.
for (CallGraphNode::const_iterator CI = N->begin(),
CE = N->end(); CI != CE; ++CI) {
- if (!Visited.count(*CI))
+ if (!shouldSkipFunction(*CI, Visited))
BFSQueue.push_back(*CI);
}
// Skip the functions which have been processed already or previously
// inlined.
- if (Visited.count(N))
+ if (shouldSkipFunction(N, Visited))
continue;
// Analyze the function.
SetOfConstDecls VisitedCallees;
Decl *D = N->getDecl();
assert(D);
- HandleCode(D, ANALYSIS_PATH,
- (Mgr->InliningMode == All ? 0 : &VisitedCallees));
+ HandleCode(D, AM_Path,
+ (Mgr->options.InliningMode == All ? 0 : &VisitedCallees));
// Add the visited callees to the global visited set.
for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
@@ -451,7 +461,9 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
// Run the AST-only checks using the order in which functions are defined.
// If inlining is not turned on, use the simplest function order for path
// sensitive analyzes as well.
- RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
+ RecVisitorMode = AM_Syntax;
+ if (!Mgr->shouldInlineCall())
+ RecVisitorMode |= AM_Path;
RecVisitorBR = &BR;
// Process all the top level declarations.
@@ -466,7 +478,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
}
if (Mgr->shouldInlineCall())
- HandleDeclsGallGraph(LocalTUDeclsSize);
+ HandleDeclsCallGraph(LocalTUDeclsSize);
// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
@@ -513,24 +525,32 @@ static std::string getFunctionName(const Decl *D) {
return "";
}
-bool AnalysisConsumer::skipFunction(Decl *D) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- getFunctionName(D) != Opts.AnalyzeSpecificFunction)
- return true;
-
- // Don't run the actions on declarations in header files unless
- // otherwise specified.
+AnalysisConsumer::AnalysisMode
+AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
+ if (!Opts->AnalyzeSpecificFunction.empty() &&
+ getFunctionName(D) != Opts->AnalyzeSpecificFunction)
+ return AM_None;
+
+ // Unless -analyze-all is specified, treat decls differently depending on
+ // where they came from:
+ // - Main source file: run both path-sensitive and non-path-sensitive checks.
+ // - Header files: run non-path-sensitive checks only.
+ // - System headers: don't run any checks.
SourceManager &SM = Ctx->getSourceManager();
SourceLocation SL = SM.getExpansionLoc(D->getLocation());
- if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
- return true;
+ if (!Opts->AnalyzeAll && !SM.isFromMainFile(SL)) {
+ if (SL.isInvalid() || SM.isInSystemHeader(SL))
+ return AM_None;
+ return Mode & ~AM_Path;
+ }
- return false;
+ return Mode;
}
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
SetOfConstDecls *VisitedCallees) {
- if (skipFunction(D))
+ Mode = getModeForDecl(D, Mode);
+ if (Mode == AM_None)
return;
DisplayFunction(D, Mode);
@@ -548,16 +568,16 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
SmallVector<Decl*, 10> WL;
WL.push_back(D);
- if (D->hasBody() && Opts.AnalyzeNestedBlocks)
+ 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 != ANALYSIS_PATH)
+ if (Mode & AM_Syntax)
checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
+ if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
RunPathSensitiveChecks(*WI, VisitedCallees);
NumFunctionsAnalyzed++;
}
@@ -583,22 +603,22 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
// Set the graph auditor.
OwningPtr<ExplodedNode::Auditor> Auditor;
- if (Mgr->shouldVisualizeUbigraph()) {
+ if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
Auditor.reset(CreateUbiViz());
ExplodedNode::SetAuditor(Auditor.get());
}
// Execute the worklist algorithm.
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
- Mgr->getMaxNodes());
+ Mgr->options.MaxNodes);
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
ExplodedNode::SetAuditor(0);
// Visualize the exploded graph.
- if (Mgr->shouldVisualizeGraphviz())
- Eng.ViewGraph(Mgr->shouldTrimGraph());
+ if (Mgr->options.visualizeExplodedGraphWithGraphViz)
+ Eng.ViewGraph(Mgr->options.TrimGraph);
// Display warnings.
Eng.getBugReporter().FlushReports();
@@ -629,7 +649,7 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
const std::string& outDir,
- const AnalyzerOptions& opts,
+ AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins) {
// Disable the effects of '-Werror' when using the AnalysisConsumer.
pp.getDiagnostics().setWarningsAsErrors(false);
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
index 5a16bffeacf3..b75220b62de3 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -16,11 +16,11 @@
#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include <string>
namespace clang {
-class AnalyzerOptions;
class ASTConsumer;
class Preprocessor;
class DiagnosticsEngine;
@@ -33,7 +33,7 @@ class CheckerManager;
/// options.)
ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
const std::string &output,
- const AnalyzerOptions& opts,
+ AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins);
} // end GR namespace
diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
index 06d148507874..aafb249c587f 100644
--- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -25,6 +25,7 @@ target_link_libraries(clangStaticAnalyzerFrontend
clangLex
clangAST
clangFrontend
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangStaticAnalyzerCheckers
)
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 0229aed6bdaa..e8daa65e410a 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -17,7 +17,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/DynamicLibrary.h"
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index 49d3101f0e99..d29e564e34fe 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -2,8 +2,10 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTooling
ArgumentsAdjusters.cpp
- CommandLineClangTool.cpp
+ CommonOptionsParser.cpp
CompilationDatabase.cpp
+ FileMatchTrie.cpp
+ JSONCompilationDatabase.cpp
Refactoring.cpp
RefactoringCallbacks.cpp
Tooling.cpp
@@ -23,5 +25,6 @@ target_link_libraries(clangTooling
clangFrontend
clangAST
clangASTMatchers
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
)
diff --git a/lib/Tooling/CommandLineClangTool.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 8da2a335a557..15091c7e901e 100644
--- a/lib/Tooling/CommandLineClangTool.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -1,4 +1,4 @@
-//===--- CommandLineClangTool.cpp - command-line clang tools driver -------===//
+//===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,28 +7,31 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the CommandLineClangTool class used to run clang
-// tools as separate command-line applications with a consistent common
-// interface for handling compilation database and input files.
+// This file implements the CommonOptionsParser class used to parse common
+// command-line options for clang tools, so that they can be run as separate
+// command-line applications with a consistent common interface for handling
+// compilation database and input files.
//
// It provides a common subset of command-line options, common algorithm
// for locating a compilation database and source files, and help messages
// for the basic command-line interface.
//
-// It creates a CompilationDatabase, initializes a ClangTool and runs a
-// user-specified FrontendAction over all TUs in which the given files are
-// compiled.
+// It creates a CompilationDatabase and reads common command-line options.
+//
+// This class uses the Clang Tooling infrastructure, see
+// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/CommandLineClangTool.h"
+#include "llvm/Support/CommandLine.h"
+#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
using namespace clang::tooling;
using namespace llvm;
-static const char *MoreHelpText =
+const char *const CommonOptionsParser::HelpMessage =
"\n"
"-p <build-path> is used to read a compile command database.\n"
"\n"
@@ -40,26 +43,27 @@ static const char *MoreHelpText =
"\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
"\texample of setting up Clang Tooling on a source tree.\n"
"\n"
- "<source0> ... specify the paths of source files. These paths are looked\n"
- "\tup in the compile command database. If the path of a file is absolute,\n"
- "\tit needs to point into CMake's source tree. If the path is relative,\n"
- "\tthe current working directory needs to be in the CMake source tree and\n"
- "\tthe file must be in a subdirectory of the current working directory.\n"
- "\t\"./\" prefixes in the relative files will be automatically removed,\n"
- "\tbut the rest of a relative path must be a suffix of a path in the\n"
- "\tcompile command database.\n"
+ "<source0> ... specify the paths of source files. These paths are\n"
+ "\tlooked up in the compile command database. If the path of a file is\n"
+ "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
+ "\trelative, the current working directory needs to be in the CMake\n"
+ "\tsource tree and the file must be in a subdirectory of the current\n"
+ "\tworking directory. \"./\" prefixes in the relative files will be\n"
+ "\tautomatically removed, but the rest of a relative path must be a\n"
+ "\tsuffix of a path in the compile command database.\n"
"\n";
-CommandLineClangTool::CommandLineClangTool() :
- BuildPath("p", cl::desc("Build path"), cl::Optional),
- SourcePaths(cl::Positional, cl::desc("<source0> [... <sourceN>]"),
- cl::OneOrMore),
- MoreHelp(MoreHelpText) {
-}
+CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv) {
+ static cl::opt<std::string> BuildPath(
+ "p", cl::desc("Build path"), cl::Optional);
+
+ static cl::list<std::string> SourcePaths(
+ cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore);
-void CommandLineClangTool::initialize(int argc, const char **argv) {
- Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+ Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc,
+ argv));
cl::ParseCommandLineOptions(argc, argv);
+ SourcePathList = SourcePaths;
if (!Compilations) {
std::string ErrorMessage;
if (!BuildPath.empty()) {
@@ -73,8 +77,3 @@ void CommandLineClangTool::initialize(int argc, const char **argv) {
llvm::report_fatal_error(ErrorMessage);
}
}
-
-int CommandLineClangTool::run(FrontendActionFactory *ActionFactory) {
- ClangTool Tool(*Compilations, SourcePaths);
- return Tool.run(ActionFactory);
-}
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 3139cc21bb8d..4149cda3787c 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -7,132 +7,49 @@
//
//===----------------------------------------------------------------------===//
//
-// This file contains multiple implementations for CompilationDatabases.
+// This file contains implementations of the CompilationDatabase base class
+// and the FixedCompilationDatabase.
//
//===----------------------------------------------------------------------===//
+#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/YAMLParser.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
-#ifdef USE_CUSTOM_COMPILATION_DATABASE
-#include "CustomCompilationDatabase.h"
-#endif
-
namespace clang {
namespace tooling {
-namespace {
-
-/// \brief A parser for escaped strings of command line arguments.
-///
-/// Assumes \-escaping for quoted arguments (see the documentation of
-/// unescapeCommandLine(...)).
-class CommandLineArgumentParser {
- public:
- CommandLineArgumentParser(StringRef CommandLine)
- : Input(CommandLine), Position(Input.begin()-1) {}
-
- std::vector<std::string> parse() {
- bool HasMoreInput = true;
- while (HasMoreInput && nextNonWhitespace()) {
- std::string Argument;
- HasMoreInput = parseStringInto(Argument);
- CommandLine.push_back(Argument);
- }
- return CommandLine;
- }
-
- private:
- // All private methods return true if there is more input available.
-
- bool parseStringInto(std::string &String) {
- do {
- if (*Position == '"') {
- if (!parseQuotedStringInto(String)) return false;
- } else {
- if (!parseFreeStringInto(String)) return false;
- }
- } while (*Position != ' ');
- return true;
- }
-
- bool parseQuotedStringInto(std::string &String) {
- if (!next()) return false;
- while (*Position != '"') {
- if (!skipEscapeCharacter()) return false;
- 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 != '"');
- return true;
- }
-
- bool skipEscapeCharacter() {
- if (*Position == '\\') {
- return next();
- }
- return true;
- }
-
- bool nextNonWhitespace() {
- do {
- if (!next()) return false;
- } while (*Position == ' ');
- return true;
- }
-
- bool next() {
- ++Position;
- return Position != Input.end();
- }
-
- const StringRef Input;
- StringRef::iterator Position;
- std::vector<std::string> CommandLine;
-};
-
-std::vector<std::string> unescapeCommandLine(
- StringRef EscapedCommandLine) {
- CommandLineArgumentParser parser(EscapedCommandLine);
- return parser.parse();
-}
-
-} // end namespace
-
CompilationDatabase::~CompilationDatabase() {}
CompilationDatabase *
CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
std::string &ErrorMessage) {
- llvm::SmallString<1024> JSONDatabasePath(BuildDirectory);
- llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
- llvm::OwningPtr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
- if (!Database) {
- return NULL;
+ std::stringstream ErrorStream;
+ for (CompilationDatabasePluginRegistry::iterator
+ It = CompilationDatabasePluginRegistry::begin(),
+ Ie = CompilationDatabasePluginRegistry::end();
+ It != Ie; ++It) {
+ std::string DatabaseErrorMessage;
+ OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate());
+ if (CompilationDatabase *DB =
+ Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
+ return DB;
+ else
+ ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
}
- return Database.take();
+ ErrorMessage = ErrorStream.str();
+ return NULL;
}
static CompilationDatabase *
-findCompilationDatabaseFromDirectory(StringRef Directory) {
-#ifdef USE_CUSTOM_COMPILATION_DATABASE
- if (CompilationDatabase *DB =
- ::clang::tooling::findCompilationDatabaseForDirectory(Directory))
- return DB;
-#endif
+findCompilationDatabaseFromDirectory(StringRef Directory,
+ std::string &ErrorMessage) {
+ std::stringstream ErrorStream;
+ bool HasErrorMessage = false;
while (!Directory.empty()) {
std::string LoadErrorMessage;
@@ -140,8 +57,15 @@ findCompilationDatabaseFromDirectory(StringRef Directory) {
CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
return DB;
+ if (!HasErrorMessage) {
+ ErrorStream << "No compilation database found in " << Directory.str()
+ << " or any parent directory\n" << LoadErrorMessage;
+ HasErrorMessage = true;
+ }
+
Directory = llvm::sys::path::parent_path(Directory);
}
+ ErrorMessage = ErrorStream.str();
return NULL;
}
@@ -151,11 +75,12 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
- CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory);
+ CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
+ ErrorMessage);
if (!DB)
ErrorMessage = ("Could not auto-detect compilation database for file \"" +
- SourceFile + "\"").str();
+ SourceFile + "\"\n" + ErrorMessage).str();
return DB;
}
@@ -164,14 +89,17 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
std::string &ErrorMessage) {
llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
- CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath);
+ CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
+ ErrorMessage);
if (!DB)
ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
- SourceDir + "\"").str();
+ SourceDir + "\"\n" + ErrorMessage).str();
return DB;
}
+CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
+
FixedCompilationDatabase *
FixedCompilationDatabase::loadFromCommandLine(int &Argc,
const char **Argv,
@@ -204,153 +132,10 @@ FixedCompilationDatabase::getAllFiles() const {
return std::vector<std::string>();
}
-JSONCompilationDatabase *
-JSONCompilationDatabase::loadFromFile(StringRef FilePath,
- std::string &ErrorMessage) {
- llvm::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(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
- if (!Database->parse(ErrorMessage))
- return NULL;
- return Database.take();
-}
-
-JSONCompilationDatabase *
-JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
- std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
- llvm::MemoryBuffer::getMemBuffer(DatabaseString));
- llvm::OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
- if (!Database->parse(ErrorMessage))
- return NULL;
- return Database.take();
-}
-
-std::vector<CompileCommand>
-JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
- llvm::SmallString<128> NativeFilePath;
- llvm::sys::path::native(FilePath, NativeFilePath);
- llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
- CommandsRefI = IndexByFile.find(NativeFilePath);
- 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))));
- }
- return Commands;
-}
-
-std::vector<std::string>
-JSONCompilationDatabase::getAllFiles() const {
- std::vector<std::string> Result;
-
- llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
- CommandsRefI = IndexByFile.begin();
- const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
- CommandsRefEnd = IndexByFile.end();
- for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
- Result.push_back(CommandsRefI->first().str());
- }
-
- return Result;
-}
-
-bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
- llvm::yaml::document_iterator I = YAMLStream.begin();
- if (I == YAMLStream.end()) {
- ErrorMessage = "Error while parsing YAML.";
- return false;
- }
- llvm::yaml::Node *Root = I->getRoot();
- if (Root == NULL) {
- ErrorMessage = "Error while parsing YAML.";
- return false;
- }
- llvm::yaml::SequenceNode *Array =
- llvm::dyn_cast<llvm::yaml::SequenceNode>(Root);
- if (Array == NULL) {
- ErrorMessage = "Expected array.";
- return false;
- }
- 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);
- if (Object == NULL) {
- ErrorMessage = "Expected object.";
- return false;
- }
- llvm::yaml::ScalarNode *Directory = NULL;
- llvm::yaml::ScalarNode *Command = NULL;
- llvm::yaml::ScalarNode *File = NULL;
- for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
- KVE = Object->end();
- KVI != KVE; ++KVI) {
- llvm::yaml::Node *Value = (*KVI).getValue();
- if (Value == NULL) {
- ErrorMessage = "Expected value.";
- return false;
- }
- llvm::yaml::ScalarNode *ValueString =
- llvm::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());
- if (KeyString == NULL) {
- ErrorMessage = "Expected strings as key.";
- return false;
- }
- llvm::SmallString<8> KeyStorage;
- if (KeyString->getValue(KeyStorage) == "directory") {
- Directory = ValueString;
- } else if (KeyString->getValue(KeyStorage) == "command") {
- Command = ValueString;
- } else if (KeyString->getValue(KeyStorage) == "file") {
- File = ValueString;
- } else {
- ErrorMessage = ("Unknown key: \"" +
- KeyString->getRawValue() + "\"").str();
- return false;
- }
- }
- if (!File) {
- ErrorMessage = "Missing key: \"file\".";
- return false;
- }
- if (!Command) {
- ErrorMessage = "Missing key: \"command\".";
- return false;
- }
- if (!Directory) {
- ErrorMessage = "Missing key: \"directory\".";
- return false;
- }
- llvm::SmallString<8> FileStorage;
- llvm::SmallString<128> NativeFilePath;
- llvm::sys::path::native(File->getValue(FileStorage), NativeFilePath);
- IndexByFile[NativeFilePath].push_back(
- CompileCommandRef(Directory, Command));
- }
- return true;
-}
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONCompilationDatabasePlugin.
+extern volatile int JSONAnchorSource;
+static int JSONAnchorDest = JSONAnchorSource;
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/CustomCompilationDatabase.h b/lib/Tooling/CustomCompilationDatabase.h
deleted file mode 100644
index b375f8d25634..000000000000
--- a/lib/Tooling/CustomCompilationDatabase.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//===--- CustomCompilationDatabase.h --------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains a hook to supply a custom \c CompilationDatabase
-// implementation.
-//
-// The mechanism can be used by IDEs or non-public code bases to integrate with
-// their build system. Currently we support statically linking in an
-// implementation of \c findCompilationDatabaseForDirectory and enabling it
-// with -DUSE_CUSTOM_COMPILATION_DATABASE when compiling the Tooling library.
-//
-// FIXME: The strategy forward is to provide a plugin system that can load
-// custom compilation databases and make enabling that a build option.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H
-#define LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H
-
-#include "llvm/ADT/StringRef.h"
-
-namespace clang {
-namespace tooling {
-class CompilationDatabase;
-
-/// \brief Returns a CompilationDatabase for the given \c Directory.
-///
-/// \c Directory can be any directory within a project. This methods will
-/// then try to find compilation database files in \c Directory or any of its
-/// parents. If a compilation database cannot be found or loaded, returns NULL.
-clang::tooling::CompilationDatabase *findCompilationDatabaseForDirectory(
- llvm::StringRef Directory);
-
-} // namespace tooling
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
new file mode 100644
index 000000000000..8f25a8c2bcfb
--- /dev/null
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -0,0 +1,188 @@
+//===--- FileMatchTrie.cpp - ----------------------------------------------===//
+//
+// 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 implementation of a FileMatchTrie.
+//
+//===----------------------------------------------------------------------===//
+
+#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"
+
+namespace clang {
+namespace tooling {
+
+/// \brief Default \c PathComparator using \c llvm::sys::fs::equivalent().
+struct DefaultPathComparator : public PathComparator {
+ virtual ~DefaultPathComparator() {}
+ virtual bool equivalent(StringRef FileA, StringRef FileB) const {
+ return FileA == FileB || llvm::sys::fs::equivalent(FileA, FileB);
+ }
+};
+
+/// \brief A node of the \c FileMatchTrie.
+///
+/// Each node has storage for up to one path and a map mapping a path segment to
+/// child nodes. The trie starts with an empty root node.
+class FileMatchTrieNode {
+public:
+ /// \brief Inserts 'NewPath' into this trie. \c ConsumedLength denotes
+ /// the number of \c NewPath's trailing characters already consumed during
+ /// recursion.
+ ///
+ /// An insert of a path
+ /// 'p'starts at the root node and does the following:
+ /// - If the node is empty, insert 'p' into its storage and abort.
+ /// - If the node has a path 'p2' but no children, take the last path segment
+ /// 's' of 'p2', put a new child into the map at 's' an insert the rest of
+ /// 'p2' there.
+ /// - Insert a new child for the last segment of 'p' and insert the rest of
+ /// 'p' there.
+ ///
+ /// An insert operation is linear in the number of a path's segments.
+ void insert(StringRef NewPath, unsigned ConsumedLength = 0) {
+ // We cannot put relative paths into the FileMatchTrie as then a path can be
+ // a postfix of another path, violating a core assumption of the trie.
+ if (llvm::sys::path::is_relative(NewPath))
+ return;
+ if (Path.empty()) {
+ // This is an empty leaf. Store NewPath and return.
+ Path = NewPath;
+ return;
+ }
+ if (Children.empty()) {
+ // This is a leaf, ignore duplicate entry if 'Path' equals 'NewPath'.
+ if (NewPath == Path)
+ return;
+ // Make this a node and create a child-leaf with 'Path'.
+ StringRef Element(llvm::sys::path::filename(
+ StringRef(Path).drop_back(ConsumedLength)));
+ Children[Element].Path = Path;
+ }
+ StringRef Element(llvm::sys::path::filename(
+ StringRef(NewPath).drop_back(ConsumedLength)));
+ Children[Element].insert(NewPath, ConsumedLength + Element.size() + 1);
+ }
+
+ /// \brief Tries to find the node under this \c FileMatchTrieNode that best
+ /// matches 'FileName'.
+ ///
+ /// If multiple paths fit 'FileName' equally well, \c IsAmbiguous is set to
+ /// \c true and an empty string is returned. If no path fits 'FileName', an
+ /// empty string is returned. \c ConsumedLength denotes the number of
+ /// \c Filename's trailing characters already consumed during recursion.
+ ///
+ /// To find the best matching node for a given path 'p', the
+ /// \c findEquivalent() function is called recursively for each path segment
+ /// (back to fron) of 'p' until a node 'n' is reached that does not ..
+ /// - .. have children. In this case it is checked
+ /// whether the stored path is equivalent to 'p'. If yes, the best match is
+ /// found. Otherwise continue with the parent node as if this node did not
+ /// exist.
+ /// - .. a child matching the next path segment. In this case, all children of
+ /// 'n' are an equally good match for 'p'. All children are of 'n' are found
+ /// recursively and their equivalence to 'p' is determined. If none are
+ /// equivalent, continue with the parent node as if 'n' didn't exist. If one
+ /// is equivalent, the best match is found. Otherwise, report and ambigiuity
+ /// error.
+ StringRef findEquivalent(const PathComparator& Comparator,
+ StringRef FileName,
+ bool &IsAmbiguous,
+ unsigned ConsumedLength = 0) const {
+ if (Children.empty()) {
+ if (Comparator.equivalent(StringRef(Path), FileName))
+ return StringRef(Path);
+ return StringRef();
+ }
+ StringRef Element(llvm::sys::path::filename(FileName.drop_back(
+ ConsumedLength)));
+ llvm::StringMap<FileMatchTrieNode>::const_iterator MatchingChild =
+ Children.find(Element);
+ if (MatchingChild != Children.end()) {
+ StringRef Result = MatchingChild->getValue().findEquivalent(
+ Comparator, FileName, IsAmbiguous,
+ ConsumedLength + Element.size() + 1);
+ if (!Result.empty() || IsAmbiguous)
+ return Result;
+ }
+ std::vector<StringRef> AllChildren;
+ getAll(AllChildren, MatchingChild);
+ StringRef Result;
+ for (unsigned i = 0; i < AllChildren.size(); i++) {
+ if (Comparator.equivalent(AllChildren[i], FileName)) {
+ if (Result.empty()) {
+ Result = AllChildren[i];
+ } else {
+ IsAmbiguous = true;
+ return StringRef();
+ }
+ }
+ }
+ return Result;
+ }
+
+private:
+ /// \brief Gets all paths under this FileMatchTrieNode.
+ void getAll(std::vector<StringRef> &Results,
+ llvm::StringMap<FileMatchTrieNode>::const_iterator Except) const {
+ if (Path.empty())
+ return;
+ if (Children.empty()) {
+ Results.push_back(StringRef(Path));
+ return;
+ }
+ for (llvm::StringMap<FileMatchTrieNode>::const_iterator
+ It = Children.begin(), E = Children.end();
+ It != E; ++It) {
+ if (It == Except)
+ continue;
+ It->getValue().getAll(Results, Children.end());
+ }
+ }
+
+ // The stored absolute path in this node. Only valid for leaf nodes, i.e.
+ // nodes where Children.empty().
+ std::string Path;
+
+ // The children of this node stored in a map based on the next path segment.
+ llvm::StringMap<FileMatchTrieNode> Children;
+};
+
+FileMatchTrie::FileMatchTrie()
+ : Root(new FileMatchTrieNode), Comparator(new DefaultPathComparator()) {}
+
+FileMatchTrie::FileMatchTrie(PathComparator *Comparator)
+ : Root(new FileMatchTrieNode), Comparator(Comparator) {}
+
+FileMatchTrie::~FileMatchTrie() {
+ delete Root;
+}
+
+void FileMatchTrie::insert(StringRef NewPath) {
+ Root->insert(NewPath);
+}
+
+StringRef FileMatchTrie::findEquivalent(StringRef FileName,
+ llvm::raw_ostream &Error) const {
+ if (llvm::sys::path::is_relative(FileName)) {
+ Error << "Cannot resolve relative paths";
+ return StringRef();
+ }
+ bool IsAmbiguous = false;
+ StringRef Result = Root->findEquivalent(*Comparator, FileName, IsAmbiguous);
+ if (IsAmbiguous)
+ Error << "Path is ambiguous";
+ return Result;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
new file mode 100644
index 000000000000..cf35a2566637
--- /dev/null
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -0,0 +1,303 @@
+//===--- JSONCompilationDatabase.cpp - ------------------------------------===//
+//
+// 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 implementation of the JSONCompilationDatabase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/JSONCompilationDatabase.h"
+
+#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"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// \brief A parser for escaped strings of command line arguments.
+///
+/// Assumes \-escaping for quoted arguments (see the documentation of
+/// unescapeCommandLine(...)).
+class CommandLineArgumentParser {
+ public:
+ CommandLineArgumentParser(StringRef CommandLine)
+ : Input(CommandLine), Position(Input.begin()-1) {}
+
+ std::vector<std::string> parse() {
+ bool HasMoreInput = true;
+ while (HasMoreInput && nextNonWhitespace()) {
+ std::string Argument;
+ HasMoreInput = parseStringInto(Argument);
+ CommandLine.push_back(Argument);
+ }
+ return CommandLine;
+ }
+
+ private:
+ // All private methods return true if there is more input available.
+
+ bool parseStringInto(std::string &String) {
+ do {
+ if (*Position == '"') {
+ if (!parseQuotedStringInto(String)) return false;
+ } else {
+ if (!parseFreeStringInto(String)) return false;
+ }
+ } while (*Position != ' ');
+ return true;
+ }
+
+ bool parseQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '"') {
+ if (!skipEscapeCharacter()) return false;
+ 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 != '"');
+ return true;
+ }
+
+ bool skipEscapeCharacter() {
+ if (*Position == '\\') {
+ return next();
+ }
+ return true;
+ }
+
+ bool nextNonWhitespace() {
+ do {
+ if (!next()) return false;
+ } while (*Position == ' ');
+ return true;
+ }
+
+ bool next() {
+ ++Position;
+ return Position != Input.end();
+ }
+
+ const StringRef Input;
+ StringRef::iterator Position;
+ std::vector<std::string> CommandLine;
+};
+
+std::vector<std::string> unescapeCommandLine(
+ StringRef EscapedCommandLine) {
+ CommandLineArgumentParser parser(EscapedCommandLine);
+ return parser.parse();
+}
+
+} // end namespace
+
+class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
+ virtual CompilationDatabase *loadFromDirectory(
+ StringRef Directory, std::string &ErrorMessage) {
+ llvm::SmallString<1024> JSONDatabasePath(Directory);
+ llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
+ llvm::OwningPtr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
+ if (!Database)
+ return NULL;
+ return Database.take();
+ }
+};
+
+// Register the JSONCompilationDatabasePlugin with the
+// CompilationDatabasePluginRegistry using this statically initialized variable.
+static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
+X("json-compilation-database", "Reads JSON formatted compilation databases");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONCompilationDatabasePlugin.
+volatile int JSONAnchorSource = 0;
+
+JSONCompilationDatabase *
+JSONCompilationDatabase::loadFromFile(StringRef FilePath,
+ std::string &ErrorMessage) {
+ llvm::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(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
+ if (!Database->parse(ErrorMessage))
+ return NULL;
+ return Database.take();
+}
+
+JSONCompilationDatabase *
+JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
+ std::string &ErrorMessage) {
+ llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
+ llvm::MemoryBuffer::getMemBuffer(DatabaseString));
+ llvm::OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
+ if (!Database->parse(ErrorMessage))
+ return NULL;
+ return Database.take();
+}
+
+std::vector<CompileCommand>
+JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
+ llvm::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";
+ 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))));
+ }
+ return Commands;
+}
+
+std::vector<std::string>
+JSONCompilationDatabase::getAllFiles() const {
+ std::vector<std::string> Result;
+
+ llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefI = IndexByFile.begin();
+ const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefEnd = IndexByFile.end();
+ for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
+ Result.push_back(CommandsRefI->first().str());
+ }
+
+ return Result;
+}
+
+bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
+ llvm::yaml::document_iterator I = YAMLStream.begin();
+ if (I == YAMLStream.end()) {
+ ErrorMessage = "Error while parsing YAML.";
+ return false;
+ }
+ llvm::yaml::Node *Root = I->getRoot();
+ if (Root == NULL) {
+ ErrorMessage = "Error while parsing YAML.";
+ return false;
+ }
+ llvm::yaml::SequenceNode *Array =
+ llvm::dyn_cast<llvm::yaml::SequenceNode>(Root);
+ if (Array == NULL) {
+ ErrorMessage = "Expected array.";
+ return false;
+ }
+ 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);
+ if (Object == NULL) {
+ ErrorMessage = "Expected object.";
+ return false;
+ }
+ llvm::yaml::ScalarNode *Directory = NULL;
+ llvm::yaml::ScalarNode *Command = NULL;
+ llvm::yaml::ScalarNode *File = NULL;
+ for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
+ KVE = Object->end();
+ KVI != KVE; ++KVI) {
+ llvm::yaml::Node *Value = (*KVI).getValue();
+ if (Value == NULL) {
+ ErrorMessage = "Expected value.";
+ return false;
+ }
+ llvm::yaml::ScalarNode *ValueString =
+ llvm::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());
+ if (KeyString == NULL) {
+ ErrorMessage = "Expected strings as key.";
+ return false;
+ }
+ llvm::SmallString<8> KeyStorage;
+ if (KeyString->getValue(KeyStorage) == "directory") {
+ Directory = ValueString;
+ } else if (KeyString->getValue(KeyStorage) == "command") {
+ Command = ValueString;
+ } else if (KeyString->getValue(KeyStorage) == "file") {
+ File = ValueString;
+ } else {
+ ErrorMessage = ("Unknown key: \"" +
+ KeyString->getRawValue() + "\"").str();
+ return false;
+ }
+ }
+ if (!File) {
+ ErrorMessage = "Missing key: \"file\".";
+ return false;
+ }
+ if (!Command) {
+ ErrorMessage = "Missing key: \"command\".";
+ return false;
+ }
+ if (!Directory) {
+ ErrorMessage = "Missing key: \"directory\".";
+ return false;
+ }
+ llvm::SmallString<8> FileStorage;
+ StringRef FileName = File->getValue(FileStorage);
+ llvm::SmallString<128> NativeFilePath;
+ if (llvm::sys::path::is_relative(FileName)) {
+ llvm::SmallString<8> DirectoryStorage;
+ llvm::SmallString<128> AbsolutePath(
+ Directory->getValue(DirectoryStorage));
+ llvm::sys::path::append(AbsolutePath, FileName);
+ llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
+ } else {
+ llvm::sys::path::native(FileName, NativeFilePath);
+ }
+ IndexByFile[NativeFilePath].push_back(
+ CompileCommandRef(Directory, Command));
+ MatchTrie.insert(NativeFilePath.str());
+ }
+ return true;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index 628435307c0b..c5002ef9fcfc 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/Support/raw_os_ostream.h"
@@ -164,12 +164,11 @@ Replacements &RefactoringTool::getReplacements() { return Replace; }
int RefactoringTool::run(FrontendActionFactory *ActionFactory) {
int Result = Tool.run(ActionFactory);
LangOptions DefaultLangOptions;
- DiagnosticOptions DefaultDiagnosticOptions;
- TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(),
- DefaultDiagnosticOptions);
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
- &DiagnosticPrinter, false);
+ &*DiagOpts, &DiagnosticPrinter, false);
SourceManager Sources(Diagnostics, Tool.getFiles());
Rewriter Rewrite(Sources, DefaultLangOptions);
if (!applyAllReplacements(Replace, Rewrite)) {
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index e93e0c97f710..af20254811aa 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -97,17 +97,22 @@ static clang::CompilerInvocation *newInvocation(
bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
const Twine &FileName) {
+ return runToolOnCodeWithArgs(
+ ToolAction, Code, std::vector<std::string>(), FileName);
+}
+
+bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName) {
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
- const char *const CommandLine[] = {
- "clang-tool", "-fsyntax-only", FileNameRef.data()
- };
+ std::vector<std::string> Commands;
+ Commands.push_back("clang-tool");
+ Commands.push_back("-fsyntax-only");
+ Commands.insert(Commands.end(), Args.begin(), Args.end());
+ Commands.push_back(FileNameRef.data());
FileManager Files((FileSystemOptions()));
- ToolInvocation Invocation(
- std::vector<std::string>(
- CommandLine,
- CommandLine + llvm::array_lengthof(CommandLine)),
- ToolAction, &Files);
+ ToolInvocation Invocation(Commands, ToolAction, &Files);
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
@@ -154,11 +159,12 @@ bool ToolInvocation::run() {
for (int I = 0, E = CommandLine.size(); I != E; ++I)
Argv.push_back(CommandLine[I].c_str());
const char *const BinaryName = Argv[0];
- DiagnosticOptions DefaultDiagnosticOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter DiagnosticPrinter(
- llvm::errs(), DefaultDiagnosticOptions);
- DiagnosticsEngine Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
- new DiagnosticIDs()), &DiagnosticPrinter, false);
+ llvm::errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagnosticPrinter, false);
const llvm::OwningPtr<clang::driver::Driver> Driver(
newDriver(&Diagnostics, BinaryName));